[AWS EKS] EKS Security 2 - Kubernetes x.509 인증 및 CSR 관리 실습

주영·2025년 3월 12일
0

AWS EKS Workshop Study 3기

목록 보기
19/31

이 글은 CloudNet@팀의 AWS EKS Workshop Study(AEWS) 3기 스터디 내용을 바탕으로 작성되었습니다.
AEWS는 CloudNet@의 '가시다'님께서 진행하는 스터디로, EKS를 학습하는 과정입니다.
EKS를 깊이 있게 이해할 기회를 주시고, 소중한 지식을 나눠주시는 가시다님께 다시 한번 감사드립니다.
이 글이 EKS를 학습하는 분들께 도움이 되길 바랍니다.

1. 운영 서버 EC2에서 SSH 접속 및 노드 IP 확인

운영 서버에서 EC2 인스턴스의 공인 IP를 확인한 후 SSH 접속을 수행합니다.

1.1 EC2 공인 IP 확인

# 노드 IP 확인 
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output table

1.2 SSH 접속

ssh -i <your-key.pem> ec2-user@<PublicIP>

2. Kubernetes 클러스터(kind) 생성 및 인증서 정보 확인

2.1 inotify 설정 변경

Kubernetes 이벤트 모니터링을 위한 inotify 설정을 조정합니다.
이는 Kubernetes가 다수의 파일 변경 이벤트를 감지할 수 있도록 리소스 제한을 늘려주는 역할을 합니다.

sudo sysctl fs.inotify.max_user_watches=524288
sudo sysctl fs.inotify.max_user_instances=512

2.2 kind 클러스터 생성

kind는 Docker 컨테이너 안에서 Kubernetes 클러스터를 실행하는 도구입니다.
이를 통해 로컬 개발 및 테스트 환경을 손쉽게 구축할 수 있습니다.

kind create cluster --name myk8s

2.3 인증서 파일 확인

Kubernetes는 보안 강화를 위해 클러스터의 주요 구성 요소 간의 통신을 TLS(Transport Layer Security)로 보호합니다.
각 구성 요소의 신뢰성을 검증하기 위해 다양한 인증서가 필요하며, 이를 /etc/kubernetes/pki/ 경로에서 확인할 수 있습니다.

docker exec -it myk8s-control-plane ls -l /etc/kubernetes/pki
-rw-r--r-- 1 root root 1123 Mar  7 13:34 apiserver-etcd-client.crt
-rw------- 1 root root 1675 Mar  7 13:34 apiserver-etcd-client.key
-rw-r--r-- 1 root root 1176 Mar  7 13:34 apiserver-kubelet-client.crt
-rw------- 1 root root 1675 Mar  7 13:34 apiserver-kubelet-client.key
-rw-r--r-- 1 root root 1326 Mar  7 13:34 apiserver.crt # 루트인증서로부터 발급된 하위 인증서
-rw------- 1 root root 1675 Mar  7 13:34 apiserver.key
-rw-r--r-- 1 root root 1107 Mar  7 13:34 ca.crt # 루트인증서
-rw------- 1 root root 1675 Mar  7 13:34 ca.key # 루트인증서에 대응하는 비밀키
drwxr-xr-x 2 root root 4096 Mar  7 13:34 etcd
-rw-r--r-- 1 root root 1123 Mar  7 13:34 front-proxy-ca.crt
-rw------- 1 root root 1679 Mar  7 13:34 front-proxy-ca.key
-rw-r--r-- 1 root root 1119 Mar  7 13:34 front-proxy-client.crt
-rw------- 1 root root 1679 Mar  7 13:34 front-proxy-client.key
-rw------- 1 root root 1679 Mar  7 13:34 sa.key
-rw------- 1 root root  451 Mar  7 13:34 sa.pub

주요 인증서 파일

  • apiserver-kubelet-client.crt: kubelet과 API 서버 간의 인증을 위한 인증서
  • apiserver.crt: 루트 인증서로부터 발급된 하위 인증서
  • ca.crt: Kubernetes 클러스터의 루트 인증서
  • ca.key: 루트 인증서에 대응하는 비밀키
  • front-proxy-ca.crt: 프록시 CA 인증서
  • sa.key / sa.pub: 서비스 계정 서명 키

