Kubernetes/Certificates

[CKS] Cluster Hardening

Operation CWAL 2021. 5. 1. 18:27

RBAC

Role과 RoleBinding

다음과 같은 시나리오를 진행한다.

1. 네임스페이스 red, blue 생성

kubectl create ns red
kubectl create ns blue

2. User 'john'은 red 네임스페이스의 'secret' 리소스에 대해 'get' 동작을 수행할 수 있다.

#Role 'secret-manager' 생성
kubectl -n red create role secret-manager --verb=get --resource=secrets

#User 'john'과 Role 'secret-manager'를 Binding
kubectl -n red create rolebinding secret-manager --role=secret-manager --user=john

3. User 'john'은 blue 네임스페이스의 'secret' 리소스에 대해 'get', 'list' 동작을 수행할 수 있다.

#Role 'secret-manager' 생성
kubectl -n blue create role secret-manager --verb=get --verb=list --resource=secrets

#User 'john'과 Role 'secret-manager'를 Binding
kubectl -n blue create rolebinding secret-manager --role=secret-manager --user=john

4. kubectl의 'auth can-i' 명령어를 통해 권한을 확인한다.

kubectl -n red auth can-i get secrets --as john #yes
kubectl -n red auth can-i list secrets --as john #no
kubectl -n blue auth can-i get secrets --as john #yes
kubectl -n blue auth can-i list secrets --as john #yes
kubectl -n blue auth can-i create secrets --as john #no
kubectl auth can-i get secrets --as john #no

 

ClusterRole과 ClusterRoleBinding

다음과 같은 시나리오를 진행한다.

1. Deployment 삭제 가능한 ClusterRole 'deploy-deleter'를 생성

#ClusterRole 'deploy-deleter' 생성
kubectl create clusterrole deploy-deleter --verb=delete --resource=deployments

2. User 'john'은 모든 네임스페이스의 Deployment를 삭제할 수 있다.

kubectl create clusterrolebinding deploy-deleter --user=john --clusterrole=deploy-deleter

3. User 'jane'은 red 네임스페이스의 Deployment 삭제만 가능하다.

ClusterRole과 RoleBinding을 사용할 경우, Namespace의 리소스에 대해서만 권한을 부여한다.

kubectl -n red create rolebinding deploy-deleter --user=jane --clusterrole=deploy-deleter

4. kubectl의 'auth can-i' 명령어를 통해 권한을 확인한다.

kubectl auth can-i delete deployment --as john #yes
kubectl -n red auth can-i delete deployment --as john #yes
kubectl auth can-i delete deployment --as jane #no
kubectl -n red auth can-i delete deployment --as jane #yes

CertificateSigningRequest

1. SSL Key 파일 및 CSR 파일 생성

openssl genrsa -out dev1.key 2048
openssl req -new -key dev1.key -out dev1.csr

CSR 파일 생성시, Common Name에 새로 추가할 사용자의 이름을 입력하며 그 외 항목은 생략한다. 이 과정에서 dev1.key, dev1.csr 두 개의 파일이 생성된다.

 

2. K8s CertificateSigningRequest 리소스 생성

우선 다음 명령어로 CSR 파일의 내용을 base64로 인코딩할 필요가 있다. 

cat dev1.csr | base64 -w 0

