본문 바로가기

컨테이너/쿠버네티스 네트워크

[KANS] 쿠버네티스 네트워크 (4) 쿠버네티스 인증 deep div

더보기
목표

 # 쿠버네티스 인증 딥다이브 

# PKI 인증 체계와 쿠버네티스 인증에 대해서

 인증이란? 

https://docs.google.com/presentation/d/1bAxTbLjUxq2d81R7ZP17QuRYA7fLw3RhpRUyBBy5ETY/edit#slide=id.g11ef75f9f2d_0_0

인증서에 대해서 간략하게 짚고 넘어가자

PKI = '공개키 기반구조(Public Key Infrastructure)'라는 뜻
PKI 는 비대칭 암호화 기술을 이용한 공개키 기반의 인증 체계입니다.

X.509는 PKI 기술 중에서 가장 널리 알려진 표준 포맷입니다. 
공개키가 뭘까? Public 키
반댓말은 개인키= 비밀키= Private키 

X.509 기술의 근간이 되는 암호화 기술입니다. 여기에는 Public 키와 Private 키가 존재합니다. Public 키는 누구나 가질 수 있으며 Private 키는 오직 Public, Private 키페어 소유자만 가지고 있습니다. Public 키를 이용하여 메세지를 암호화하게 되면 해당 Public키에 매핑되는 Private 키로만 복호화가 가능합니다. 반대로 Priate 키를 이용하여 메세지를 암호화할 수 있는데, 이때 누구나 해당 Private 키에 매핑되는 Public 키를 이용하여 암호화된 메세지에 대해서 정말 Private 키의 소유자가 작성한 메세지인지를 검증할 수 있습니다. Private 키로 메세지를 암호화하는 것을 디지털 서명(digital signature)이라고 합니다. X.509에서 디지털 서명을 이용하여 사용자의 신원을 확인합니다.



공개키는 어떻게 전달할까? 
- 공개키는 SSL 인증 과정에서 핸드쉐이킹 과정에 대해서 이해해야 합니다.
핸드쉐이킹 과정중  서버의 인증서를 보낼때 함께 공개키를 전달합니다. (= 서버 헬로우 )
공개키는 Handshaking 과정에서 클라이언트 서버에 전달 되어 클라이언트와 서버가 서로를 신뢰할수 있는지 신원확인을 위해 존재합니다. 
하지만 공개키는 사용하는데 있어서 불필요한 리소스 사용이 크기 때문에 
다수의 상대와 통신할때 사용하는 방식이 바로, 대칭키 교환 방식 입니다.
따라서 처음 세션을 맺는데 핸드쉐이킹 과정에서만 비대칭키 인증방식이 활용되고 그 이후에는 
대칭키를 활용하여 암호화 통신을 진행 합니다.

핸드쉐이크 할때 서버의 인증서 안에 들어있는 공개키로 PMS 값을 복호화 합니다.

공개키 실습

#https://www.youtube.com/watch?v=mMCNqc1BmSE&list=PLCZ-8rvakaqbplQZAoUku8uuxUgbLQm-1&index=3

openssl genrsa -out private.pem 1024;
ls -al
# private.pem

openssl rsa -in private.pem -out public.pem -outform PEM -pubout;

ls -al
# private.pem
# public.pem

echo "coding koo" > file.txt
ls -al
# private.pem
# public.pem
# file.txt

openssl rsautl -encrypt -inkey public.pem -pubin -in file.txt -out file.ssl;
ls -al
# private.pem
# public.pem
# file.txt
# file.ssl 공개키로 암호화 했음

openssl rsautl -decrypt -inkey private.pem -in file.ssl -out decrypted.txt
ls -al 
# private.pem
# public.pem
# file.txt
# file.ssl 공개키로 암호화 했음
# decrypted.txt 개인키로 복호화 했음 

cat decrypted.txt
# coding koo

 

쿠버네티스 인증체계

이러한 그림을 이해하기 위해서  각 서버에는 
crt - key 구조로 서버의 개인키와 공유키를 가지고 있습니다.

kind 클러스터 설치

클러스터 설치는 docker in docker 로 쿠버네티스 클러스터 환경을 구성 -
테스트환경 만들때 macos 기준으로 편리하게 설치할수 있습니다. 

# 클러스터 배포 전 확인
docker ps

# kind 는 별도 도커 네트워크 생성 후 사용 : 기본값 172.18.0.0/16
docker network ls
docker inspect kind | jq

# Create a cluster with kind
cat << EOT > kind-2node.yaml 
# two node (one workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
EOT
kind create cluster --config kind-2node.yaml --name myk8s

# 확인
kind get nodes --name myk8s

# k8s api 주소 확인 : 어떻게 로컬에서 접속이 되는 걸까?
kubectl cluster-info
docker ps # 포트 포워딩 정보 확인
docker exec -it myk8s-control-plane ss -tnlp | grep 6443
kubectl get pod -n kube-system -l component=kube-apiserver -owide # 파드 IP 확인
kubectl describe  pod -n kube-system -l component=kube-apiserver
docker exec -it myk8s-control-plane curl -k https://localhost:6443/livez ;echo
docker exec -it myk8s-control-plane curl -k https://localhost:6443/readyz ;echo