2.4 특정 인증서 내용 확인

인증서 정보를 직접 확인하여 만료 날짜 및 발급 기관을 검토할 수 있습니다.

docker exec -it myk8s-control-plane cat /etc/kubernetes/pki/ca.crt
docker exec -it myk8s-control-plane openssl x509 -in /etc/kubernetes/pki/ca.crt -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 8736798006158023849 (0x793f577f3f63dca9)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = kubernetes
        Validity
            Not Before: Mar  7 13:29:06 2025 GMT
            Not After : Mar  5 13:34:06 2035 GMT
        Subject: CN = kubernetes
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical #  클라이언트는 이 키 사용 용도를 반드시 준수
                Digital Signature, Key Encipherment, Certificate Sign
                # Digital Signature: 인증서가 디지털 서명에 사용됨.
                # Key Encipherment: 인증서가 키 암호화(예: TLS에서 세션 키 암호화)에 사용됨.
                # Certificate Sign: 이 인증서가 다른 인증서를 서명(즉, CA 역할)할 수 있음. 주로 인증 기관(CA) 인증서에서 사용됨.
            X509v3 Basic Constraints: critical # 인증서가 인증 기관(CA) 역할을 할 수 있는지를 나타냄.
                CA:TRUE
            X509v3 Subject Key Identifier:
                32:75:7F:9F:C2:C4:C8:25:8C:04:79:6A:B7:18:84:27:37:E2:4A:75
            X509v3 Subject Alternative Name: #  인증서가 적용되는 주체(Subject)의 대체 이름
                DNS:kubernetes
    ...
    Signature Value:
        18:9b:6f:ad:09:d1:ea:78:4a:3d:b7:93:cc:7e:e2:c1:94:30:
        ...

docker exec -it myk8s-control-plane cat /etc/kubernetes/pki/apiserver-kubelet-client.crt
docker exec -it myk8s-control-plane openssl x509 -in /etc/kubernetes/pki/apiserver-kubelet-client.crt -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 805610438108720721 (0xb2e1a6cd6d12e51)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = kubernetes
        Validity
            Not Before: Mar  7 13:29:06 2025 GMT
            Not After : Mar  7 13:34:06 2026 GMT
        Subject: O = kubeadm:cluster-admins, CN = kube-apiserver-kubelet-client
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Client Authentication # 클라이언트 인증용
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier:
                32:75:7F:9F:C2:C4:C8:25:8C:04:79:6A:B7:18:84:27:37:E2:4A:75

인증서 정보 예시

  • Issuer: CN = kubernetes
  • Validity: 2025년 3월 7일부터 2035년 3월 5일까지 유효
  • X509v3 Key Usage: 디지털 서명, 키 암호화, 인증서 서명
  • X509v3 Basic Constraints: CA 역할 수행 가능 (CA: TRUE)

3. Kubernetes의 CSR(Certificate Signing Request) 확인

Kubernetes의 클라이언트 인증을 위해 생성된 CSR을 조회합니다.
CSR은 인증서 요청의 일환으로, 관리자가 이를 승인하면 새로운 클라이언트 인증서가 발급됩니다.

3.1 CSR 목록 확인

kubectl get certificatesigningrequests

# 출력 예시
NAME        AGE     SIGNERNAME                                    REQUESTOR                         CONDITION
csr-852t8   4m14s   kubernetes.io/kube-apiserver-client-kubelet   system:node:myk8s-control-plane   Approved,Issued
csr-t8hvk   4m4s    kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef           Approved,Issued

3.2 CSR 상세 정보 확인

kubectl describe certificatesigningrequests csr-852t8

# 출력 예시
Name:               csr-852t8
...
Requesting User:    system:node:myk8s-control-plane
Signer:             kubernetes.io/kube-apiserver-client-kubelet
Status:             Approved,Issued
Subject:
         Common Name:    system:node:myk8s-control-plane
         Serial Number:
         Organization:   system:nodes
Events:  <none>


