Search
Duplicate

TLS in k8s

생성일
2021/05/08 11:31
태그

Certificate in Kubernetes

Root Certificate를 기반으로 만들어진 Client Certificate, Server Certificate가 존재하게 된다. 쿠버네티스 클러스터의 마스터 노드와 워커 노드간 통신이나 kubectl사용자와 kube-api server간 통신은 모두 TLS 보안이 적용된다. 따라서 쿠버네티스 클러스터 내부의 서비스들은 모두 Server Certificate를 사용해서 통신을 암호화하고, 클라이언트는 Client Certificate를 사용해서 자신의 신분을 증명해야 한다. 하지만 Certificate는 인증된 기관을 통해 서명되어야 하기 때문에 Certificate Authority(CA)가 필요하다. 쿠버네티스 클러스터를 위한 CA는 브라우저로 접속하는 웹 사이트에서 제공하는 TLS 인증서의 CA와 원리는 같다고 할 수 있지만 코모도, 시만텍, 고대디 등과 같은 인증 기관으로부터 서명을 받는 대신 자체적으로 서명한 CA를 사용한다. 이 CA를 Root Certificate라고 하며, CA를 만들게 되면 ca.crt, ca.key을 갖게 된다. Certificates의 Public key는 보통 .crt 또는 .pem이라는 이름을 갖고, Private key는 .key 또는 *-key.pem 이름을 사용한다.

두 가지 기본 요구 사항은 클러스터 내에 모든 다양한 서비스가 서버 인증서를 사용하도록하고 모든 클라이언트가 클라이언트 인증서를 사용하여 자신이 누구인지 확인하는 것입니다.

Server Certificates for Servers
Client Certificates for Clients

Server Certificates for Servers

Kube-API Server / ETCD Server / Kubelet Server kube-api server의 경우, 사용자가 HTTP 요청을 통해 쿠버네티스 클러스터를 관리할 수 있기 때문에 모든 통신은 보안이 되어야 한다. 따라서 일반적인 웹 서버의 HTTPS 제공 방식과 동일하게 TLS Certificate와 Private Key가 필요하다.kubeadm으로 클러스터를 구축하면 /etc/kuberntes/pki 디렉터리 밑에 apiserver.crtapiserver.key가 생성되어 있다. 그 밖에 etcd 서버도 동일한 목적으로 etcdserver.crt, etcdserver.key이 만들며, 마스터 노드와 워커 노드에 실행 중인 Kubelet도 Kube-api server에서 상태 관리를 위한 통신을 위한 HTTP API 서비스를 제공하기 때문에 kubelet.crt, kubelet.key를 만들게 된다.

Client Certificates for Clients

admin user / kube-scheduler / kube-controller-manager / kube-proxy Client Certificates는 다양한 사용자(Client)가 자신의 신분을 증명하기 위해 사용하는 Certificates이다.kubectl을 사용하는 클라이언트는 Kube-api server와 통신하기 위해 admin.crtadmin.key를 만들어야 한다. Kube-Scheduler도 POD를 스케줄링하기 위한 정보를 얻기 위해 Kube-api server와 통신하기 때문에 scheduler.crt,scheduler.key를 만들어야 한다. Kube-Scheduler는 관리자 클라이언트와 비슷한 클라이언트일 뿐이다. 그밖에 Kube-Controller-Manager와 Kube-Proxy도 Kube-api server와 통신해야 하기 때문에 위와 동일하게 Key 페어를 갖고 있어야 한다.

Kuber-api server (Server & Client)

kube-api server는 ETCD 서버와 통신하기 때문에 ETCD 서버 입장에서 Kube-api server는 클라이언트이다. 따라서 Kube-api server도 etcd 서버와 통신하기 위한 Certificate 키 페어를 가져야 한다. 이미 만든 apiserser.crtapiserver.key를 사용해도 되고 새로운 키 페어를 만들어도 된다. (apiserver-etcd-client.crt, apiserver-etcd-client.key)
Kube-api server는 워커 노드 상태를 모니터링하기 위해 워커 노드에서 실행 중인 Kubelet server와도 통신한다. 이 경우에도 마찬가지로 신분 인증을 위해 Certificate 키 페어가 필요하다. (apiserver-kubelet-client.crt, apiserver-kubelet-client.key)로 만드는 경우도 있음

Certificate Authority

위에서 다룬 Server Certificate와 Client Certificate에 사인을 하기 위한 Root Certificates가 존재한다. 이 Root Certificate는 ca.crtca.key 쌍으로 존재하고, ETCD에서 사용하는 Client Certificate와 Server Certificate에 사인하기 위한 ca.crtca.key가 따로 존재하기도 한다.

TLS Certificates

1.
서버는 먼저 인증서 서명요청(CSR)을 CA에 보냅니다.
2.
CA는 개인 키를 사용하여 CSR에 서명합니다. 서명 된 인증서는 서버로 다시 전송됩니다. 서버 구성은 서명 된 인증서가있는 웹 애플리케이션입니다.
3.
사용자가 웹 애플리케이션에 액세스 할 때마다. 서버는 먼저 Public Key 와 함께 인증서를 보냅니다.
4.
사용자의 브라우저가 인증서를 읽고 CA의 공개 키를 사용하여 서버의 공개 키를 확인하고 검색합니다.
5.
그런 다음 앞으로 모든 통신에 사용할 symmetric key 를 생성합니다.
6.
대칭 키는 서버를 공개 키로 사용하여 암호화 되어 서버로 다시 전송됩니다..
7.
서버는 Private key 를 사용하여 메시지를 해독 하고 대칭 키를 검색합니다.
Certificates with public key are named crt or pem extension. so that's server.crt, server.pem for server certificates or client.crt or client.pem for client certificates.Private keys are usually with extension .key or -key.pem.

