Security는 굉장히 방대하고, 어려운 파트 중 하나인데 k8s Security 역시 많은 내용을 담고있다.
k8s에서 kube-apiserver가 system component 및 Worker Node와 통신을 하는데, 이 kube-apiserver가 구성 컴포넌트에 따라 Server측이 되기도 하고, Client 측이 되기도 한다.
물론 CA라는 신뢰된 인증서를 바탕으로, 각 구성 컴포넌트들의 인증서를 증명하는 역할을 수행한다.
k8s는 TLS를 통한 인증을 위해 PKI 인증서가 필요하다.
직접 인증키(.key)와 인증서 파일(.crt)을 생성하지 않고, kubeadm으로 k8s를 사용하게 되면, 각 Cluster에서 필요한 인증서는 자동으로 생성되어 편리하다. Private Key를 API 서버에 저장하지 않기에 더 안전하게 인증서를 생성할 수 있어 편리함과 동시에 보안성까지 더욱 갖출 수 있다.
대부분의 인증서 위치는 /etc/kubernetes/pki 디렉터리에 있다.
Root CA Certificate
최상위 인증서로, k8s의 오브젝트를 생성할 때 사용하는 최상위 인증서이다. 즉, 클러스터 내에서 발급된 다른 인증서의 진위여부를 확인하는 최상위 인증서이며, 암호화를 기반으로 기밀성과 무결성을 보장한다.
구성 컴포넌트가 주장하는 요소를 인증해주는 최상위 인증서.
-중간CA에 서명하여 개별 컴포넌트의 인증서에 서명함(신뢰성 보장)
-kubeadm과 같은 툴로 클러스터 셋업 시 자동 생성
-모든 클러스터 구성 요소에 접근할 수 있는 ConfigMap에 저장됨
Authentication of Root CA Certification
-컴포넌트 인증: 노드, api server, Controller 간 신원(인증서) 인증
-User 인증: k8s API 접근 허용 판단을 위한 사용자 인증서 검증
-워크로드 인증: 상호간 안전한 통신 채널인지 확인하기 위한 인증 수행
주의) ETCD Server의 루트CA는 별도로 관리됨(아래 참고)
kube-apiserver Certificate
아래 명령어로 kube-apiserver에 대한 설정 값과 인증서파일의 경로 및 키에 대해 알 수 있다.
cat /etc/kubernetes/manifests/kube-apiserver.yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.15.55.6:6443
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.15.55.6
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
- --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
- --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
- --etcd-servers=https://127.0.0.1:2379
- --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
- --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
- --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
- --requestheader-allowed-names=front-proxy-client
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --requestheader-extra-headers-prefix=X-Remote-Extra-
- --requestheader-group-headers=X-Remote-Group
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
- --service-cluster-ip-range=10.96.0.0/12
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
image: registry.k8s.io/kube-apiserver:v1.27.0
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
host: 192.15.55.6
path: /livez
port: 6443
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
name: kube-apiserver
readinessProbe:
failureThreshold: 3
httpGet:
host: 192.15.55.6
path: /readyz
port: 6443
scheme: HTTPS
periodSeconds: 1
timeoutSeconds: 15
resources:
requests:
cpu: 250m
startupProbe:
failureThreshold: 24
httpGet:
host: 192.15.55.6
path: /livez
port: 6443
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
volumeMounts:
- mountPath: /etc/ssl/certs
name: ca-certs
readOnly: true
- mountPath: /etc/ca-certificates
name: etc-ca-certificates
readOnly: true
- mountPath: /etc/kubernetes/pki
name: k8s-certs
readOnly: true
- mountPath: /usr/local/share/ca-certificates
name: usr-local-share-ca-certificates
readOnly: true
- mountPath: /usr/share/ca-certificates
name: usr-share-ca-certificates
readOnly: true
hostNetwork: true
priority: 2000001000
priorityClassName: system-node-critical
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- hostPath:
path: /etc/ssl/certs
type: DirectoryOrCreate
name: ca-certs
- hostPath:
path: /etc/ca-certificates
type: DirectoryOrCreate
name: etc-ca-certificates
- hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate
name: k8s-certs
- hostPath:
path: /usr/local/share/ca-certificates
type: DirectoryOrCreate
name: usr-local-share-ca-certificates
- hostPath:
path: /usr/share/ca-certificates
type: DirectoryOrCreate
name: usr-share-ca-certificates
status: {}
위 인증서 관련 파라미터 중, 아래 매개변수에 대한 차이점을 이해해야 한다.
cafile
-CA(신뢰보장되는 공인 인증 기관)의 인증서 파일 경로를 지정
-Security 통신 중, 다른 Server가 제시한 인증서의 진위 여부를 확인하는데 사용함
certfile
-클라이언트의 인증서 파일 경로를 지정
-서버 인증에 사용되는 클라이언트(User or Service 계정)의 공개 키 및 ID 정보를 포함
(즉, apiserver를 ETCD서버의 클라이언트로 인증하는데 사용되는 파일은 Certfile임)
keyfile
-클라이언트 Private key 경로 지정
-클라이언트 인증서와 일치하는 개인키를 포함하여, 서명/암호화/복호화에 사용 됨
위 파라미터들은 k8s 클러스터 내에서 다양한 구성 컴포넌트 간 통신 채널의 보안 통신을 구축하는데 필수적이며, 인증서와 키 관리가 요구된다.
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
--tls-cert-file=/etc/kubernetes/pki/apiserver.crt -> kube-apisever가 다른 서버를 인증할 때 사용하는 인증서
--tls-private-key-file=/etc/kubernetes/pki/apiserver.key -> kube-apiserver의 키
kube-apiserver의 인증서 세부사항 확인하기
위 kube-apiserver.yaml파일에서 참고한 kube-apiserver의 인증서를 openssl 구문으로 확인해보기
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout
//openssl x509 -in [file-path.crt] -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4085601723811199419 (0x38b2f91f117d79bb)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = kubernetes
Validity
Not Before: Jan 21 12:34:27 2024 GMT
Not After : Jan 20 12:34:27 2025 GMT
Subject: CN = kube-apiserver
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:e7:6c:c7:70:5d:a9:e7:0b:49:eb:09:b4:26:e1:
4c:1d:ea:9a:ee:bc:54:cc:c7:a2:f8:11:ae:f8:b3:
40:b8:6e:15:f6:ca:db:36:b1:9d:82:ea:5b:10:28:
92:43:8c:a5:3e:88:48:7c:01:84:78:64:9f:4e:7f:
ec:ed:16:67:b3:97:1c:78:25:9a:2b:5b:86:69:7b:
78:32:39:2d:90:aa:b7:82:71:eb:9c:81:96:20:4f:
72:11:04:10:fe:55:68:1a:47:10:c6:d2:ae:04:15:
ba:b3:c3:f5:24:1e:d5:e4:a8:fe:c0:0e:5d:02:41:
73:d9:95:71:66:74:c3:85:f8:ca:51:a8:d9:1c:db:
fa:23:dc:81:44:58:32:99:ae:1a:a6:25:f5:79:ef:
eb:69:a2:2b:1a:66:32:c3:1f:85:74:90:ac:36:43:
d3:8b:38:79:5e:15:c2:1d:6a:b4:45:87:91:ea:d8:
3c:e4:91:68:e1:c3:c7:5a:4a:91:35:cd:f4:b9:4b:
08:66:15:43:62:da:19:c9:8d:ee:25:ac:3b:2f:e6:
51:79:1d:4a:62:ba:3c:08:1d:a8:65:a8:1a:b3:5f:
aa:5d:7c:7f:46:82:46:ee:d3:18:e7:54:7e:dc:63:
24:71:f3:7b:67:76:75:3d:02:ea:e3:e1:5e:5b:cd:
2d:b7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Authority Key Identifier:
keyid:90:DF:4D:87:6F:E6:C7:51:F4:17:A4:48:81:33:FA:BF:FE:A9:07:DA
X509v3 Subject Alternative Name:
DNS:controlplane, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, IP Address:10.96.0.1, IP Address:192.20.97.8
Signature Algorithm: sha256WithRSAEncryption
64:97:ac:63:e1:48:a5:14:c4:a8:53:06:0c:eb:32:21:a0:69:
4f:bc:23:44:6d:9b:4f:88:b1:d9:b3:06:90:53:ff:f8:b9:c2:
33:42:7e:91:bf:87:53:1e:7a:9b:9d:22:82:4e:d2:4a:7b:e9:
06:f6:82:4b:ad:06:78:dd:b0:97:26:ef:88:54:a3:9a:0f:bc:
ee:07:cc:73:0a:69:03:1a:2d:bf:d7:23:9a:f4:78:1c:86:55:
5e:d6:64:8a:a7:e5:4d:11:27:40:9d:97:5c:4a:a8:99:80:57:
74:cf:4c:c5:b2:47:0c:dd:19:fe:d6:cd:16:87:e5:16:7a:af:
99:45:6b:2a:ac:8b:48:85:ac:e6:f7:c2:8e:40:6b:cb:da:2f:
63:9f:d6:68:6c:67:0f:d6:78:c7:b3:36:5f:76:ce:46:ea:8f:
53:62:0b:68:d4:59:19:20:a6:d7:dc:be:2b:5c:f8:f7:1a:1e:
1f:83:50:d8:b7:ec:ae:ca:7d:46:69:5d:27:07:08:c5:9e:f4:
92:80:17:26:47:25:66:3a:95:8f:23:c4:bd:82:1b:a9:3c:e5:
14:af:42:58:44:38:1f:8e:18:95:39:57:b1:76:ec:69:5e:c1:
eb:ae:63:05:77:34:d1:15:80:b0:43:d6:c2:b0:ba:52:ec:c6:
e1:7a:41:ca
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4085601723811199419 (0x38b2f91f117d79bb)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = kubernetes //CA 인증서 발급자 확인
Validity
Not Before: Jan 21 12:34:27 2024 GMT
Not After : Jan 20 12:34:27 2025 GMT //인증서 유효성 확인(만료일자)
Subject: CN = kube-apiserver //CN 확인
CA 발급자와 인증서 유효기간, CN 등을 위에서 확인 가능하다.
X509v3 Subject Alternative Name:
DNS:controlplane, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, IP Address:10.96.0.1, IP Address:192.20.97.8
Signature Algorithm: sha256WithRSAEncryption
위에서 확인 시, kube-apiserver의 Alternative Name을 모두 확인 할 수 있다.
kube-apiserver는 그 자체를 k8s라고 볼 수 있는데, 모든 구성 컴포넌트들과 연결되어 통신하고 상태를 체크하기 때문이다.
따라서, 각 구성 컴포넌트들과 어떤 때는 kube-apiserver가 서버이기도, 클라이언트이기도 하기 때문에
불려지는 Name이 다양하다. 이를 모두 식별하기 위해
X509v3 Subject Alternative Name: 아래에 정보가 담겨있다.
ETCD Server Certificate
ETCD Server와 관련된 정보는 아래 경로 디렉터리 내 etcd.yaml 파일에서 확인할 수 있다.
cat /etc/kubernetes/manifests/etcd.yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/etcd.advertise-client-urls: https://192.20.97.8:2379
creationTimestamp: null
labels:
component: etcd
tier: control-plane
name: etcd
namespace: kube-system
spec:
containers:
- command:
- etcd
- --advertise-client-urls=https://192.20.97.8:2379
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --client-cert-auth=true
- --data-dir=/var/lib/etcd
- --experimental-initial-corrupt-check=true
- --experimental-watch-progress-notify-interval=5s
- --initial-advertise-peer-urls=https://192.20.97.8:2380
- --initial-cluster=controlplane=https://192.20.97.8:2380
- --key-file=/etc/kubernetes/pki/etcd/server.key
- --listen-client-urls=https://127.0.0.1:2379,https://192.20.97.8:2379
- --listen-metrics-urls=http://127.0.0.1:2381
- --listen-peer-urls=https://192.20.97.8:2380
- --name=controlplane
- --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
image: registry.k8s.io/etcd:3.5.7-0
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
host: 127.0.0.1
path: /health?exclude=NOSPACE&serializable=true
port: 2381
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
name: etcd
resources:
requests:
cpu: 100m
memory: 100Mi
startupProbe:
failureThreshold: 24
httpGet:
host: 127.0.0.1
path: /health?serializable=false
port: 2381
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
volumeMounts:
- mountPath: /var/lib/etcd
name: etcd-data
- mountPath: /etc/kubernetes/pki/etcd
name: etcd-certs
hostNetwork: true
priority: 2000001000
priorityClassName: system-node-critical
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- hostPath:
path: /etc/kubernetes/pki/etcd
type: DirectoryOrCreate
name: etcd-certs
- hostPath:
path: /var/lib/etcd
type: DirectoryOrCreate
name: etcd-data
status: {}
ETCD Server의 CA 인증서는 kube-apiserver의 CA와는 달리 별도로 관리된다.
--cert-file=/etc/kubernetes/pki/etcd/server.crt -> ETCD Server Certificate file 경로
--trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt -> ETCD Server 루트 CA 경로
ETCD Server 인증서 세부사항 확인하기
위 etcd.yaml파일에서 참고한 인증서를 openssl 구문으로 확인해보기
openssl x509 -in /etc/kubernetes/pki/etcd.crt -text -noout
//openssl x509 -in [file-path.crt] -text -noout
openssl x509 -in /etc/kubernetes/pki/etcd/server.crt -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 3764440671794400025 (0x343dfad89c568b19)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = etcd-ca
Validity
Not Before: Jan 21 12:34:28 2024 GMT
Not After : Jan 20 12:34:28 2025 GMT
Subject: CN = controlplane
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:a5:a1:db:df:4e:ff:85:2a:ad:d9:a4:9e:bd:6f:
0f:90:14:fd:e1:5c:97:ce:b0:68:69:ca:e6:de:64:
79:ad:76:52:de:4d:7e:14:b9:db:7d:42:79:b0:a4:
42:19:bd:72:46:66:6f:13:7a:0a:ff:34:d5:c7:eb:
02:36:3d:3d:d4:61:8a:89:36:d0:8c:f4:80:c9:52:
ba:e7:e2:f8:5a:dc:80:a4:2a:a0:e1:ba:5c:a7:25:
fb:d7:88:cf:91:7b:c4:ac:c7:fb:76:5c:1d:33:b7:
a8:93:e4:3f:5e:51:28:20:0b:0b:bd:10:1c:60:09:
5e:ec:1f:32:77:a9:78:ce:26:0e:35:71:0f:6d:62:
a7:f0:e0:35:e2:a4:0e:1e:dd:b5:0c:0e:95:db:40:
50:55:e8:f4:e8:77:dd:64:e1:cd:8e:1d:70:83:bd:
57:f8:5c:d9:44:3e:8c:6a:4a:da:ee:8d:ab:96:bb:
42:b3:bb:12:77:d9:cf:81:ea:47:d7:57:97:1f:df:
03:7b:b3:56:a4:52:e4:b7:32:3c:65:3a:7c:25:39:
8b:1e:7f:38:50:5a:89:67:4b:56:58:08:7b:9c:8e:
5f:e8:f3:bc:f3:1a:de:03:f2:e3:3e:ed:4b:e8:55:
a2:26:df:93:3a:58:ed:53:c2:66:00:12:b6:39:ca:
29:0b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Authority Key Identifier:
keyid:E2:27:56:BC:4E:14:35:E4:B9:4E:12:05:35:D6:D0:82:A1:B2:10:18
X509v3 Subject Alternative Name:
DNS:controlplane, DNS:localhost, IP Address:192.20.97.8, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1
Signature Algorithm: sha256WithRSAEncryption
88:98:8f:41:5b:ad:1f:0b:63:2e:57:f6:b3:64:c5:c7:fa:9b:
89:d0:23:06:92:49:1d:b0:47:40:30:96:b5:0a:6b:6b:36:af:
86:0d:c9:fd:0e:6a:20:d6:ee:e8:f2:50:51:89:6e:9e:e2:ae:
5a:c6:4c:a7:42:63:ee:62:20:bc:e0:a2:d6:5c:ba:e4:ea:ec:
cf:01:e3:83:6a:29:32:f4:1d:16:e1:37:96:bb:f7:c7:27:44:
85:0c:60:14:68:8d:d5:ec:dd:b7:20:3c:23:53:89:22:23:d1:
91:35:0f:66:2e:94:c7:c0:c5:e0:19:ec:c3:4a:f8:83:71:6c:
6a:88:b2:b0:51:55:c9:c8:ba:19:21:00:d0:5a:d2:b6:52:9b:
36:00:8d:3d:32:65:8d:d7:53:9e:fe:a8:97:eb:b4:b5:36:bf:
fe:be:fd:2a:ea:06:83:b5:c3:17:e0:f4:19:c7:44:6e:dc:d7:
f3:2c:b7:cb:b7:28:07:cd:49:8d:fe:c0:f5:86:85:41:2d:32:
d4:4b:75:f5:87:20:8a:58:a1:3a:97:88:fb:d6:f1:1e:e2:2f:
7b:d6:1a:df:50:33:64:30:bc:28:4a:91:13:05:74:a9:ba:6f:
81:07:82:2d:cf:9d:66:b0:84:9d:42:c3:fb:90:da:f6:11:94:
d2:0a:d8:9a