Name:               csr-t8hvk
...
Requesting User:    system:bootstrap:abcdef
Signer:             kubernetes.io/kube-apiserver-client-kubelet
Status:             Approved,Issued
Subject:
         Common Name:    system:node:myk8s-worker
         Serial Number:
         Organization:   system:nodes
Events:  <none>

주요 정보

  • Requesting User: system:node:myk8s-control-plane
  • Signer: kubernetes.io/kube-apiserver-client-kubelet
  • Status: Approved, Issued
  • Subject: Common Name(CN) = system:node:myk8s-control-plane, Organization = system:nodes

CSR이 승인되면 해당 사용자는 클러스터에 대한 인증서를 발급받아 API 서버와의 보안 연결을 수립할 수 있습니다.

4. kubeconfig 정보 확인

kind 설치자의 kubeconfig 파일에서 인증서 정보를 확인합니다.

4.1 kubeconfig 파일 내용 확인

cat $HOME/.kube/config

# 출력 예시
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0...
    server: https://127.0.0.1:50032
  name: kind-myk8s
contexts:
- context:
    cluster: kind-myk8s
    user: kind-myk8s
  name: kind-myk8s
current-context: kind-myk8s
kind: Config
preferences: {}
users:
- name: kind-myk8s
  user:
    client-certificate-data: LS0tL...
    client-key-data: LS0tLS1CR....

주요 필드

  • certificate-authority-data: Kubernetes 클러스터의 CA(Certificate Authority) 인증서를 포함하며, 신뢰할 수 있는 루트 인증서를 확인하는 데 사용된다. base64 인코딩된 데이터로, 디코딩하여 내용을 확인할 수 있다. 디코딩하면 Kubernetes 클러스터의 자체 서명된 CA 인증서를 확인할 수 있다.
  • client-certificate-data: 클라이언트(사용자)가 인증받기 위해 사용하는 X.509 인증서. Kubernetes API 서버는 이 인증서를 검증하여 사용자를 식별한다. base64 인코딩된 데이터로, 디코딩하여 내용을 확인할 수 있다.
  • client-key-data: 클라이언트 개인 키. 해당 사용자가 API 서버와 안전하게 통신할 수 있도록 도와준다.(API 서버와의 보안 통신을 위한 서명 및 암호화에 사용) 이 키는 기밀성이 요구되며, 외부로 유출되지 않도록 주의해야 한다.

4.2 인증서 디코딩

echo "<base64-encoded-cert>" | base64 -d
  • certificate-authority-data
  • client-certificate-data
  • client-key-data

4.3 인증서 상세 정보 확인

vi myuser.crt
-----BEGIN CERTIFICATE-----
MIIDKTCCAhGgAwIBAgIIeKzXmvzBrkswDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
...

# 
openssl x509 -in myuser.crt -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 8695562041211072075 (0x78acd79afcc1ae4b)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes
        Validity
            Not Before: Mar  8 12:26:08 2025 GMT
            Not After : Mar  8 12:31:08 2026 GMT
        Subject: O=kubeadm:cluster-admins, CN=kubernetes-admin
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier:
                BC:3D:E4:40:A8:C1:A5:95:14:4F:1C:8D:00:3B:46:68:B0:FD:14:A5
  • Signature Algorithm: SHA-256을 사용한 RSA 암호화
  • Issuer: 인증서를 발급한 주체로, Kubernetes 클러스터에서 자체 서명한 CA임
  • Validity: 인증서가 유효한 기간 (2025년 3월 8일 ~ 2026년 3월 8일)
  • Subject: 인증서의 대상. 이 경우, O=kubeadm:cluster-admins, CN=kubernetes-admin은 Kubernetes 클러스터 관리자로 지정된 사용자임
  • X.509 확장 필드:
    • Key Usage (critical): 디지털 서명과 키 암호화에 사용됨
    • Extended Key Usage: TLS 웹 클라이언트 인증에 사용됨
    • Basic Constraints: 이 인증서는 CA 역할을 수행할 수 없음 (CA:FALSE)
    • Authority Key Identifier: 인증 기관이 서명한 인증서임을 식별하는 값
  • client-certificate-data
  • certificate-authority-data

5. 신규 관리자를 위한 인증서 생성 및 승인

5.1 관리자의 인증서 키 및 CSR 생성