TLS in kubernetes - Certificate Creation

Certificate Authority (CA)

먼저 CA(Certificate Authority) 측면에서 루트 인증서(root certificate)를 만들도록 한다. 인증서를 만들기 위한 여러가지 방법 중 openssl을 이용한다. 먼저 Private key를 만들고, CSR 파일을 만든다. CSR에는 CN(Common Name)) 필드에 정보를 입력해줘야 한다. CN 필드의 용도는 보통 웹 사이트에서 HTTPS를 제공하기 위해 사용하는 인증서에는 CN 필드는 FQDN을 명시하도록 한다. 그래야 클라이언트가 요청하는 서버와 출처가 같은지 확인할 수 있기 때문이다. 마지막으로 인증서를 만들기 위해 x509 명령어를 사용한다. 처음에 만들었던 Private key를 이용해 CSR에 명시에 따라 인증서에 서명하게 된다. 이렇게 CA는 Private key와 인증서를 갖게 되었다.
Generate Keys
$ openssl genrsa -out ca.key 2048
Plain Text
복사
Generate CSR
$ openssl req -new -key ca.key -subj "/CN=KUBERNETES-CA" -out ca.csr
Plain Text
복사
Sign certificates
$ openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
Plain Text
복사

Generating Client Certificates

Admin User Certificates

admin 사용자를 위한 인증서를 만들어본다. 전 단계와 동일하게 Private Key를 만든 후 CSR을 만든다. 이 CSR에도 CN 필드 값을 넣어줘야 한다. 이 때 CN 필드 값은 kube-admin같이 사용자 이름을 명시하면 된다. 꼭 kube-admin일 필요는 없으며 단지 kubectl을 이용할 때 쿠버네티스에 인증하기 위한 사용자를 의미하고, audit log 같은 곳에 이 이름이 남게 된다. 마지막으로 x509 명령어로 서명된 인증서를 만든다. 단, 이 클라이언트 인증서는 전 단계에서 만든 루트 인증서의 하위 인증서이기 때문에 Certificate Authrity의 ca.crtca.key를 활용하게 된다.
Generate Keys
$ openssl genrsa -out admin.key 2048
Plain Text
복사
Generate CSR
$ openssl req -new -key admin.key -subj "/CN=kube-admin" -out admin.csr
Plain Text
복사
Sign certificates
$ openssl x509 -req -in admin.csr -CA ca.crt -CAkey ca.key -out admin.cr
Plain Text
복사
이로써 클러스터 내부에서 유효한 인증을 받을 수 있는 인증서가 만들어지게 된다. 이렇게 Private Key와 인증서를 만드는 과정은 새로운 사용자(계정)을 만드는 방식과 유사하다고 볼 수 있다. 인증서는 사용자의 ID 역할을 하고 Private Key는 비밀번호 역할을 하는 것이다.
이렇게 만든 admin 사용자는 다른 사용자와 어떻게 구별될 수 있을까? 이 부분은 Group을 이용해서 해결할 수 있다. 쿠버네티스 내부에는 이미 정해진 Group이 몇가지 있는데 그 중 system:masters 그룹이 관리자 권한을 갖고 있다. admin 사용자를 이 그룹에 속하기 위해 CSR 생성시 O필드를 통해 소속 그룹을 명시할 수 있다.
Certificate with admin privilages
$ openssl req -new -key admin.key -subj "/CN=kube-admin/O=system:masters" -out admin.csr
Plain Text
복사

kube-apiserver에 액세스하는 다른 모든 구성 요소에 대한 클라이언트 인증서를 생성하려면 동일한 절차를 따릅니다.

Generating Server Certificates

ETCD 서버의 Certificate도 이전 과정과 차이가 없다. ETCD 서버는 고가용성을 위해 여러 서버로 구성될 수 있는데 각 멤버들이 보안이 적용된 통신을 하기 위해 추가로 Peer Certificate를 만든다. 그리고 ETCD 서버가 실행될 때 이 Key와 Certificate를 명시해줘야 한다.
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: component: etcd tier: control-plane name: etcd namespace: kube-system spec: containers: - command: - etcd - --advertise-client-urls=https://10.187.2.31:2379 - --cert-file=/etc/kubernetes/pki/etcd/server.crt - --client-cert-auth=true - --data-dir=/var/lib/etcd - --initial-advertise-peer-urls=https://10.187.2.31:2380 - --initial-cluster=k8s-test001=https://10.187.2.31:2380 - --key-file=/etc/kubernetes/pki/etcd/server.key - --listen-client-urls=https://127.0.0.1:2379,<https://10.187.2.31:2379> - --listen-metrics-urls=http://127.0.0.1:2381 - --listen-peer-urls=https://10.187.2.31:2380 - --name=k8s-test001 - --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt - --peer-client-cert-auth=true - --peer-key-file=/etc/kubernetes/pki/etcd/peer.key - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt - --snapshot-count=10000 - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
Plain Text
복사