# 노드 정보 확인 : CRI 는 containerd 사용
kubectl get node -o wide

# 파드 정보 확인 : CNI 는 kindnet 사용
kubectl get pod -A -owide

# 네임스페이스 확인 >> 도커 컨테이너에서 배운 네임스페이스와 다릅니다!
kubectl get namespaces

# 컨트롤플레인, 워커 컨테이너 각각 1대씩 실행 : 도커 컨테이너 이름은 myk8s-control-plane , myk8s-worker 임을 확인
docker ps
docker images

# 디버그용 내용 출력에 ~/.kube/config 권한 인증 로드
kubectl get pod -v6

# kube config 파일 확인
cat ~/.kube/config
혹은
cat $KUBECONFIG

# local-path 라는 StorageClass 가 설치, local-path 는 노드의 로컬 저장소를 활용함
# 로컬 호스트의 path 를 지정할 필요 없이 local-path provisioner 이 볼륨을 관리
kubectl get sc
kubectl get deploy -n local-path-storage

# 툴 설치
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop git nano -y'
docker exec -it myk8s-worker sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop git nano -y'
  • /etc/kubernetes/pki 확인 
  • crt - key 구조로 서버의 개인키와 공유키를 가지고 있습니다.
  • 해당 키를 이용하여 서버와 서버간 통신을 암복호화 하여 보안을 유지합니다.
docker exec -it myk8s-control-plane tree /etc/kubernetes/pki

/etc/kubernetes/pki
|-- apiserver-etcd-client.crt
|-- apiserver-etcd-client.key
|-- apiserver-kubelet-client.crt
|-- apiserver-kubelet-client.key
|-- apiserver.crt
|-- apiserver.key
|-- ca.crt
|-- ca.key
|-- etcd
|   |-- ca.crt
|   |-- ca.key
|   |-- healthcheck-client.crt
|   |-- healthcheck-client.key
|   |-- peer.crt
|   |-- peer.key
|   |-- server.crt
|   `-- server.key
|-- front-proxy-ca.crt
|-- front-proxy-ca.key
|-- front-proxy-client.crt
|-- front-proxy-client.key
|-- sa.key
`-- sa.pub

2 directories, 22 files

What's next:
    Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug myk8s-control-plane
    Learn more at https://docs.docker.com/go/debug-cli/

kubeconfig의 역할

기본적으로 쿠버네티스 api 서버는 복잡하게 생각할것 없이 API 서버일뿐이다.
CA file과 Client 공개키/개인키가 있으면 통신할수 있다.

https://blog.naver.com/PostView.nhn?blogId=alice_k106&logNo=221492934710
 

157. [Kubernetes] 쿠버네티스 인증서 (CA) 및 인증 (auth) 에 관련된 공부

이번 포스트에서는 예전에 했었던 쿠버네티스 인증서 및 인증에 대한 내용을 적어보려고 한다.  대단...

blog.naver.com

https://coffeewhale.com/kubernetes/authentication/x509/2020/05/02/auth01/

 

k8s 인증 완벽이해 #1 - X.509 Client Certs

쿠버네티스를 지금까지 사용해 오면서 어렴풋이만 인증서와 토큰을 이용하여 사용자 인증을 하는지는 알고 있엇지만 그 이상 다른 방법에 대해서는 자세히 몰랐었습니다. 쿠버네티스 공인 자

coffeewhale.com

 

root CA

쿠버네티스에서 사용하는 root CA의 PKI 키들은 다음과 같습니다.

  • CA 인증서: /etc/kubernetes/pki/ca.crt

server 인증서

api 서버의 인증서 및 키는 다음과 같습니다.

  • 인증서: /etc/kubernetes/pki/apiserver.crt
  • 개인키: /etc/kubernetes/pki/apiserver.key

client 인증서

클라이언트의 인증서 및 키는 다음과 같습니다.

  • 인증서: /etc/kubernetes/admin.conf 파일내 client-certificate-data 부분
  • 개인키: /etc/kubernetes/admin.conf 파일내 client-key-data 부분

 

cat ~/.kube/config
# echo "#####" | base64 --decode 
# 3개의 키 파일을 다음과 같은 방식으로 decode해서 만들자

-rw-r--r--@  1 mzc01-kook  staff  1107  9  3 08:51 ca.pem
-rw-r--r--@  1 mzc01-kook  staff  1679  9  3 08:41 client-key.pem
-rw-r--r--@  1 mzc01-kook  staff  1155  9  3 08:41 client.pem

# 다음과 같이 3개의 키파일이 준비되면 curl 요청한다.
# https://127.0.0.1:60671도 cat ~/.kube/config에 api서버 주소가 나와있다.
curl --cacert ca.pem --cert client.pem --key client-key.pem https://127.0.0.1:60671