Kubernetes에서 클라이언트 인증을 위해서는 클라이언트가 신뢰할 수 있는 인증서를 사용해야 합니다. 이를 위해 먼저 비밀 키를 생성한 후, 해당 키를 기반으로 CSR(Certificate Signing Request, 인증서 서명 요청)을 생성합니다. 이 과정은 클러스터 관리자가 특정 사용자를 인증할 수 있도록 하는 중요한 단계입니다.

# 하위 인증서를 위한 비밀키 생성 : gasida 대신 자신의 닉네임으로 변경해서 실습해보세요!
openssl genrsa -out gasida.key 2048

# 확인
cat gasida.key
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCpb0u8E7Km0CkX
...

# 인증서 사인 요청 파일(.csr) 파일 생성
openssl req -new -key gasida.key -out gasida.csr -subj "/O=kubeadm:cluster-admins/CN=gasida-cert"

# 확인
cat gasida.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICczCCAVsCAQAwLjEWMBQGA1UECgwNY2xvdWRuZXRhLW9yZzEUMBIGA1UEAwwL
...

# 출력 값을 아래 request 에 붙여넣기 : 끝에 == 빼먹지 말것!
cat gasida.csr | base64 | tr -d '\n'

CSR 파일은 Kubernetes 클러스터 내부에서 특정 사용자에 대한 인증서를 발급하기 위한 요청입니다. 생성된 CSR을 클러스터 관리자가 승인하면, Kubernetes는 이를 기반으로 클라이언트 인증서를 발급합니다.

5.2 CSR 요청 생성 및 적용

Kubernetes 클러스터 내부에서는 CSR 요청을 통해 클라이언트 인증을 위한 서명을 받을 수 있습니다. CSR 요청을 적용하면, 클러스터 내의 CA(Certificate Authority)가 이를 검토하고 서명하여 인증서를 발급할 수 있습니다.

# CSR 요청 : k8s 내부적으로 루트인증서의 비밀키로 서명해 반환. 즉 간접적으로 루트 인증서의 비밀키를 사용할 수 있음 셈.
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: gasida-csr
spec:
  signerName: kubernetes.io/kube-apiserver-client
  groups:
  - system:masters
  - system:authenticated
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2ZEQ0NBV1FDQVFBd056RWZNQjBHQTFVRUNnd1dhM1ZpWldGa2JUcGpiSFZ6ZEdWeUxXRmtiV2x1Y3pFVQpNQklHQTFVRUF3d0xaMkZ6YVdSaExXTmxjblF3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUURTOU9xRktsTCt6Z0RoQ2Qxb3QvS1h0Q1JTMWI5Y3p1YzVDdW5WcTUrdEtFRkIydzFpby9zQUtwOUMKSlo2UklLcXFydm85YXRzTkF1cGFybUNORnV5SHN1d1d3RjdNbTdCYzZpZk1uRElDSU1ybG5BUDhyYkllcHFuRwo4YkJxTXM1c3VoYXl6UlVMT3hkeEg5K1ZqOERoSjZsQ0FaL3ZTcEVtVXJlbjMyMGJIZzRUay9JTnE5a0REN2xJCjR2a0ZTQzlqeDVtRG9mT2FvNzhHZEl1c0lZK01wT3Vvb1I2ZWVmSlJOa3NPanBGQ1F5bGExTURWeHd1OVpDbG4KU3FXZWFmWHZiODNnSGdJYmRsSDRER2Z3bzQrRERQckpZak5oLzA1UVd2Zjh0UW5XTkpJdXRRblpOOGlxRVhrQQpBdG5UY0tWcDFTS2x3LzJ3azJuQkU5anE4VFN2QWdNQkFBR2dBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBCm00UGpaZGM1ZERlS3d2dk1qUlRMWmJNRVBTQkQ4QXlLMWEyU1k4QjU1MmFNWlhFekFGQ1Zob2xxWGFsWmhudWkKbDZzeHVTVWVkMWxKQyt4OURZcHlrTmNYTXI3NDgrNkR0dTQybklUVGRZcmg4bHh0cjNSWEFkVXNYSzZoNDBxcApJVEVVNXpkeXBxZmMyMmJpN0hhZWhxZEo0c1lsaGNYK2pJemYxVml6SHUyd25ET1BWdlQxQTFnS3NwRE9kK2NCCm9DeTF2cUNxVDkydjhjektmTHVYdFMvL2QwRkJaRjlqaU9vWnpnV0pUYTV5K1Nsak1oV0hTNU1MMEkrUk9KdW0KYi91NVRDYytKRnhpRFlIOVg3MlNWL3VJaXJVNVgwRmFnaUJ0bjRjVEF1cFVrNFRrYlN4QUxXcmNOeGFXdjZ4MgpqaEV4WThFOGFNeGRuaXRDeU56WjNBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==
  usages:
  - digital signature
  - key encipherment
  - client auth