아래와 같은 CSR Manifest 파일을 작성하되, request 필드에 위에서 얻은 인코딩 텍스트를 입력한다.

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: dev1
spec:
  groups:
  - system:authenticated
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ21UQ0NBWUVDQVFBd1ZERUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeApJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpERU5NQXNHQTFVRUF3d0VaR1YyCk1UQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUpiVGNJd2JOcStmRnNsZGg2NnMKbWpoMFZLTldiaElkTjFWV0hrQkV6Vm84M0hhNXZIUXM2UUtwazJMUlBmaERxbHMrU3AySVRkemxHcHFiUmNhWQpXeHRsa1NNOFcrZlBUc2VUZDFTTXZMU1hGSjFpUVc0ZzcwUDVobmsrL0NTUWlPUTJmQzU5MnBhV1lWRWZMUE5PCld0aXdxTC9iczNhWjl0VktXZUkrSXB0eExCQTdhRTlKUzVTZ1BndlEzcHZVOFIzNnltbUdOVE1JeEI3ZVVMMUQKN2tvMFk0Y0RlTzQrK3YrRm5xYU04dTBOTXJONkhSTkZ3V05abStkK1l4c1lGTGk2REFwbW9ZVyt2Z2NGS0oybgpETEtuNmJSVE44U3JoTkF5a0xQRnNwN0lCT3A5RnJkaDltU21RQWdmcEVUWVZmdzJscjJBcmVuV0w5SEEySTJ1Cmw0RUNBd0VBQWFBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQk5yMkRPVXlTUE9jb1Zsa0dsM0tCaVJKeEgKanhkSEVwaFVFY3VpWllEZmJybldoQmZ1UEV5bXpVMDRHTmZmcHBCbEtUTDdOYWJZOURGNmpHQ3dqcDJ0L0xyMApsM1FhaGVrRWQyZ2FVcjhxMWcwZkdHTGlqc0RuMnI4TUxaSDVVaS9kZ2Q2NXRlb1d5YW10ZkxWQ2dEUjJSaVN0CitTeG0yVXh2R3lqVVUvekEya2xSZWNKWVV0aXNBRVY3VHpYUDFVZDloOWlWMFNuSHNhUVpxN04rdWh6NjRObTUKQmRyRlVsOGsvdEtSNGJzN2JRMDgxQXcrM3NIQndOZFpleHRncnRXSVVhNTJUUHF4T3MrYmwvbGFpRm12LzNpUQo2cXZ4RzROL3dwalhtOXVPYlp3YXBhM08rMWY4cnY1dHJWKzAxZ2t2bk1qVnhxS2JoWXNweHJ3VFVkNmwKLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVU
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - client auth

아래 명령어로 K8s CSR 리소스를 생성하여, 인증서 발급을 요청한다.

kubectl apply -f csr.yaml

 

 

3. CSR 확인 및 Approve

아래 명령어로 현재 존재하는 K8s CSR 리소스를 확인할 수 있으며, 현재 dev1이라는 이름의 CSR이 승인 대기중인 것으로 나온다.

kubectl get csr

다음 명령어로 해당 CSR을 승인하여, K8s CA가 서명한 인증서를 얻을 수 있다.

kubectl certificate approve dev1

 

4. Client Certificate 파일 생성

승인 완료시, 해당 CSR 리소스에 CA가 서명한 인증서 데이터가 추가되며, 다음 명령어로 이를 확인할 수 있다. 