#성공

 

 

쿠버네티스 컴포넌트들끼리는 통신과 API서버에 접근하는 클라이언트의 통신체계와 보안을 알아봤다.
다음으로는 Token과 ServiceAccount와의 관계를 알아보자.

목표

토큰 ? 
pod는 k8s 컴포넌트 또는 클라이언트 보다는 보다 제약적인 권한을 주는것이 최소 권한의 원칙에 적합하다.
따라서 토큰과 service account를 활용하여 권한 부여 하기 때문에 
자세히 알아보자

여기서 사용하는 토큰이 흔히 웹서버에서 사용하는 jwt 토큰

 

  • 파드 배포
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: netpod
spec:
  containers:
  - name: netshoot-pod
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF
  • 토큰이 마운트 된 포인트 확인 
kubectl exec -it netpod -- tree /var/run/secrets
/var/run/secrets
└── kubernetes.io
    └── serviceaccount
        ├── ca.crt -> ..data/ca.crt
        ├── namespace -> ..data/namespace
        └── token -> ..data/token

2 directories, 3 files
  • token 복사 
netpod:/var/run/secrets/kubernetes.io/serviceaccount# cat token
eyJhbGciOiJSUzI1NiIsImtpZCI6IkQ0ZkZZS2tUakhPZ3BwckJ3eFhtbTZETWMxQ0dfcl9MRi1ScDNheWd2NHMifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzU2ODY0MDE4LCJpYXQiOjE3MjUzMjgwMTgsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiOWYxMDQzNTctZDM5NC00YTc4LWI0NGYtNzYxZmY0N2ZkYjIwIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwibm9kZSI6eyJuYW1lIjoibXlrOHMtd29ya2VyIiwidWlkIjoiZjNiZjZkZGMtMmU2Ni00NGZlLWJhOTYtNDgxYTQwNWFiYjJlIn0sInBvZCI6eyJuYW1lIjoibmV0cG9kIiwidWlkIjoiZjgyNjA4NTEtNzhjMC00NWZjLTlkNDktOTAzODc3ZWUyMGY2In0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkZWZhdWx0IiwidWlkIjoiM2M5OWQ5NzYtOGI5ZC00ZDZlLTk3ZmYtMTYwM2UzMWU1NTM2In0sIndhcm5hZnRlciI6MTcyNTMzMTYyNX0sIm5iZiI6MTcyNTMyODAxOCwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6ZGVmYXVsdCJ9.eKZFoZWOT6UVSNCkcT0M-A3DSzzKuMrw-0LcSNlSJKsNxbsg-rLn5s4l2jyOs6zD8P5xvpXApSwKVxI0LScMeC9tgUREB1h5qDLGF7nrybEXHmtWLz5gT45r9MejXqRWr-4r8q3_zjOC3NJooNq8LNW4hBDUefhvO4o3G8PYE8nqYrdgRw_aGCi5XQSBu174HBgdDBj9rgKFXqzsjjE_63YZPPlo7v3hPWDGmvduT0JV_XCbnRAAzUGWkHH5aSwFJktRi7pXYKf5jSjYJcURvEColfIaEbGJET5kkmVRfGU0x8EK1gTZkKyL2EaHA36Wcu_vppY9exb9JHM-YFU3mg
  • JWT io 사이트를 통해 페이로드 분석
  •  payload 부분에는 ServiceAccount가 생성된 namespace, Secret 이름, ServiceAccount 이름 등 쿠버네티스의 다양한 세부 정보가 담긴 것을 확인할 수 있습니다.
  • 쿠버네티스에서는 이러한 사용자 정보를 활용하여 Bearer token을 통한 인증을 처리합니다.

  • JWT 방식 토큰을 입력한 후에 공개키를 전달해 주어야 인증절차를 통과할수 있습니다. 
  • 공개키는 서비스 어카운트의 공개키를 입력해주어야 합니다.
docker exec -it myk8s-control-plane cat /etc/kubernetes/pki/sa.pub

# sa.pub키를 같이 넣어줘야 valid signature 뜸

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtDUKF4asZsUG1sJDff3o
GucTDVBCtBUF9LYpCgicAtgm0vDW/OtTw4kakoUwZKqAkMs/NIbYbJVwNL8iN37S
6PY7s3pGhpRFS2G3pvwfulWjyjaxCOCE9qd0/sZhl1xoM4BHvKLWw5U64PxXVP5L
pQgL1FF5lzBNfe+H1nxG0hNovrI3CRqTe8HChbXwP77WT8mfnh9rBE0W3xdpA3MA
UL1MxqPswoKr9kSwxtk6MVRBl47/inIZetEF/IER1RKgIMu2jUW9ScH3o3NksQzU
OspsEcJYyPVqSPY2zX40yaQFzlV3wH7mnGTK4b30MEPBECReNuPvYeHeo2wDhdUA
EQIDAQAB
-----END PUBLIC KEY-----
  • 성공