EOF

# csr 확인 : 아직은 펜딩 상테
kubectl get csr
NAME         AGE   SIGNERNAME                              REQUESTOR              REQUESTEDDURATION   CONDITION
gasida-csr   1s    kubernetes.io/kube-apiserver-client     kubernetes-admin       <none>              Pending
...

이 과정이 완료되면 kubectl get csr 명령어를 사용하여 요청된 CSR이 보류(Pending) 상태인지 확인할 수 있습니다. 관리자가 해당 요청을 승인하면 인증서가 발급됩니다.

5.3 CSR 승인

# 'k8s 관리자' 입장에서 해당 서명 요청을 승인하자
kubectl certificate approve gasida-csr
certificatesigningrequest.certificates.k8s.io/gasida-csr approved

CSR을 승인하면 Kubernetes CA가 해당 요청을 검토하고 서명하여 유효한 클라이언트 인증서를 발급하게 됩니다. 이후, 사용자는 발급된 인증서를 이용하여 클러스터 내에서 인증된 사용자로 동작할 수 있습니다.

5.4 인증서 발급 확인

CSR이 승인된 후, 아래 명령을 사용하여 발급된 인증서를 확인할 수 있습니다. 이 인증서를 kubeconfig 파일에 추가하여 사용자가 인증된 접근을 할 수 있도록 설정해야 합니다.

# 확인 : 정상적으로 하위 인증서가 발급됨
kubectl get csr
NAME         AGE    SIGNERNAME                              REQUESTOR             REQUESTEDDURATION   CONDITION
gasida-csr   2m4s   kubernetes.io/kube-apiserver-client     kubernetes-admin      <none>              Approved,Issued
...

# csr 에서 하위 인증서 추출
kubectl get csr gasida-csr -o jsonpath='{.status.certificate}' | base64 -d
kubectl get csr gasida-csr -o jsonpath='{.status.certificate}' | base64 -d > gasida.crt

#
openssl x509 -in gasida.crt -noout -text
...
        Issuer: CN=kubernetes
        Validity
            Not Before: Mar  7 14:03:06 2025 GMT
            Not After : Mar  7 14:03:06 2026 GMT
        Subject: O=kubeadm:cluster-admins, CN=gasida-cert
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Client Authentication

5.5 kubeconfig에 새로운 사용자 등록

새로운 관리자를 위한 인증서가 발급되었으면, 이를 kubeconfig에 등록하여 해당 사용자가 Kubernetes 클러스터에 접근할 수 있도록 설정해야 합니다. 아래 명령어를 통해 신규 사용자의 인증서를 적용하고, 새로운 Kubernetes 컨텍스트(context)를 생성합니다.

# kubeconfig 에 새로운 사용자 등록
kubectl config set-credentials gasida-user --client-certificate=gasida.crt --client-key=gasida.key
kubectl config set-context kind-gasida --cluster=kind-myk8s --user=gasida-user
cat ~/.kube/config
kubectl config use-context kind-gasida # 혹은 kubectl ctx kind-gasida

5.6 신규 관리자 계정으로 Kubernetes 정보 조회

위의 설정을 완료하면 생성한 계정이 Kubernetes 클러스터에 정상적으로 접근할 수 있는지 확인해야 합니다. 아래 명령어를 실행하여 kubectl 명령이 제대로 작동하는지 검증할 수 있습니다.

# ctx kind-gasida 로 k8s 정보 확인 시도
kubectl get node

0개의 댓글