kubectl get csr dev1 -o yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"certificates.k8s.io/v1","kind":"CertificateSigningRequest","metadata":{"annotations":{},"name":"dev1"},"spec":{"groups":["system:authenticated"],"request":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ21UQ0NBWUVDQVFBd1ZERUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeApJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpERU5NQXNHQTFVRUF3d0VaR1YyCk1UQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUpiVGNJd2JOcStmRnNsZGg2NnMKbWpoMFZLTldiaElkTjFWV0hrQkV6Vm84M0hhNXZIUXM2UUtwazJMUlBmaERxbHMrU3AySVRkemxHcHFiUmNhWQpXeHRsa1NNOFcrZlBUc2VUZDFTTXZMU1hGSjFpUVc0ZzcwUDVobmsrL0NTUWlPUTJmQzU5MnBhV1lWRWZMUE5PCld0aXdxTC9iczNhWjl0VktXZUkrSXB0eExCQTdhRTlKUzVTZ1BndlEzcHZVOFIzNnltbUdOVE1JeEI3ZVVMMUQKN2tvMFk0Y0RlTzQrK3YrRm5xYU04dTBOTXJONkhSTkZ3V05abStkK1l4c1lGTGk2REFwbW9ZVyt2Z2NGS0oybgpETEtuNmJSVE44U3JoTkF5a0xQRnNwN0lCT3A5RnJkaDltU21RQWdmcEVUWVZmdzJscjJBcmVuV0w5SEEySTJ1Cmw0RUNBd0VBQWFBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQk5yMkRPVXlTUE9jb1Zsa0dsM0tCaVJKeEgKanhkSEVwaFVFY3VpWllEZmJybldoQmZ1UEV5bXpVMDRHTmZmcHBCbEtUTDdOYWJZOURGNmpHQ3dqcDJ0L0xyMApsM1FhaGVrRWQyZ2FVcjhxMWcwZkdHTGlqc0RuMnI4TUxaSDVVaS9kZ2Q2NXRlb1d5YW10ZkxWQ2dEUjJSaVN0CitTeG0yVXh2R3lqVVUvekEya2xSZWNKWVV0aXNBRVY3VHpYUDFVZDloOWlWMFNuSHNhUVpxN04rdWh6NjRObTUKQmRyRlVsOGsvdEtSNGJzN2JRMDgxQXcrM3NIQndOZFpleHRncnRXSVVhNTJUUHF4T3MrYmwvbGFpRm12LzNpUQo2cXZ4RzROL3dwalhtOXVPYlp3YXBhM08rMWY4cnY1dHJWKzAxZ2t2bk1qVnhxS2JoWXNweHJ3VFVkNmwKLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==","signerName":"kubernetes.io/kube-apiserver-client","usages":["client auth"]}}
  creationTimestamp: "2021-04-15T13:13:53Z"
  managedFields:
  - apiVersion: certificates.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
      f:spec:
        f:groups: {}
        f:request: {}
        f:signerName: {}
        f:usages: {}
    manager: kubectl-client-side-apply
    operation: Update
    time: "2021-04-15T13:13:53Z"
  - apiVersion: certificates.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:status:
        f:certificate: {}
    manager: kube-controller-manager
    operation: Update
    time: "2021-04-15T13:17:18Z"
  - apiVersion: certificates.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:status:
        f:conditions:
          .: {}
          k:{"type":"Approved"}:
            .: {}
            f:lastTransitionTime: {}
            f:lastUpdateTime: {}
            f:message: {}
            f:reason: {}
            f:status: {}
            f:type: {}
    manager: kubectl
    operation: Update
    time: "2021-04-15T13:17:18Z"
  name: dev1
  resourceVersion: "861571"
  uid: 725f36ff-f730-4aaa-9d02-7b0575b45045
spec:
  groups:
  - system:masters
  - system:authenticated
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ21UQ0NBWUVDQVFBd1ZERUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeApJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpERU5NQXNHQTFVRUF3d0VaR1YyCk1UQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUpiVGNJd2JOcStmRnNsZGg2NnMKbWpoMFZLTldiaElkTjFWV0hrQkV6Vm84M0hhNXZIUXM2UUtwazJMUlBmaERxbHMrU3AySVRkemxHcHFiUmNhWQpXeHRsa1NNOFcrZlBUc2VUZDFTTXZMU1hGSjFpUVc0ZzcwUDVobmsrL0NTUWlPUTJmQzU5MnBhV1lWRWZMUE5PCld0aXdxTC9iczNhWjl0VktXZUkrSXB0eExCQTdhRTlKUzVTZ1BndlEzcHZVOFIzNnltbUdOVE1JeEI3ZVVMMUQKN2tvMFk0Y0RlTzQrK3YrRm5xYU04dTBOTXJONkhSTkZ3V05abStkK1l4c1lGTGk2REFwbW9ZVyt2Z2NGS0oybgpETEtuNmJSVE44U3JoTkF5a0xQRnNwN0lCT3A5RnJkaDltU21RQWdmcEVUWVZmdzJscjJBcmVuV0w5SEEySTJ1Cmw0RUNBd0VBQWFBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQk5yMkRPVXlTUE9jb1Zsa0dsM0tCaVJKeEgKanhkSEVwaFVFY3VpWllEZmJybldoQmZ1UEV5bXpVMDRHTmZmcHBCbEtUTDdOYWJZOURGNmpHQ3dqcDJ0L0xyMApsM1FhaGVrRWQyZ2FVcjhxMWcwZkdHTGlqc0RuMnI4TUxaSDVVaS9kZ2Q2NXRlb1d5YW10ZkxWQ2dEUjJSaVN0CitTeG0yVXh2R3lqVVUvekEya2xSZWNKWVV0aXNBRVY3VHpYUDFVZDloOWlWMFNuSHNhUVpxN04rdWh6NjRObTUKQmRyRlVsOGsvdEtSNGJzN2JRMDgxQXcrM3NIQndOZFpleHRncnRXSVVhNTJUUHF4T3MrYmwvbGFpRm12LzNpUQo2cXZ4RzROL3dwalhtOXVPYlp3YXBhM08rMWY4cnY1dHJWKzAxZ2t2bk1qVnhxS2JoWXNweHJ3VFVkNmwKLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - client auth
  username: kubernetes-admin
status:
  certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURPakNDQWlLZ0F3SUJBZ0lSQUsycytPc1Q1WjVvTnoxcVgwZDhEQll3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRBME1UVXhNekV5TVRoYUZ3MHlNakEwTVRVeApNekV5TVRoYU1GUXhDekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJRXdwVGIyMWxMVk4wWVhSbE1TRXdId1lEClZRUUtFeGhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXhEVEFMQmdOVkJBTVRCR1JsZGpFd2dnRWkKTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDVzAzQ01HemF2bnhiSlhZZXVySm80ZEZTagpWbTRTSFRkVlZoNUFSTTFhUE54MnVieDBMT2tDcVpOaTBUMzRRNnBiUGtxZGlFM2M1UnFhbTBYR21Gc2JaWkVqClBGdm56MDdIazNkVWpMeTBseFNkWWtGdUlPOUQrWVo1UHZ3a2tJamtObnd1ZmRxV2xtRlJIeXp6VGxyWXNLaS8KMjdOMm1mYlZTbG5pUGlLYmNTd1FPMmhQU1V1VW9ENEwwTjZiMVBFZCtzcHBoalV6Q01RZTNsQzlRKzVLTkdPSApBM2p1UHZyL2haNm1qUEx0RFRLemVoMFRSY0ZqV1p2bmZtTWJHQlM0dWd3S1pxR0Z2cjRIQlNpZHB3eXlwK20wClV6ZkVxNFRRTXBDenhiS2V5QVRxZlJhM1lmWmtwa0FJSDZSRTJGWDhOcGE5Z0szcDFpL1J3TmlOcnBlQkFnTUIKQUFHalJqQkVNQk1HQTFVZEpRUU1NQW9HQ0NzR0FRVUZCd01DTUF3R0ExVWRFd0VCL3dRQ01BQXdId1lEVlIwagpCQmd3Rm9BVTZETmt5THFSNmJaYnV6K2N4S2tOTWZROWJjRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBQmkxCi83MFR0NDkxcHBydmVlQXZQU0p6bzlic2xnSHY4emdhdlRUeXRzN1REamIremNQUGViMlRoSnZXR1k3YTBYeXYKdjNkblB5NzBLSnFpTWhldWJnc29LUHo3cDlDckVheGNIWWNjakh2QnZqbjhMd3EwNGd6VldsMHR5K3NKdDB0QQpiTHBSWXZqdVZ5K0tYeWpLYnZqMVlXZXFDc3llK04xNjltcEpPbVZQblBVMGdxOFRtL1B4RXdWWTUyQ1RQcDg1ClNIZE9COWIwRzNXZWR6b2hDZmo0cjRONDJvYTNtYllWYlJQR2IxZjNCUDU4TDh6TW9YY3dZNXpMYklDeWZuOG8KNnF6ZG9DZllYZVNoUFU2aGNtN3F6TnplOGNZYmlqaEJ0dTl2UWJ2UnlDTGdDeHJmbjY0dnVTVXpxUkp6ODZuMgpMMmlXRGdUS0tpeFBIOUVSM2dRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
  conditions:
  - lastTransitionTime: "2021-04-15T13:17:18Z"
    lastUpdateTime: "2021-04-15T13:17:18Z"
    message: This CSR was approved by kubectl certificate approve.
    reason: KubectlApprove
    status: "True"
    type: Approved

.status.certificate 항목에 base64로 인코딩된 인증서가 위치하며, 아래 명령어로 원본 데이터를 얻을 수 있다.

echo "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURPakNDQWlLZ0F3SUJBZ0lSQUsycytPc1Q1WjVvTnoxcVgwZDhEQll3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRBME1UVXhNekV5TVRoYUZ3MHlNakEwTVRVeApNekV5TVRoYU1GUXhDekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJRXdwVGIyMWxMVk4wWVhSbE1TRXdId1lEClZRUUtFeGhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXhEVEFMQmdOVkJBTVRCR1JsZGpFd2dnRWkKTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDVzAzQ01HemF2bnhiSlhZZXVySm80ZEZTagpWbTRTSFRkVlZoNUFSTTFhUE54MnVieDBMT2tDcVpOaTBUMzRRNnBiUGtxZGlFM2M1UnFhbTBYR21Gc2JaWkVqClBGdm56MDdIazNkVWpMeTBseFNkWWtGdUlPOUQrWVo1UHZ3a2tJamtObnd1ZmRxV2xtRlJIeXp6VGxyWXNLaS8KMjdOMm1mYlZTbG5pUGlLYmNTd1FPMmhQU1V1VW9ENEwwTjZiMVBFZCtzcHBoalV6Q01RZTNsQzlRKzVLTkdPSApBM2p1UHZyL2haNm1qUEx0RFRLemVoMFRSY0ZqV1p2bmZtTWJHQlM0dWd3S1pxR0Z2cjRIQlNpZHB3eXlwK20wClV6ZkVxNFRRTXBDenhiS2V5QVRxZlJhM1lmWmtwa0FJSDZSRTJGWDhOcGE5Z0szcDFpL1J3TmlOcnBlQkFnTUIKQUFHalJqQkVNQk1HQTFVZEpRUU1NQW9HQ0NzR0FRVUZCd01DTUF3R0ExVWRFd0VCL3dRQ01BQXdId1lEVlIwagpCQmd3Rm9BVTZETmt5THFSNmJaYnV6K2N4S2tOTWZROWJjRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBQmkxCi83MFR0NDkxcHBydmVlQXZQU0p6bzlic2xnSHY4emdhdlRUeXRzN1REamIremNQUGViMlRoSnZXR1k3YTBYeXYKdjNkblB5NzBLSnFpTWhldWJnc29LUHo3cDlDckVheGNIWWNjakh2QnZqbjhMd3EwNGd6VldsMHR5K3NKdDB0QQpiTHBSWXZqdVZ5K0tYeWpLYnZqMVlXZXFDc3llK04xNjltcEpPbVZQblBVMGdxOFRtL1B4RXdWWTUyQ1RQcDg1ClNIZE9COWIwRzNXZWR6b2hDZmo0cjRONDJvYTNtYllWYlJQR2IxZjNCUDU4TDh6TW9YY3dZNXpMYklDeWZuOG8KNnF6ZG9DZllYZVNoUFU2aGNtN3F6TnplOGNZYmlqaEJ0dTl2UWJ2UnlDTGdDeHJmbjY0dnVTVXpxUkp6ODZuMgpMMmlXRGdUS0tpeFBIOUVSM2dRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" | base64 -d > dev1.crt

 이제 dev1.key, dev1.crt 두 개의 파일을 사용하여 kube-apiserver 접근이 가능하다. 물론 어떠한 RBAC 설정도 되지 않은 계정이기 때문에 아직 할 수 있는 동작은 없다. 이는 해당 계정에 부여할 Role과 RoleBinding을 통해 해결 가능하지만 이번 과정은 사용자 추가가 목적이므로 생략하도록 한다.

 

5. kubeconfig 설정

새로 추가한 사용자 계정으로 kubectl을 사용하기 위해선 kubeconfig에 해당 정보가 있어야 한다. 아래 명령어로 추가해보자.

kubectl config set-credentials dev1 --client-key=dev1.key --client-certificate=dev1.crt --embed-certs

현재 kubeconfig 설정은 다음 명령어로 확인 가능하다.

kubectl config view

이제 K8s 클러스터와 kubectl 사용자를 매칭하는 context를 정의할 차례다.

kubectl config set-context dev1 --user=dev1 --cluster=kubernetes

context 목록은 다음 명령어로 확인 가능하다.

kubectl config get-contexts

다음 명령어로 kubectl에서 사용할 context를 선택할 수 있다.

kubectl config use-context dev1

 

 

Securing ServiceAccount

Pod에 Custom ServiceAccount 적용

1. ServiceAccount 'accessor' 생성

kubectl create sa accessor

2. 해당 SA를 사용하는 Pod 정의

kubectl run accessor --image=nginx --dry-run=client -oyaml > accessor-pod.yaml
vim accessor-pod.yaml

아래와 같이 'serviceAccountName' 필드를 추가한다.

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: accessor
  name: accessor
spec:
  serviceAccountName: accessor
  containers:
  - image: nginx
    name: accessor
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

3. Pod 생성

kubectl apply -f accessor-pod.yaml

 

ServiceAccount Mouting 비활성화

일반적인 서비스를 수행하는 Pod은 API 서버에 접근할 이유가 없으므로, 보안을 위해 SA 토큰을 마운트하지 않도록 설정해야 한다. 'accessor-pod.yaml' 파일을 다음과 같이 수정한다.

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: accessor
  name: accessor
spec:
  serviceAccountName: accessor
  automountServiceAccountToken: false
  containers:
  - image: nginx
    name: accessor
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

 

ServiceAccount와 RBAC

ServiceAccount 'accessor'는 현재 아무 Role도 Binding 되어있지 않은 상태로, 클러스터의 어떠한 리소스도 접근이 불가하다. 다음과 같이 ClusterRole 'edit'을 Binding한다.

kubectl create clusterrolebinding accessor --clusterrole edit --serviceaccount default:accessor

kubectl auth can-i delete secrets --as system:serviceaccount:default:accessor #yes

 

API 서버 접근 제한

Anonymous Access 허용

kube-apiserver manifest 파일 수정이 필요하다.

vim /etc/kubernetes/manifests/kube-apiserver.yaml

다음과 같이 'anonymous-auth=true' 옵션을 추가한다.

kube-apiserver Pod이 재가동될 때까지 기다린 후, 다음 명령어로 Anonymous Access를 확인해보자. 권한을 부여하지 않은 상태이므로, 리소스에 대한 접근을 할 순 없지만 서버와의 통신을 막진 않는다.

curl -k https://localhost:6443

Insecure Access

Kubernetes 1.20 이후부터, Insecure Access를 허용하지 않으므로 '--insecure-port=8080'과 같은 옵션은 더 이상 사용할 수 없다.

 

Manaul API Request

.kube/config 파일에 존재하는 'certificate-authority-data', 'client-certificate-data', 'client-key-data'를 'base64 --decode' 명령어를 통해 각각 ca, crt, key 파일을 생성할 수 있다. 그리고 이 파일을 사용하여 매뉴얼 방식의 API 서버 접근이 가능하다.

curl https://localhost:6443 --cacert ca --cert crt --key key

클러스터 외부 kubectl로 API 서버 접근 

1. default 네임스페이스의 'kubernetes' Service를 NodePort 타입으로 변경

2. .kube/config 파일 복사 후 'server' 주소를 External IP와 NodePort로 수정

3. Exernal IP는 '/etc/kubernetes/pki/apiserver.crt'에 등록되지 않은 CN이므로 접근 불가하다. 따라서 /etc/hosts 파일에서 'kubernetes'를 External IP로 resolving 되도록 설정한다.

 

NodeRestriction 검증

kubelet은 자신이 위치한 Node 이외 리소스에는 접근할 수 없다. 이를 확인하기 위해 사용자의 kubeconfig 대신 kubelet의 config를 사용하여 API 서버에 접근해보자.

export KUBECONFIG=/etc/kubernetes/kubelet.conf

 

API 서버의 NodeRestriction에 의해 'namespace' 리소스에 대한 'get' 동작을 수행할 수 없다. Node에 대한 작업은 가능한지 아래와 같이 테스트해보자.

kubectl label node master hello=world #Success
kubectl label node worker-1 hello=world #Failed

master에는 label을 추가할 수 있지만, 그 외 node에는 API 서버가 허용하지 않는 것을 확인할 수 있다.

 

Upgrade Kubernetes

 다음 순서로 업그레이드를 수행한다.

A. Master Node 업그레이드

1. Node Drain

kubectl drain master --ignore-daemonsets

 

2. K8s 패키지 업데이트

Master Node 안에서 다음과 같이 패키지를 설치한다.

apt update
apt-cache show kubeadm
apt install kubeadm=<version> kubectl=<version> kubelet=<version>

3. kubeadm을 사용하여 업그레이드

kubeadm upgrade plan

kubeadm upgrade apply <available version>

4. Node 활성화

kubectl uncordon master

B. Worker Node 업그레이드

1. Node Drain

kubectl drain worker --ignore-daemonsets

2. K8s 패키지 업데이트

Worker Node 안에서 다음과 같이 패키지를 설치한다.

apt update
apt-cache show kubeadm
apt install kubeadm=<version> kubelet=<version>

3. kubeadm을 사용하여 업그레이드

kubeadm upgrade node

4. Node 활성화

kubectl uncordon worker-1

 

'Kubernetes > Certificates' 카테고리의 다른 글

[CKS] Runtime Security  (0) 2021.05.08
[CKS] Minimize Microservice Vulnerabilities  (0) 2021.05.03
[CKS] System Hardening  (0) 2021.05.02
[CKS] Cluster Hardening  (0) 2021.05.01
[CKS] Cluster Setup  (0) 2021.04.30
Certified Kubernetes Security Specialist (CKS)  (0) 2021.04.27