WellSpring

AEWS - 6주차 EKS Security 본문

AEWS

AEWS - 6주차 EKS Security

daniel00324 2025. 3. 11. 23:22

※ 본 게재 글은 gasida님의 'AEWS' 강의내용과 실습예제 및 AWS 공식사이트 및 EKS Security 관련 Blog 등을 참고하여 작성하였습니다.


[ 기본 개념 잡기 ]

1. 암호화를 다루는 방법론 (Crypto Graphy)

 - 정보 보안 3요소 : 기밀성(암호화, 액세스 제어..), 무결성(무단 변조 방지), 가용성 - Link

  • 기밀성 (Confidentiality)
  • 무결성 (Integrity)
  • 인증 (Authentication)

 

2. 암/복호화 과정

 - 평문을 제 3자가 해독할 수 없는 문장인 암호문으로 변환하여 전송하고, 수신측에서 평문으로 암호문으로부터 평문복원하는 과정

 - 무결성 (Integrity) 가 핵심!!

 

☞ 단방향 암호화 방법 - Ref. Link

   - Hash 알고리즘 ( CRC, MD5, RIPEMD160, SHA-1, SHA-256, SHA-512 etc )

    : 무결성 체크, 전자서명, 비밀번호, 작업증명 ( Proof of work ) 등에서 활용

 

[ 따라해 보기 ]

더보기

단방향 알고리즘 (해시) 따라해보기

  • 암호 알로리듬 테스트 온라인 사이트 : MD5 선택 - Link
  • MD5 : input - 1, 11, 111, kubernetes, 맨 뒤에 빈칸도 넣어보자
    • 확인1 : 입력 값의 길이와 상관없는지 확인
    • 확인2 : 메시지가 다르면 해시 값도 다른지 확인
    • 확인3 : kubernetes 입력 후 해시 값을 슬랙 창에 올려보고, 다른 멤버와 비교해보기
      • Output : *b76e98af9aaa680979bf5a65b2d5a105*

 

 

3. 양방향 암호화 - 대칭키 방식 

 - 동일한 키암호화복호화를 할 수 있는 기법

출처 : 정환열님 강의 JADE CROSS 자료 참조

 

 - 여러 방법론이 있는데, 그중 AES에 대해서 살펴보자. - Ref. link

  Step1. 해당 링크에서 Seed plain text "My Secret" 과 비밀키 "My password"를 넣고 암호화 후,

  Step2. 암호화 된 문구를 Seed 값으로 입력 후, 동일 비밀키 "My password"를 입력하고 복호화 수행하면 원래의 plain text "My Secret" 을 얻어 낼 수 있다.

   

4-1. 양방향 암호화 - 비대칭키 (공개키 방식) 

 - 한 쌍이 키 pair로 public key로 암호화 된 대상은 private key로 만 복호화 가능하며, 반대의 경우도 마찬가지로 pair key로 만 복호화가 가능하다.

 

[ 비대칭 키를 사용하는 이유 ]

☞ 온라인을 통해 타인과 암호화 문을 주고 받을 경우, 대칭키 방식의 경우 cracker는 탈취한 대칭키를 통해 암호화된 문서를 복호화하여 비밀이 노출될 수 위험이 있다.

출처 : 생활코딩 - https://www.youtube.com/watch?v=MR4sCU82tgo

 

비대칭 키를 사용할 경우, A는 public key를 온라인을 통해 B에게 전달한다. 이 때 Cracker 도 같이 public key를 받았다고 가정해 보자. 

B는 공개 된 Public key로 문서를 암호화 하여 A에게 보내고, 이 때 역시 Cracker가 암호화 된 정보를 탈취한다.

B는 자신이 가진 pair-keyprivate key로 해당 암호문을 풀어서 볼 수 있으나, Cracker 는 암호를 해독할 수 없다!!

출처 : 생활코딩 - https://www.youtube.com/watch?v=MR4sCU82tgo

 

☞ 대표적인 RSA키 암복호화 테스트를 통해 알고리즘을 이해해 보자!! - ref. Link

※ private key 는 절대로 노출되면 안된다!!!

더보기

Step1. 비대칭 키 생성

 

Step2. 공개키(public key)로 암호화

 

Step3. 비밀키 (private key)로 복호화

 

 

4-2. 양방향 암호화 - 비대칭키(공개키) - 전자 서명하는 법 

☞ A는 보내고자 하는 평문과 해당 plain text를 private key로 암호화 한 cipher text와 함께 B 에게 전달하고

B는 자신이 획득한 public key 로 이를 해독하여 plain text와 복호화 된 문서가 동일함을 보고 A가 보낸 것을 확인할 수 있다.

☞ 이 때, Cracker가  A가 보낸 평문을 자신이 가지고 있는 private key로 암호화 된 문서와 함께 악의적인 목적으로 B에게 보내게 되면, B는 자신이 가지고 있는 public key로 암호화 문서를 해독할 수 없고, 해당 문건이 A가 보낸 것이 아님을 인지하게 된다. 

출처 : 생활코딩 - https://www.youtube.com/watch?v=O7SiDuTCysM

 

* RSA 키를 통해 4-1번 수행과정과 동일한 방법으로 실습해 볼 수 있다!!

  RSA는 긴 데이터를 암/복호화 하는데 한계를 가지고 있어 보통 Hash 방식과 혼합하여 사용한다.

 

5. 정리

 - 암호화의 핵심은 "키를 잃어 버리지 않는 것" 이다.

 - 암호화와 보안은 상호 보완적인 것이다!!

 - 키 값이 길어지면 더 많은 computing power가 필요하다. 

   해당 시점에 주어 진 알고리즘 중 자신의 목적에 가장 부합한 것을 선택하는 것이 관건!!

더보기
출처 : 생활코딩 - https://www.youtube.com/watch?v=AJjOJdJjLzg

[ 기타 실습을 통한 이해도 넓히기 - kind 생성 및 인증서 확인 ]

 

1. [운영서버2 EC2] kind(k8s) x.509 인증서 확인

더보기

Step1. 운영서버2 EC2 공인 IP 확인 후 SSH 접속

# 노드 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

   

Step2. 인증서 정보 확인

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

#
kind create cluster --name myk8s

# 인증서 확인
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
 
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

# CSR 확인 : EKS에서도 같이 확인해보자!
kubectl get certificatesigningrequests
NAME        AGE     SIGNERNAME                                    REQUESTOR                         REQUESTEDDURATION   CONDITION
csr-852t8   4m14s   kubernetes.io/kube-apiserver-client-kubelet   system:node:myk8s-control-plane   <none>              Approved,Issued
csr-t8hvk   4m4s    kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef           <none>              Approved,Issued

kubectl describe certificatesigningrequests
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>

 

 Step3. kind 설치자의 kubeconfig 정보 확인 - https://www.base64decode.org/

# 아래 출력되는 client-certificate-data 값을 위 사이트에 붙여넣고 DECODE : 끝에 == 빼먹지 말것!
# 참고로 '운영서버1(EKS 관리자)'에서도 .kube/config 확인해보고 비교해보자.
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....

# base64 디코딩 하자!
echo "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLVENDQWhHZ0F3SUJBZ0lJTldrNnpQYWh4UUl3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBek1Ea3hNakE0TURsYUZ3MHlOakF6TURreE1qRXpNRGxhTUR3eApIekFkQmdOVkJBb1RGbXQxWW1WaFpHMDZZMngxYzNSbGNpMWhaRzFwYm5NeEdUQVhCZ05WQkFNVEVHdDFZbVZ5CmJtVjBaWE10WVdSdGFXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFEa0VYcGcKZlF5WXFjVkZOOEJMM0w0NERQOFVaQ0tyaWhOV3JvV2dYblBMSjI4S01zVW1YOGFTZzNmSTExZko0b0c2UFpuTwpOQWJFajdWckM3NDM0WitNVDRhWkZTMlBpMHg0Q0p6RUlDWms0ZDV6eVhvbUZtd2tRTFM0N2Z1SkFDWERxZDc3CncyVVJUMWp1QlJvb1lRbnA1QUk3cjJBak9Selpxa1FEZkdtOGVYQWwvYnVJazcxYnlqeVRtUGRPZnRqRUtPbmcKeXptb2g1K2xLRCs5ZlI3SHhWdnFXZEFJR0NRaFVtWUFHY3VRaFdjdEpSSGFidUpNR3VGV2tqUmZlQVh5VjI2eAoraVZFdy8wbUtKWVZwTjJrWVJUenVEQnVxQ3dtd0RSNXFTaG9VRXJJTXVqakNmYnhhOGQwL0xSOFpwcTBUaWplCkE1clNSU3VodkNRaXFTZ0JBZ01CQUFHalZqQlVNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUsKQmdnckJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRktCZUJxai9NYnJTU1FEUApnV0tWTmMvZW5ySFVNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFZenFOYjhHSVh0R0Vjbk10N21VNzM3NWFBClRYcE5HbFh3allYWUU2YkhFKzk2NDZudWlvRFE0ZGhiMGRPbFR5M1MyeVUrZE1LNHI0WkRBYU5tQm1HVkp6OXcKVVFyb3QzYi9nUmM3Ykd1bTJ5Z0hSdE5CNTlFYmVxa1BxR2hlcVVrQmZqd1BmMmJtY3NHRDQ2ZE5QaWJOS3JRYQozWG5xTjc2SmE5OGkxWDZhUGx3TnlXcnIrUzc0RlV4MGRtQ3FOSUFTQSt3cVJ3bUFuZkVqNm5nblZmVHZRZ2ovCkIwZGR6L2tYL1BUVzNNcURmWTQzRWV5alJhWGFacUJPUHF0akJ6bCtsWlBJcnc2TXhnVTM4TFp6NVVXRW1XYVcKaVdoQnRKb1RYOWhGRG1ZaERoOWx1K2QwMVh4dkRjYTluWGI2WlgvdE4yRjduK1lEZlVTdFRkL2phRU8wCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" | base64 -d
...

# 어떤 인증서인가요? 
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
...

# 아래 출력되는 client-key-data 값을 위 사이트에 붙여넣고 DECODE : 어떤 키인가요?
cat $HOME/.kube/config
    client-key-data: LS0tLS1CR....

-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAzO6NiTZgSKiIhdwc1KIfrvRPFfstapKbo/70DPXH12hyBaaZ
...


# 아래 출력되는 certificate-authority-data 값을 위 사이트에 붙여넣고 DECODE : 어떤 인증서인가요?
cat $HOME/.kube/config
    certificate-authority-data: LS0...

 

 Step4. 신규 관리자를 위한 인증서 설정 - K8S_Docs

# 하위 인증서를 위한 비밀키 생성 : 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 요청 : 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
...

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

# 확인 : 정상적으로 하위 인증서가 발급됨
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

# 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

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

[ 실행 결과 - 한 눈에 보기 ] 

 


[ 신규 관리자를 위한 인증서 설정 ]

 

 

 

 

2. Practical Guide to Kubernetes API - Blog

더보기

. 참고 링크 : Link

 

1. About K8s API ...

1) Kubernetes API는 본질적으로 RESTful합니다.

2) Stateless Communication : Client로 부터 요청되는 모든 API는 이전 call 의 상태, 내용과 상관 없이 독립적으로 수행될 수 있도록 가능한 모든 내용을 포함하고 있어야 한다.

3) Uniform Interface : Kubernetes API는 매우 일관적이고 표준화된 통신 인터페이스를 가지고 있어 기본적인 패턴만 익히면, 나머지 사용법은 이해만 하고 사용할 수 있다.

4) Self-descriptive Messages : RESTful API는 설명적 메시지를 사용하여 클라이언트와 서버 간에 통신합니다. 즉, 각 상호 작용에는 요청된 작업과 처리 방법에 대한 정보가 포함됩니다.

 

2. K8S API 노출 (Exposing the K8s API)

  • 본질적으로 RESTful하다는 것 외에도 제어 평면의 API 서버 구성 요소가 Kubernetes API를 클러스터 내의 사용자 및 다른 구성 요소에 노출한다는 것을 아는 것이 중요합니다. 공식적으로 이 구현은 kube-apiserver 라고 하며 이를 통해 최종 사용자, 클러스터의 다른 부분 및 외부 구성 요소가 서로 통신할 수 있습니다. Apart from it being RESTful in nature, it’s essential to know that API server component of the control plane is the one that exposes the Kubernetes API to users and other components within the cluster. Officially, the implementation is called kube-apiserver and this enables the end users, different parts of your cluster, and external components communicate with one another.
  • API 서버는 클러스터에 대한 외부 사용자 또는 요청에 대한 첫 번째 접점 역할을 하며 모든 내부 작업도 API 서버 구성 요소를 통해 처리됩니다. The API server acts as the first point of contact for any external user or request to the cluster and all the internal operations are channeled through the API server component as well.

3. 접근 방법 ( Ways of Accessing the API )

 1) kubectl

  • kubectlKubernetes의 공식 명령줄 도구이며 Kubernetes API와 상호 작용하는 편리한 방법을 제공합니다.
  • 직관적인 명령을 사용하여 리소스 생성 , 업데이트 및 삭제 와 같은 작업을 간소화합니다.

 2) 간단한 REST 호출 사용

# 실행 중인 모든 Pod를 가져오는 curl 요청
$ curl -s http://127.0.0.1:8080/api/v1/namespaces/default/pods

 {
   "kind": "PodList",
   "apiVersion": "v1",
   "metadata": {
     "resourceVersion": "3606"
   },
   "items": [
     {
       "metadata": {
         "name": "demo",
         "namespace": "default",
         "uid": "9cbf8ea4-9fbf-4824-a170-6cace6888a57",
         "resourceVersion": "2693",
         "creationTimestamp": "2024-03-14T05:51:03Z",
         "labels": {
           "run": "demo"
         },
 ....

 

3) 클라이언트 라이브러리 사용

  • 쿠버네티스 API와 상호 작용하는 애플리케이션을 개발하고자 하는 사람들을 위해 다양한 프로그래밍 언어(예: Python , Go , Java )로 클라이언트 라이브러리 세트를 제공합니다.
  • 이러한 라이브러리는 HTTP 요청을 만드는 복잡성을 추상화하고 쿠버네티스와 상호 작용하는 애플리케이션을 더 쉽게 빌드할 수 있도록 합니다.

 

3. API 구조 :  Resource + Verb

더보기

1. 리소스 및 동사

출처 : https://blog.kubesimplify.com/practical-guide-to-kubernetes-api
  • RESTful API를 이해하려고 하기 때문에, 통신은 주로 리소스동사를 중심으로 이루어집니다. the communication primarily revolves around resources and verbs.
  • 리소스는 상호작용하고자 하는 엔티티를 나타내고, 동사는 해당 리소스에서 수행할 수 있는 작업을 지정합니다. Resources represent the entities you want to interact with, while verbs specify the actions you can perform on those resources.
  • 간단히 말해서 리소스는 작업하고 싶은 "사물" 입니다. 쿠버네티스의 경우 포드, 서비스 또는 디플로이먼트 등이 있습니다. 반면 동사생성, 가져오기, 업데이트 또는 삭제와 같이 이러한 사물에 대해 수행할 수 있는 "작업" 입니다. In simple terms, resources are the "things" you want to work with. In case of Kubernetes, we have pods, services, or deployments etc. Verbs, on the other hand, are the "actions" you can take on those things, such as create, get, update, or delete.
  • 결론적으로, 각 리소스별도의 개체로 처리되며 기본적으로 API의 엔드포인트이므로 독립적으액세스하고 조작할 수 있습니다. In conclusion, each resource is treated as a separate entity and is basically the endpoint of the API, that can be accessed and manipulated independently.

[ 리소스 예시 - pod ]

#
kubectl get pod

#
kubectl get --raw /api/v1/namespaces/default/pods/nginx | jq
{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "nginx",
...

 

[ 동사 ]

  • GET /<resourceNamePlural>: 유형의 리소스 목록을 검색합니다 <resourceName>. 예를 들어, GET /podsPod 목록을 반환합니다.
  • POST /<resourceNamePlural>: 클라이언트가 제공한 JSON 객체를 기반으로 새로운 리소스를 생성합니다.
  • GET /<resourceNamePlural>/<name>: 주어진 이름의 단일 리소스를 가져옵니다. 예를 들어, GET /pods/first"first"라는 이름의 Pod를 검색합니다.
  • DELETE /<resourceNamePlural>/<name>: 주어진 이름을 가진 단일 리소스를 삭제합니다.
  • DELETE /<resourceNamePlural>: 유형의 리소스 목록을 삭제합니다 <resourceName>. 예를 들어, DELETE /podsPod 목록을 제거합니다.
  • PUT /<resourceNamePlural>/<name>: 클라이언트가 제공한 JSON 객체를 사용하여 지정된 이름의 리소스를 업데이트하거나 생성합니다.
  • PATCH /<resourceNamePlural>/<name>: 리소스의 지정된 필드를 선택적으로 수정합니다.
  • GET /<resourceNamePlural>?watch=true: 시간 경과에 따라 주어진 종류의 리소스에 대한 변경 사항에 해당하는 JSON 객체 스트림을 수신합니다.

2. API 그룹 및 버전 : 2가지 주요 API 그룹 - The Core Group , Named Group

 

a. The Core Group : The core (also called legacy) group is found at REST path - /api.

  • 이 특정 엔드포인트는 포드, 비밀, 구성 맵 등과 같은 핵심 K8s 리소스에서만 사용됩니다. 일반적으로 yaml파일에서 - apiVersion: v1필드로 언급.
 apiVersion: v1
 kind: Pod
 metadata:
   name: nginx
 spec:
   containers:
   - name: nginx
     image: nginx:1.14.2
     ports:
     - containerPort: 80

 

b. Named Group : The named groups are a bit more modern and generic which can be found at the REST path - /apis/<group-name>.

  • 이 엔드포인트는 다른 모든 리소스( 사용자 지정 리소스 포함 )에서 사용되며 네트워킹이나 스토리지와 같은 특정 영역을 처리.
 apiVersion: batch/v1
 kind: Job
 metadata:
   name: pi
 spec:
   template:
     spec:
       containers:
       - name: pi
         image: perl:5.34.0
         command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
       restartPolicy: Never
   backoffLimit: 4
  • 각 API 그룹은 시간이 지남에 따라 진화하는 독립적인 버전이 지정되어 개발 및 사용의 여러 단계를 거침.
    • alpha실험적이며 잠재적으로 불안정함.
    • beta더 많은 테스트를 거쳤지만 아직 변경될 수 있음.
    • stable또는 GA(일반 제공) - 안정적이며 프로덕션에 바로 사용할 수 있습니다.
  • K8s API 참조 에서 모든 API 그룹의 전체 목록과 버전을 확인하거나 간단한 명령을 사용하여 kubectl api-resources동일한 작업을 수행할 수 있습니다.
$ kubectl api-resources
NAME                              SHORTNAMES   APIVERSION                        NAMESPACED   KIND
bindings                                       v1                                true         Binding
componentstatuses                 cs           v1                                false        ComponentStatus
configmaps                        cm           v1                                true         ConfigMap
endpoints                         ep           v1                                true         Endpoints
events                            ev           v1                                true         Event
limitranges                       limits       v1                                true         LimitRange
namespaces                        ns           v1                                false        Namespace
nodes                             no           v1                                false        Node
persistentvolumeclaims            pvc          v1                                true         PersistentVolumeClaim
persistentvolumes                 pv           v1                                false        PersistentVolume
pods                              po           v1                                true         Pod
...

 

3. 종류 (객체 스키마) Kind (Object Schema)

  • 이전에 Kubernetes를 사용해 본 적이 있고 일반적인 Kubernetes yaml 매니페스트를 다루는 방법을 알고 있다면, 아마도 이 분야를 접했을 것입니다 kind. 예를 들어 - kind: Pod, kind: Ingress, kind: Deployment
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

 

  • sig-architecture API 규칙 에 따라 종류는 세 가지 범주로 그룹화됩니다.
    • Object ( Pod, Service, 등) - 시스템 내의 영구 엔티티
    • List ( PodList, APIResourceList, 등) - 한 종류 이상의 리소스 모음
    • Simple - 객체( status, scale, 등) 또는 비지속형 보조 엔티티( ListOptions, Policy, 등)에 대한 특정 작업

 

 


0. 실습환경 구성

  Amazon EKS (myeks) 윈클릭 배포 (bastion ec2 2대) & 기본 설정

더보기
  • bastion ec2 : 운영서버1, 운영서버2
  • Amazon EKS (myeks) 윈클릭 배포  ( * 사전 변수 지정 누락되지 않도록 주의 !! )
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/myeks-6week.yaml

# 변수 지정
CLUSTER_NAME=myeks
SSHKEYNAME=<SSH 키 페이 이름>
MYACCESSKEY=<IAM Uesr 액세스 키>
MYSECRETKEY=<IAM Uesr 시크릿 키>

# CloudFormation 스택 배포
aws cloudformation deploy --template-file myeks-6week.yaml --stack-name $CLUSTER_NAME --parameter-overrides KeyName=$SSHKEYNAME SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32  MyIamUserAccessKeyID=$MYACCESSKEY MyIamUserSecretAccessKey=$MYSECRETKEY ClusterBaseName=$CLUSTER_NAME --region ap-northeast-2

# CloudFormation 스택 배포 완료 후 작업용 EC2 IP 출력
aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text

(옵션) 배포 과정 살펴보기

# 운영서버 EC2 SSH 접속
ssh -i <SSH 키 파일 위치> ec2-user@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)
ssh -i ~/.ssh/kp-gasida.pem ec2-user@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)
-------------------------------------------------
#
whoami
pwd

# cloud-init 실행 과정 로그 확인
tail -f /var/log/cloud-init-output.log

# eks 설정 파일 확인
cat myeks.yaml

# cloud-init 정상 완료 후 eksctl 실행 과정 로그 확인
tail -f /root/create-eks.log

#
exit
-------------------------------------------------

 

자신의 PC에서 AWS EKS 설치 확인 ← 스택 생성 시작 후 20분 후 접속 할 것

더보기

Step1. Stack 배포

# 변수 지정
CLUSTER_NAME=myeks-kyukim
SSHKEYNAME=kp-kyukim

#
eksctl get cluster

# kubeconfig 생성
aws sts get-caller-identity --query Arn
aws eks update-kubeconfig --name myeks --user-alias <위 출력된 자격증명 사용자>
aws eks update-kubeconfig --name myeks --user-alias admin

# 
kubectl ns default
kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
kubectl get pod -A
kubectl get pdb -n kube-system

 

Step2. 노드 IP 정보 확인 및 SSH 접속

# EC2 공인 IP 변수 지정
export N1=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=myeks-ng1-Node" "Name=availability-zone,Values=ap-northeast-2a" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N2=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=myeks-ng1-Node" "Name=availability-zone,Values=ap-northeast-2b" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N3=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=myeks-ng1-Node" "Name=availability-zone,Values=ap-northeast-2c" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
echo $N1, $N2, $N3

# *remoteAccess* 포함된 보안그룹 ID
aws ec2 describe-security-groups --filters "Name=group-name,Values=*remoteAccess*" | jq
export MNSGID=$(aws ec2 describe-security-groups --filters "Name=group-name,Values=*remoteAccess*" --query 'SecurityGroups[*].GroupId' --output text)

# 해당 보안그룹 inbound 에 자신의 집 공인 IP 룰 추가
aws ec2 authorize-security-group-ingress --group-id $MNSGID --protocol '-1' --cidr $(curl -s ipinfo.io/ip)/32

# 해당 보안그룹 inbound 에 운영서버 내부 IP 룰 추가
aws ec2 authorize-security-group-ingress --group-id $MNSGID --protocol '-1' --cidr 172.20.1.100/32
aws ec2 authorize-security-group-ingress --group-id $MNSGID --protocol '-1' --cidr 172.20.1.200/32

# 워커 노드 SSH 접속
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ssh -o StrictHostKeyChecking=no ec2-user@$i hostname; echo; done

 

운영서버1 EC2 SSH 접속 (SSH 키 파일 사용) : AWS EKS 설치 확인 ← 스택 생성 시작 후 20분 후 접속 할 것

더보기
# default 네임스페이스 적용
kubectl ns default

# 환경변수 정보 확인
export | egrep 'ACCOUNT|AWS_|CLUSTER|KUBERNETES|VPC|Subnet'
export | egrep 'ACCOUNT|AWS_|CLUSTER|KUBERNETES|VPC|Subnet' | egrep -v 'KEY'

# krew 플러그인 확인 : 보안 관련 플러그인 다수 설치
kubectl krew list

# 인스턴스 정보 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{InstanceID:InstanceId, PublicIPAdd:PublicIpAddress, PrivateIPAdd:PrivateIpAddress, InstanceName:Tags[?Key=='Name']|[0].Value, Status:State.Name}" --filters Name=instance-state-name,Values=running --output table

# 노드 IP 확인 및 PrivateIP 변수 지정
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output table
N1=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a -o jsonpath={.items[0].status.addresses[0].address})
N2=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2b -o jsonpath={.items[0].status.addresses[0].address})
N3=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c -o jsonpath={.items[0].status.addresses[0].address})
echo "export N1=$N1" >> /etc/profile
echo "export N2=$N2" >> /etc/profile
echo "export N3=$N3" >> /etc/profile
echo $N1, $N2, $N3

# 노드 IP 로 ping 테스트
for i in $N1 $N2 $N3; do echo ">> node $i <<"; ping -c 1 $i ; echo; done

 

  • 운영서버2 EC2 에 SSH 접속 (SSH 키 파일 사용) : kind(k8s) 설치 확인 → 위에 별도 실습 내용 참고!

EKS 배포 후 실습 편의를 위한 설정 : macOS, Windows(WSL2)

더보기

☆ MAC 환경 ( 실습 후, 삭제 필요 )

# 변수 지정
export CLUSTER_NAME=myeks
export VPCID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" --query 'Vpcs[*].VpcId' --output text)
export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet2" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet3=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet3" --query "Subnets[0].[SubnetId]" --output text)
export N1=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2a" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N2=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2b" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N3=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2c" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export CERT_ARN=$(aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text) #사용 리전의 인증서 ARN 확인
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
MyDomain=gasida.link # 각자 자신의 도메인 이름 입력
MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "$MyDomain." --query "HostedZones[0].Id" --output text)


# 실습 완료 후 삭제 할 것!
cat << EOF >> ~/.zshrc

# eksworkshop
export CLUSTER_NAME=myeks
export VPCID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" --query 'Vpcs[*].VpcId' --output text)
export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet2" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet3=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet3" --query "Subnets[0].[SubnetId]" --output text)
export N1=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2a" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N2=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2b" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N3=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2c" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export CERT_ARN=$(aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text)
MyDomain=gasida.link # 각자 자신의 도메인 이름 입력
MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "$MyDomain." --query "HostedZones[0].Id" --output text)
EOF

# [신규 터미널] 확인
echo $CLUSTER_NAME $VPCID $PubSubnet1 $PubSubnet2 $PubSubnet3
echo $N1 $N2 $N3 $MyDomain $MyDnzHostedZoneId
tail -n 15 ~/.zshrc

  

☆ Windows 환경 ( 실습 후, 삭제 필요 )

# 변수 지정
export CLUSTER_NAME=myeks
export VPCID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" --query 'Vpcs[*].VpcId' --output text)
export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet2" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet3=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet3" --query "Subnets[0].[SubnetId]" --output text)
export N1=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2a" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N2=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2b" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N3=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2c" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export CERT_ARN=$(aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text) #사용 리전의 인증서 ARN 확인
MyDomain=gasida.link # 각자 자신의 도메인 이름 입력
MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "$MyDomain." --query "HostedZones[0].Id" --output text)


# 실습 완료 후 삭제 할 것!
cat << EOF >> ~/.bashrc

# eksworkshop
export CLUSTER_NAME=myeks
export VPCID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" --query 'Vpcs[*].VpcId' --output text)
export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet2" --query "Subnets[0].[SubnetId]" --output text)
export PubSubnet3=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-Vpc1PublicSubnet3" --query "Subnets[0].[SubnetId]" --output text)
export N1=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2a" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N2=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2b" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export N3=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$CLUSTER_NAME-ng1-Node" "Name=availability-zone,Values=ap-northeast-2c" --query 'Reservations[*].Instances[*].PublicIpAddress' --output text)
export CERT_ARN=$(aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text)
MyDomain=gasida.link # 각자 자신의 도메인 이름 입력
MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "$MyDomain." --query "HostedZones[0].Id" --output text)
EOF

# [신규 터미널] 확인
echo $CLUSTER_NAME $VPCID $PubSubnet1 $PubSubnet2 $PubSubnet3
echo $N1 $N2 $N3 $MyDomain $MyDnzHostedZoneId
tail -n 15 ~/.bashrc

 

 

AWS LoadBalancer Controller, ExternalDNS, gp3 storageclass, kube-ops-view(Ingress) 설치

더보기

Step1. 설치

# AWS LoadBalancerController
helm repo add eks https://aws.github.io/eks-charts
helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=$CLUSTER_NAME \
  --set serviceAccount.create=false --set serviceAccount.name=aws-load-balancer-controller

# ExternalDNS
echo $MyDomain
curl -s https://raw.githubusercontent.com/gasida/PKOS/main/aews/externaldns.yaml | MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst | kubectl apply -f -

# gp3 스토리지 클래스 생성
cat <<EOF | kubectl apply -f -
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gp3
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
allowVolumeExpansion: true
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  allowAutoIOPSPerGBIncrease: 'true'
  encrypted: 'true'
  fsType: xfs # 기본값이 ext4
EOF
kubectl get sc


# kube-ops-view
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=ClusterIP  --set env.TZ="Asia/Seoul" --namespace kube-system

# kubeopsview 용 Ingress 설정 : group 설정으로 1대의 ALB를 여러개의 ingress 에서 공용 사용
echo $CERT_ARN
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
    alb.ingress.kubernetes.io/group.name: study
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
    alb.ingress.kubernetes.io/load-balancer-name: $CLUSTER_NAME-ingress-alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/success-codes: 200-399
    alb.ingress.kubernetes.io/target-type: ip
  labels:
    app.kubernetes.io/name: kubeopsview
  name: kubeopsview
  namespace: kube-system
spec:
  ingressClassName: alb
  rules:
  - host: kubeopsview.$MyDomain
    http:
      paths:
      - backend:
          service:
            name: kube-ops-view
            port:
              number: 8080  # name: http
        path: /
        pathType: Prefix
EOF

 

Step2. 확인

# 설치된 파드 정보 확인
kubectl get pods -n kube-system

# service, ep, ingress 확인
kubectl get ingress,svc,ep -n kube-system

# Kube Ops View 접속 정보 확인 : 조금 오래 기다리면 접속됨...
echo -e "Kube Ops View URL = https://kubeopsview.$MyDomain/#scale=1.5"
open "https://kubeopsview.$MyDomain/#scale=1.5" # macOS

 

[ 설치 결과 - 한 눈에 보기 ]

 

프로메테우스 & 그라파나(admin / prom-operator) 설치 : 대시보드 Import 17900 - Link

더보기

※ 주의 : Annotation 에서 alb.ingress.kubernetes.io/load-balancer-name 은 자신의 자원명에 맞게 수정할 것!!

( In my case, alb.ingress.kubernetes.io/load-balancer-name= myeks-kyukim-ingress-alb ) 

# repo 추가
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts

# 파라미터 파일 생성 : PV/PVC(AWS EBS) 삭제에 불편하니, 4주차 실습과 다르게 PV/PVC 미사용
cat <<EOT > monitor-values.yaml
prometheus:
  prometheusSpec:
    scrapeInterval: "15s"
    evaluationInterval: "15s"
    podMonitorSelectorNilUsesHelmValues: false
    serviceMonitorSelectorNilUsesHelmValues: false
    retention: 5d
    retentionSize: "10GiB"
  
  # Enable vertical pod autoscaler support for prometheus-operator
  verticalPodAutoscaler:
    enabled: true

  ingress:
    enabled: true
    ingressClassName: alb
    hosts: 
      - prometheus.$MyDomain
    paths: 
      - /*
    annotations:
      alb.ingress.kubernetes.io/scheme: internet-facing
      alb.ingress.kubernetes.io/target-type: ip
      alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
      alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
      alb.ingress.kubernetes.io/success-codes: 200-399
      alb.ingress.kubernetes.io/load-balancer-name: myeks-kyukim-ingress-alb
      alb.ingress.kubernetes.io/group.name: study
      alb.ingress.kubernetes.io/ssl-redirect: '443'

grafana:
  defaultDashboardsTimezone: Asia/Seoul
  adminPassword: prom-operator
  defaultDashboardsEnabled: false

  ingress:
    enabled: true
    ingressClassName: alb
    hosts: 
      - grafana.$MyDomain
    paths: 
      - /*
    annotations:
      alb.ingress.kubernetes.io/scheme: internet-facing
      alb.ingress.kubernetes.io/target-type: ip
      alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
      alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
      alb.ingress.kubernetes.io/success-codes: 200-399
      alb.ingress.kubernetes.io/load-balancer-name: myeks-kyukim-ingress-alb
      alb.ingress.kubernetes.io/group.name: study
      alb.ingress.kubernetes.io/ssl-redirect: '443'

alertmanager:
  enabled: false
defaultRules:
  create: false
kubeControllerManager:
  enabled: false
kubeEtcd:
  enabled: false
kubeScheduler:
  enabled: false
prometheus-windows-exporter:
  prometheus:
    monitor:
      enabled: false
EOT
cat monitor-values.yaml

# helm 배포
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 69.3.1 \
-f monitor-values.yaml --create-namespace --namespace monitoring

# helm 확인
helm get values -n monitoring kube-prometheus-stack

# PV 사용하지 않음
kubectl get pv,pvc -A
kubectl df-pv

# 프로메테우스 웹 접속
echo -e "https://prometheus.$MyDomain"
open "https://prometheus.$MyDomain" # macOS

# 그라파나 웹 접속 : admin / prom-operator
echo -e "https://grafana.$MyDomain"
open "https://grafana.$MyDomain" # macOS

(옵션) 4주차 노션 확인하여 17900 대시보드에 PromQL/Variables 수정 해둘 것 - Link

[1 Kubernetes All-in-one Cluster Monitoring KR] Dashboard → New → Import → 17900 입력 후 Load ⇒ 데이터소스(Prometheus 선택) 후 Import 클릭

☞ TASK1 : 해당 패널에서 Edit → 아래 수정 쿼리 입력 후 Run queries 클릭 → 상단 Save 후 Apply

# 수정 : CPU 점유율
sum by (instance) (irate(node_cpu_seconds_total{mode!~"guest.*|idle|iowait", instance="$instance"}[5m]))

# 수정 : 메모리 점유율
(node_memory_MemTotal_bytes{instance="$instance"}-node_memory_MemAvailable_bytes{instance="$instance"})/node_memory_MemTotal_bytes{instance="$instance"}

# 수정 : 디스크 사용률
sum(node_filesystem_size_bytes{instance="$instance"} - node_filesystem_avail_bytes{instance="$instance"}) by (instance) / sum(node_filesystem_size_bytes{instance="$instance"}) by (instance)

======================================================================
☞ TASK2 :  상단 네임스페이스와 파드 정보 필터링 출력되게 수정해보자!

1) 오른쪽 상단 Edit → Settings → Variables 아래 namesapce, pod 값 수정 ⇒ 수정 후 Save dashboard 클릭
2) namespace 경우 : kube_pod_info 로 수정
3) namespace 오른쪽 Showing usages for 클릭 시 → 맨 하단에 pod variable 가 namespace 를 하위 종속관계 확인
======================================================================
☞  TASK3 : POD의 리소스 할당 제한 표기오류 Fix 해 보자!!
1) 리소스 할당 제한 패널 edit → Save dashboard
sum(kube_pod_container_resource_limits{resource="cpu", pod="$pod"})

2) Memory 수정
sum(kube_pod_container_resource_limits{resource="memory", pod="$pod"})

 

1. K8S 인증/인가

  인증(Authentication) 은 특정 User의 접근의 허용을 결정하는 것으로  ID/Password 가 사용된다.

      Kubernetes에서 UserObject를 대상으로 부여된다.

☞  인가(Authorization) 은 인증이 완료된 유저에게 어떤 리소스에 대해 어떤 범위까지 Action 을 허용할지를 결정하는 기준으로 Role, Action 등을 사용한다. Kubernetes 에서  User, Group, Service Account 에 부여된다.

 

[ More ... ]

더보기

1) K8S(API 접근) 인증/인가 : 출처 - 김태민 기술 블로그 - 링크 링크2

  • API 서버 사용 : kubectl(config, 다수 클러스터 관리 가능), 서비스 어카운트, https(x.509 Client Certs) ⇒ X.509 발음을 어떻게 하시나요? - 링크
  • API 서버 접근 과정 : 인증 → 인가 → Admission Control(API 요청 검증, 필요 시 변형 - 예. ResourceQuota, LimitRange) - 참고

 

Controlling Access to the Kubernetes API - Docs

출처 : https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/

 

Admission Process : Mutating(변경), Validating(검사)

 

2) 인증 ( Authentication )

  • X.509 Client Certs : kubeconfig 에 CA crt(발급 기관 인증서) , Client crt(클라이언트 인증서) , Client key(클라이언트 개인키) 를 통해 인증
  • kubectl : 여러 클러스터(kubeconfig)를 관리 가능 - contexts 에 클러스터와 유저 및 인증서/ 참고
  • Service Account : 기본 서비스 어카운트(default) - 시크릿(CA crt 와 token)

 

 3) 인가 (Authorization)

  • 인가 방식 : RBAC(Role, RoleBinding), ABAC, Webhook, Node Authorization ⇒ RBAC 발음을 어떻게 하시나요?
  • RBAC : 역할 기반의 권한 관리, 사용자와 역할을 별개로 선언 후 두가지를 조합(binding)해서 사용자에게 권한을 부여하여 kubectl or API로 관리 가능
    • Namespace/Cluster - Role/ClusterRole, RoleBinding/ClusterRoleBinding, Service Account
    • Role(롤) - (RoleBinding 롤 바인딩) - Service Account(서비스 어카운트) : 롤 바인딩은 롤과 서비스 어카운트를 연결
    • Role(네임스페이스내 자원의 권한) vs ClusterRole(클러스터 수준의 자원의 권한)

 

 

4) .kube/config 내용 살펴보기

  • clusters : kubectl 이 사용할 쿠버네티스 API 서버의 접속 정보 목록. 원격의 쿠버네티스 API 서버의 주소를 추가해 사용 가능
  • users : 쿠버네티스의 API 서버에 접속하기 위한 사용자 인증 정보 목록. (서비스 어카운트의 토큰, 혹은 인증서의 데이터 등)
  • contexts : cluster 항목과 users 항목에 정의된 값을 조합해 최종적으로 사용할 쿠버네티스 클러스터의 정보(컨텍스트)를 설정.
    • 예를 들어 clusters 항목에 클러스터 A,B 가 정의돼 있고, users 항목에 사용자 a,b 가 정의돼 있다면 cluster A + user a 를 조합해, 'cluster A 에 user a 로 인증해 쿠버네티스를 사용한다' 라는 새로운 컨텍스트를 정의할 수 있습니다.
    • kubectl 을 사용하려면 여러 개의 컨텍스트 중 하나를 선택.
cat .kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeE1Ea3dNVEl5TkRjMU1sb1hEVE14TURnek1ESXlORGMxTWxvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTG1qCml1cW11UUxWTXN6UE83VUpxTkdCNHdXQ3RnYTl1cFcwYUVNVmUrZm41YXZZMWxUWUZqZjBCb1VlQXhOWmc5YXoKRU1FZVJMWCt1ZzhqTDNETjhCTzEwdUEwSzF6b3ZpQVVtbDlCU2dNWU9FOHpUMFJsV2tvcnBtVDNGai9td1lJagpEemRxYld6MlpuQ1FoQ3dvYURzdlpoUVNMRTh6dnFwU0F5c0hNSUdzV3J0anI4aC9QaW52dnF5bUo0UlFhWlY3CnNuZ0lzMDBqakdGbFowcUVueWZMSGtBeHpjSktVUnJHamFsZm1RdmZ3WkZ2Z0pjam5rSG9jb3g0T0JKUEh0N2EKdFE1OEpBTTF3cng0b3pFSjh1MExsa21LOWYwWGVzQmRGeUhFamZ1elhTYml0Q09sbTR1Q1o3UkVRVmRjZWk1SAo3Tjg1M1RjbWRIck9tRkQwZVpVQ0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZLRVYvZFNBUkJteVhyLytxUkVnb1h5QUg3UTZNQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFDQ0M4cDRQRmdoVVFDbW5weWk1SDAxYVRNYXp0Si9pdkw0amxiMWJNdXc3ZjJNZmM0UQpDRGw2UWVNd2FpYk9raHNrVGhMTEtRckQwQ0xqWXNCSy9iNVhQSTNtMmoxS0cvc1ExREFPL0hNdmt6RmkzUDdrCmJHOUErdWk1YXJPREs5eWJFQ2NtUG5adnVmWkFSY3d3dkp1ZGRMUy9QZERkOW9ZVGgzV3FQMjloVk9tZnZUS3kKNFhzeVg0cHk5dzVTNkYxaGVpUE9odnprMWRzNWFZZENBR1E5R0ZRb3BIQSs1Wm9YOWJjazFuN0FiMDVua0UrUQprMTVnc1VhQWFEMGVGUlRHY0tRTzM5dW1ZdkxhVnUrL20xcDFFRWU0YWdLdktvUGZlZ1VJTFQ0dGtLdjFwcWYvCmhIZldDUFo3Vy9ldmRZODI5WmtudE1HWHZ5QXZaWHFUZE1KZwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
    server: https://192.168.100.10:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    namespace: default
    user: kubernetes-admin
  name: admin@k8s
current-context: admin@k8s
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJUzFnbmhwU0N5Q2d3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRBNU1ERXlNalEzTlRKYUZ3MHlNakE1TURFeU1qUTNOVFZhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQW52eXoxc1R1SXRpKzE3WmQKVVRXTFVxMUxIL2VJN01lMkI0K2ZNZlhKSStlM2xCVnp5RXpIV0ZOR1phM2JYbkYvS0VJaDJRcmpOcXh0bGswSgpIOW83dUtVZmRyVjhNL3IzZmxidUN1VG9lZnN3UFROQmJhbGladzVPRXl0VWV6V3ZxK3VUZzFmeExZVUl6Zk4xCldxMzhiU2pjYlhQa3Q3UWJZVThqUEpMMmlKalBlbVFRN1FnTW9pUmlsNXM2TzRCZnNYbzNCbDNrdUY0VDlCK1MKVzE2VmpQTnRMQ0pxQW1ENEt1ZWdBcWl3RHdDNFVScjhNbDhJaHJmL2FzT2JTZnVqTG5HL1Npd2V6dnJ4bHJnUgo0QVBlNjFSOU1RZFFjaldsT1Z2TXQrSXhlSnlrbWdmeHJsNFJmbytFOWVNK0VTNzFHaVhnQmtycFp0NGxQWURsClllSVZQd0lEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JTaEZmM1VnRVFac2w2Ly9xa1JJS0Y4Z0IrMApPakFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBa0ZqdDJPNW5ZQUkxRHRrZnh6R1RPbFdGT1F3b3FKelBHQXJSCmRoTnFXL3JjUlhyYkgzZ3FHaXF4cmQ2anczblJiYThCRWxOazE0YUtYWGVYRnU0U0YyYTJCY3RzKzhkNE9VSkwKeU1pUVBpN0g2Q3RrQ0o2QzRCZDU4Vk5XaVM0YVg4b0ExQWloZWp0cURRc2U2MCtna2JoSlJwdnM0WGRVUkNTdgpFL3NqZWgvc1JIVjBJYWNrNzlTVEduSUdlVVUrbUxwVlF1bHZkd1lkVDhXK08zMkpRbFk1Z3pTZllFMkI2YjB4Ci9TK1dORU9QTzhhaTlmQkQ5cWJ1dWdRd2wzSkNYT005amZLV1gzOTBZZzhYcWhndEhuR0JDdlcwbjQxY0ZLUDgKQVFFdXRnbDNhQ0ZibWZFZ2Z3cWlUVFc3R3EzSklZSTZrZ3EwNGxUbVdKa1gvQnZmaXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBbnZ5ejFzVHVJdGkrMTdaZFVUV0xVcTFMSC9lSTdNZTJCNCtmTWZYSkkrZTNsQlZ6CnlFekhXRk5HWmEzYlhuRi9LRUloMlFyak5xeHRsazBKSDlvN3VLVWZkclY4TS9yM2ZsYnVDdVRvZWZzd1BUTkIKYmFsaVp3NU9FeXRVZXpXdnErdVRnMWZ4TFlVSXpmTjFXcTM4YlNqY2JYUGt0N1FiWVU4alBKTDJpSmpQZW1RUQo3UWdNb2lSaWw1czZPNEJmc1hvM0JsM2t1RjRUOUIrU1cxNlZqUE50TENKcUFtRDRLdWVnQXFpd0R3QzRVUnI4Ck1sOElocmYvYXNPYlNmdWpMbkcvU2l3ZXp2cnhscmdSNEFQZTYxUjlNUWRRY2pXbE9Wdk10K0l4ZUp5a21nZngKcmw0UmZvK0U5ZU0rRVM3MUdpWGdCa3JwWnQ0bFBZRGxZZUlWUHdJREFRQUJBb0lCQUQzOHFPR0R4cFV2akxqdQpFVlFvWERuUDl3cHZxS01vK24vWUwybDdPd0VVeHk2bGJvOFo0RjgvbUtMc05pdU1kTmR0Y1dUK0tiaVhZZUxJCkJsYTA3N1ArTFZaTFRERzRGK2JhWGRWQmlxS0VuVG8vVWJNLzUyM20xZW9EYXR6ZkFhODJHajJMZkMwVFFXdUwKRUtaYVQ2RC8zWEdQVGcyUjIxc0ZUK2UrSlFEOGRnc25oNE9vVlQrTkRacC9kU0JHYXZNQTFZUmo0bFhwY1U5RAo5bW15ckxRZFlRcE56K1U4cGZKdHhIcXlGSWhOakZmK0JkNHdRdEhrN3NOODE4Um9JalZHV3RYeGVhZXFOMXVtCnFlWEhFNHVDRG5tYS9qTElLLzBRaWlMZTZ1WGVTMk1udG1UUjJ1d0paOWh5V3NsYnlTb2oyQmNONVBaaHpGK3kKMUtyZEFZRUNnWUVBenNEeUFtZ1dUUXI5M083ZnlSR1U5azBad01LRFVSK25Lb0xQcUNhSmxQeE4xaG1zTkJmWApKWURsZ3cwVTk5R1lmRGJZUTdjS3BaRE8xWHZpWTI4K1UxY21nM2xVMVFVOTdFR0N3ejVxMnNjUFY0SDBhZmxnCmNUQko5dGo1ZTkzVS9sVDFpd0M1eEFONlpjektTbzhYSytNQ29nUkEyeEFZZjFJZnJTZmhoVzBDZ1lFQXhOc2kKQ2oxS29FQzV0TjlEaW41eFQzMUVBTjlwVmtONkZlcy9nZC9JSFREWXJLSytaMnNpVVNhR1NyaHYwZkc1ZGVwagpIMjdEeVF6cW1aUUlpaE44cFB5TzRSOXMya21la3RISUZqMjRnSUpQZDNzS3BaS1QwQjJmZUErTXVCOFlsclRGCk0ycTJ2V1JHeHFmMERMZmpWNm5JVkZkQ1hJWFZLMjlRcWprdkZkc0NnWUFmUGRxVDhJU0dLY1lJajNQelh4dkMKU0E0L0tXVk1hZHNKdW5DRWVTWkxCQUVDL0NnZ1N3WHduZFNRZy9hS0ovckJza3ZsbDVBZFNvOW1oT3pGbDdhMApRelFIbzlya3dZRUU1VFZNS1c5ZUZieEV2ZGRmK0JYUnBMbFllcHJnVTdudW9Jbmw4anNmMm1LeFpVdWdEcFV5CnhYL05XWlV2UlBSZXNOc21nQ004MVFLQmdRQ0xSOFFJM0o3TlRaNVhNOVJVeSt1ZDR6SlhMN3NXMXIwdGZ2bTcKQ1R0TU5BQkovUWVjb25kd1ZVS1U0WFAwWmdQalF3Z0krRlM4RGxCNmd2dWJ2ZmZsdisvVHBtbGM5Tk9tYTVrVwo2MnA4T2piQmdhUGh6QmliR2lwM1J3RTRVSUFVT1NpQm5aSlg0L2dUbkVlWExCQkZPUkpOWWtQSXRNUkRiQW4xCnRtbnpHd0tCZ0J3NHhLanNEUUozcCtxWW50cTdtVzhLS2hPWTFMRWczOVJ4Snd1aEord0VSZUh5TGhIcEU5SFkKUndxbUVCYjdvY2dDcmV6bWR5WndUSXZkMGEzaStBbWpucTd1QU1DUFpNUjU0a2FkNUpmZmVib0FzbXcwSW5aeApvVGltQXNya3BmRlVxZzZsSVBIMEtuUEVTVWQxQlJLS2I5dTUzTWpwZEZiVkhWZVZhVEtlCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

  

[ 실습 - 따라하며 이해하기 ]

실습환경 설명

더보기
  • 쿠버네티스에 사용자를 위한 서비스 어카운트(Service Account, SA)를 생성 : dev-k8s, infra-k8s
  • 사용자는 각기 다른 권한(Role, 인가)을 가짐 : dev-k8s(dev-team 네임스페이스 내 모든 동작) , infra-k8s(dev-team 네임스페이스 내 모든 동작)
  • 각각 별도의 kubectl 파드를 생성하고, 해당 파드에 SA 를 지정하여 권한에 대한 테스트를 진행

 

네임스페이스와 서비스 어카운트 생성 후 확인

더보기
  • 파드 기동 시 서비스 어카운트 한 개가 할당되며, 서비스 어카운트 기반 인증/인가를 함, 미지정 시 기본 서비스 어카운트가 할당
  • 서비스 어카운트에 자동 생성된 시크릿에 저장된 토큰으로 쿠버네티스 API에 대한 인증 정보로 사용 할 수 있다 ← 1.23 이전 버전의 경우에만 해당
# 네임스페이스(Namespace, NS) 생성 및 확인
kubectl create namespace dev-team
kubectl create ns infra-team

# 네임스페이스 확인
kubectl get ns

# 네임스페이스에 각각 서비스 어카운트 생성 : serviceaccounts 약자(=sa)
kubectl create sa dev-k8s -n dev-team
kubectl create sa infra-k8s -n infra-team

# 서비스 어카운트 정보 확인
kubectl get sa -n dev-team
kubectl get sa dev-k8s -n dev-team -o yaml

kubectl get sa -n infra-team
kubectl get sa infra-k8s -n infra-team -o yaml

 

서비스 어카운트를 지정하여 파드 생성 후 권한 테스트

더보기

 

Ref. : https://kubetm.github.io/practice/intermediate/object-authentication/
# 각각 네임스피이스에 kubectl 파드 생성 - 컨테이너이미지
# docker run --rm --name kubectl -v /path/to/your/kube/config:/.kube/config bitnami/kubectl:latest
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: dev-kubectl
  namespace: dev-team
spec:
  serviceAccountName: dev-k8s
  containers:
  - name: kubectl-pod
    image: bitnami/kubectl:1.31.4
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: infra-kubectl
  namespace: infra-team
spec:
  serviceAccountName: infra-k8s
  containers:
  - name: kubectl-pod
    image: bitnami/kubectl:1.31.4
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

# 확인
kubectl get pod -A
kubectl get pod -o dev-kubectl -n dev-team -o yaml
 serviceAccount: dev-k8s
 ...
kubectl get pod -o infra-kubectl -n infra-team -o yaml
 serviceAccount: infra-k8s
...

# 파드에 기본 적용되는 서비스 어카운트(토큰) 정보 확인
kubectl exec -it dev-kubectl -n dev-team -- ls /run/secrets/kubernetes.io/serviceaccount
kubectl exec -it dev-kubectl -n dev-team -- cat /run/secrets/kubernetes.io/serviceaccount/token
kubectl exec -it dev-kubectl -n dev-team -- cat /run/secrets/kubernetes.io/serviceaccount/namespace
kubectl exec -it dev-kubectl -n dev-team -- cat /run/secrets/kubernetes.io/serviceaccount/ca.crt

# 각각 파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
alias k1='kubectl exec -it dev-kubectl -n dev-team -- kubectl'
alias k2='kubectl exec -it infra-kubectl -n infra-team -- kubectl'

# 권한 테스트
k1 get pods # kubectl exec -it dev-kubectl -n dev-team -- kubectl get pods 와 동일한 실행 명령이다!
k1 run nginx --image nginx:1.20-alpine
k1 get pods -n kube-system

k2 get pods # kubectl exec -it infra-kubectl -n infra-team -- kubectl get pods 와 동일한 실행 명령이다!
k2 run nginx --image nginx:1.20-alpine
k2 get pods -n kube-system

# (옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
no

 

각각 네임스페이스에 롤(Role)를 생성 후 서비스 어카운트 바인딩*   

더보기
  • 롤(Role) : apiGroups 와 resources 로 지정된 리소스에 대해 verbs 권한을 인가
  • 실행 가능한 조작(verbs) : *(모두 처리), create(생성), delete(삭제), get(조회), list(목록조회), patch(일부업데이트), update(업데이트), watch(변경감시)
https://kubetm.github.io/practice/intermediate/object-authorization/

Kubernetes API Concepts* - Docs

참고 : https://blog.kubesimplify.com/practical-guide-to-kubernetes-api
참고 : https://iximiuz.com/en/series/working-with-kubernetes-api/

# Print the supported API resources on the server.
kubectl api-resources

# Print the supported API resources with more information
kubectl api-resources -o wide
  
# Print the supported API resources with a specific APIGroup
kubectl api-resources --api-group=""
kubectl api-resources --api-group="apps"
kubectl api-resources --api-group=metrics.k8s.io
kubectl api-resources --api-group=admissionregistration.k8s.io
kubectl api-resources --api-group=rbac.authorization.k8s.io
kubectl api-resources --api-group=apiextensions.k8s.io


# 각각 네임스페이스내의 모든 권한에 대한 롤 생성
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: role-dev-team
  namespace: dev-team
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
EOF

cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: role-infra-team
  namespace: infra-team
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
EOF

# 롤 확인 
kubectl get roles -n dev-team
kubectl get roles -n infra-team
kubectl get roles -n dev-team -o yaml
kubectl describe roles role-dev-team -n dev-team
...
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  *.*        []                 []              [*]

# 롤바인딩 생성 : '서비스어카운트 <-> 롤' 간 서로 연동
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: roleB-dev-team
  namespace: dev-team
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: role-dev-team
subjects:
- kind: ServiceAccount
  name: dev-k8s
  namespace: dev-team
EOF

cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: roleB-infra-team
  namespace: infra-team
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: role-infra-team
subjects:
- kind: ServiceAccount
  name: infra-k8s
  namespace: infra-team
EOF

# 롤바인딩 확인
kubectl get rolebindings -n dev-team
kubectl get rolebindings -n infra-team
kubectl get rolebindings -n dev-team -o yaml
kubectl describe rolebindings roleB-dev-team -n dev-team
...
Role:
  Kind:  Role
  Name:  role-dev-team
Subjects:
  Kind            Name     Namespace
  ----            ----     ---------
  ServiceAccount  dev-k8s  dev-team
  • Role, RoleBinding, and subjects
  • Possible types for an element subjects list in a RoleBinding
  • Possible types for a roleRef field in a RoleBinding
  • standard user-facing ClusterRoles

 [ 실행 결과 - 한 눈에 보기 ]  * 위에 api-resource 도식과 비교하면서 보면 도움이 된다!!

ex) metric 정보 관련 권한 할당 시, 필요한 api resource group 대상

  

서비스 어카운트를 지정하여 생성한 파드에서 다시 권한 테스트

더보기
# 각각 파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
alias k1='kubectl exec -it dev-kubectl -n dev-team -- kubectl'
alias k2='kubectl exec -it infra-kubectl -n infra-team -- kubectl'

# 권한 테스트
k1 get pods 
k1 run nginx --image nginx:1.20-alpine
k1 get pods
k1 delete pods nginx
k1 get pods -n kube-system
k1 get pods -n kube-system -v=6
k1 get nodes
k1 get nodes -v=6

k2 get pods 
k2 run nginx --image nginx:1.20-alpine
k2 get pods
k2 delete pods nginx
k2 get pods -n kube-system
k2 get nodes

# (옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
yes

 

 

▶ 리소스 삭제 : kubectl delete ns dev-team infra-team

 


2. EKS 인증/인가

사용자/애플리케이션 → k8s 사용 시 ⇒ 인증은 AWS IAM, 인가는 K8S RBAC

더보기

[ 추천 영상 자료 ]

  • [Youtube] Amazon EKS 마이그레이션 요점정리(강인호) - 링크
  • EKS 환경을 더 효율적으로, 더 안전하게 - 신은수 시큐리티 스페셜리스트 솔루션즈 아키텍트, AWS :: AWS Summit Korea 2022 - 링크 PDF
  • [AWS Youtube EKS] Securing Kubernetes workloads in Amazon EKS (KUB315) - Link
  • [AWS Youtube EKS] Securing Kubernetes workloads in Amazon EKS (CON335) - Link

RBAC 관련 krew 플러그인 : [자신의 PC] or [운영서버 1]

더보기
  • 롤(Role) : apiGroups 와 resources 로 지정된 리소스에 대해 verbs 권한을 인가
  • 실행 가능한 조작(verbs) : *(모두 처리), create(생성), delete(삭제), get(조회), list(목록조회), patch(일부업데이트), update(업데이트), watch(변경감시)
# 설치
kubectl krew install access-matrix rbac-tool rbac-view rolesum whoami

# k8s 인증된 주체 확인
kubectl whoami
arn:aws:iam::9112...:user/admin

# Show an RBAC access matrix for server resources
kubectl access-matrix -h
kubectl access-matrix # Review access to cluster-scoped resources
kubectl access-matrix --namespace default # Review access to namespaced resources in 'default'

# RBAC Lookup by subject (user/group/serviceaccount) name
kubectl rbac-tool -h
kubectl rbac-tool lookup
kubectl rbac-tool lookup system:masters
  SUBJECT        | SUBJECT TYPE | SCOPE       | NAMESPACE | ROLE
+----------------+--------------+-------------+-----------+---------------+
  system:masters | Group        | ClusterRole |           | cluster-admin

kubectl rbac-tool lookup system:nodes # eks:node-bootstrapper
kubectl rbac-tool lookup system:bootstrappers # eks:node-bootstrapper
kubectl describe ClusterRole eks:node-bootstrapper

# RBAC List Policy Rules For subject (user/group/serviceaccount) name
kubectl rbac-tool policy-rules
kubectl rbac-tool policy-rules -e '^system:.*'
kubectl rbac-tool policy-rules -e '^system:authenticated'

# Generate ClusterRole with all available permissions from the target cluster
kubectl rbac-tool show

# Shows the subject for the current context with which one authenticates with the cluster
kubectl rbac-tool whoami
{Username: "arn:aws:iam::911283...:user/admin",      <<-- 과거 "kubernetes-admin"에서 변경됨
 UID:      "aws-iam-authenticator:911283.:AIDA5ILF2FJI...",
 Groups:   ["system:authenticated"],                 <<-- 과거 "system:master"는 안보임
 Extra:    {accessKeyId:  ["AKIA5ILF2FJI....."],
            arn:          ["arn:aws:iam::9112834...:user/admin"],
            canonicalArn: ["arn:aws:iam::9112834...:user/admin"],
            principalId:  ["AIDA5ILF2FJI...."],
            sessionName:  [""]}}
            sigs.k8s.io/aws-iam-authenticator/principalId: ["AIDA5IL..."]}}

# Summarize RBAC roles for subjects : ServiceAccount(default), User, Group
kubectl rolesum -h
kubectl rolesum aws-node -n kube-system    # sa
kubectl rolesum -k User system:kube-proxy  # user
kubectl rolesum -k Group system:masters    # group
kubectl rolesum -k Group system:nodes
kubectl rolesum -k Group system:authenticated
Policies:
• [CRB] */system:basic-user ⟶  [CR] */system:basic-user
  Resource                                       Name  Exclude  Verbs  G L W C U P D DC  
  selfsubjectaccessreviews.authorization.k8s.io  [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖   
  selfsubjectreviews.authentication.k8s.io       [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖   
  selfsubjectrulesreviews.authorization.k8s.io   [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖   
• [CRB] */system:discovery ⟶  [CR] */system:discovery
• [CRB] */system:public-info-viewer ⟶  [CR] */system:public-info-viewer

# [운영서버1 EC2 : 터미널1] A tool to visualize your RBAC permissions
kubectl rbac-view
INFO[0000] Getting K8s client
INFO[0000] serving RBAC View and http://localhost:8800

## 이후 해당 운영서버1 EC2 공인 IP:8800 웹 접속 : 최초 접속 후 정보 가져오는데 다시 시간 걸림 (2~3분 정도 후 화면 출력됨) 
echo -e "RBAC View Web http://$(curl -s ipinfo.io/ip):8800"

 

약어
Verbs
설명
G
Get
리소스를 조회할 수 있음 (get)
L
List
리소스를 목록으로 나열할 수 있음 (list)
W
Watch
리소스를 감시할 수 있음 (watch)
C
Create
새 리소스를 생성할 수 있음 (create)
U
Update
기존 리소스를 수정할 수 있음 (update)
P
Patch
리소스의 일부를 패치할 수 있음 (patch)
D
Delete
리소스를 삭제할 수 있음 (delete)
DC
Delete Collection
리소스의 컬렉션(여러 개)을 삭제할 수 있음 (deletecollection)

 

EKS 인증/인가 확인 : 참고로 aws-authdeprecated 예정 - EKS_Docs* , EKS_API*  

 핵심 : 인증은 AWS IAM, 인가는 K8S RBAC에서 처리

https://docs.aws.amazon.com/eks/latest/userguide/cluster-auth.html

더보기

1. kubectl 명령 aws eks get-tokenSTS토큰 요청 ⇒ 응답값 디코드(Pre-Signed URL 이며 GetCallerIdentity..) - 링크

 

임시 보안 자격 증명 요청 - AWS Identity and Access Management

AssumeRoleWithSAML에 대한 호출이 서명(암호화)되지 않았습니다. 따라서 요청이 신뢰할 수 있는 중개자를 통해 전송된 경우에만 선택적 세션 정책을 포함해야 합니다. 이러한 경우 누군가가 정책을

docs.aws.amazon.com

# sts caller id의 ARN 확인
aws sts get-caller-identity --query Arn
"arn:aws:iam::<자신의 Account ID>:user/admin"

# kubeconfig 정보 확인
cat ~/.kube/config
...
- name: admin@myeks.ap-northeast-2.eksctl.io
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - eks
      - get-token
      - --output
      - json
      - --cluster-name
      - myeks
      - --region
      - ap-northeast-2
      command: aws
      env:
      - name: AWS_STS_REGIONAL_ENDPOINTS
        value: regional
      interactiveMode: IfAvailable
      provideClusterInfo: false

# Get  a token for authentication with an Amazon EKS cluster.
# This can be used as an alternative to the aws-iam-authenticator.
aws eks get-token help

# 임시 보안 자격 증명(토큰)을 요청 : expirationTimestamp 시간경과 시 토큰 재발급됨
aws eks get-token --cluster-name $CLUSTER_NAME | jq
aws eks get-token --cluster-name $CLUSTER_NAME | jq -r '.status.token'
aws eks get-token --cluster-name $CLUSTER_NAME --debug | jq
...

 


 2. kubectl의 Client-Go 라이브러리는 Pre-Signed URL을 Bearer Token으로 EKS API Cluster Endpoint로 요청을 보냄

출처 : https://youtu.be/zIZ6_tYujts?t=231 'AWS 보안 웨비나'
# aws eks get-token --cluster-name $CLUSTER_NAME --debug | jq 출력 내용 아래 부분 확인
DEBUG - Endpoint provider result: https://sts.ap-northeast-2.amazonaws.com

Action=GetCallerIdentity&

Version=2011-06-15&

X-Amz-Algorithm=AWS4-HMAC-SHA256&

X-Amz-Credential=AKIA5ILF.../20230525/ap-northeast-2/sts/aws4_request&

X-Amz-Date=20230525T120720Z&

X-Amz-Expires=60&

X-Amz-SignedHeaders=host;x-k8s-aws-id&

X-Amz-Signature=6e09b846da702767f38c78831986cb558.....

 


3. EKS API는 Token ReviewWebhook token authenticator에 요청 ⇒ (STS GetCallerIdentity 호출) AWS IAM 해당 호출 인증 완료 후 User/Role에 대한 ARN 반환

 

참고로 Webhook token authenticator 는 aws-iam-authenticator 를 사용 - 링크 Github

https://ap-northeast-2.console.aws.amazon.com/cloudtrail/home?region=ap-northeast-2#/events?EventName=GetCallerIdentity

# tokenreviews api 리소스 확인 
kubectl api-resources | grep authentication
tokenreviews                                   authentication.k8s.io/v1               false        TokenReview

# List the fields for supported resources.
kubectl explain tokenreviews
...
DESCRIPTION:
     TokenReview attempts to authenticate a token to a known user. Note:
     TokenReview requests may be cached by the webhook token authenticator
     plugin in the kube-apiserver.

4.  [ConfigMap 방식] 이제 쿠버네티스 RBAC 인가를 처리합니다.

  • 해당 IAM User/Role 확인이 되면 k8s aws-auth configmap에서 mapping 정보를 확인하게 됩니다.
  • aws-auth 컨피그맵에 'IAM 사용자, 역할 arm, K8S 오브젝트' 로 권한 확인 후 k8s 인가 허가가 되면 최종적으로 동작 실행을 합니다.
  • 참고로 EKS를 생성한 IAM principal은 aws-auth 와 상관없이 kubernetes-admin Username으로 system:masters 그룹에 권한을 가짐

1) Possible types for an element subjects list in a RoleBinding

2) 시스템 그룹

3) 기본 유저

 

# aws-auth 컨피그맵 확인 : 현재는 IAM access entry 방식 우선 적용으로 아래 출력 내용과 다를 수 있습니다.
kubectl get cm -n kube-system aws-auth -o yaml
apiVersion: v1
kind: ConfigMap
metadata: 
  name: aws-auth
  namespace: kube-system
data: 
  mapRoles: |
    - groups:
      - system:bootstrappers
      - system:nodes
      rolearn: arn:aws:iam::91128.....:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-1OS1WSTV0YB9X
      username: system:node:{{EC2PrivateDNSName}}
#---<아래 생략(추정), ARN은 EKS를 설치한 IAM User , 여기 있었을경우 만약 실수로 삭제 시 복구가 가능했을까?---
  mapUsers: |
    - groups:
      - system:masters
      userarn: arn:aws:iam::111122223333:user/admin
      username: kubernetes-admin

# EKS 설치한 IAM User 정보 
kubectl rbac-tool whoami
{Username: "kubernetes-admin",
 UID:      "aws-iam-authenticator:9112834...:AIDA5ILF2FJIR2.....",
 Groups:   ["system:masters",
            "system:authenticated"],
...

# system:masters , system:authenticated 그룹의 정보 확인
kubectl rbac-tool lookup system:masters
kubectl rbac-tool lookup system:authenticated
kubectl rolesum -k Group system:masters
kubectl rolesum -k Group system:authenticated

# system:masters 그룹이 사용 가능한 클러스터 롤 확인 : cluster-admin
kubectl describe clusterrolebindings.rbac.authorization.k8s.io cluster-admin
Name:         cluster-admin
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
Role:
  Kind:  ClusterRole
  Name:  cluster-admin
Subjects:
  Kind   Name            Namespace
  ----   ----            ---------
  Group  system:masters

# cluster-admin 의 PolicyRule 확인 : 모든 리소스  사용 가능!
kubectl describe clusterrole cluster-admin
Name:         cluster-admin
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  *.*        []                 []              [*]
             [*]                []              [*]

# system:authenticated 그룹이 사용 가능한 클러스터 롤 확인
kubectl describe ClusterRole system:discovery
kubectl describe ClusterRole system:public-info-viewer
kubectl describe ClusterRole system:basic-user
kubectl describe ClusterRole eks:podsecuritypolicy:privileged

 

  

 

[aws-auth configmap 사용] 데브옵스 신입 사원을 위한 myeks-bastion-2

     (운영서버2: operator-host-2)에 설정 해보기

더보기

Step1. [myeks-bastion 운영서버1 or 자신의PC] testuser 사용자 생성

# testuser 사용자 생성
aws iam create-user --user-name testuser

# 사용자에게 프로그래밍 방식 액세스 권한 부여
aws iam create-access-key --user-name testuser
{
    "AccessKey": {
        "UserName": "testuser",
        "AccessKeyId": "AKIA5ILF2##",
        "Status": "Active",
        "SecretAccessKey": "TxhhwsU8##",
        "CreateDate": "2023-05-23T07:40:09+00:00"
    }
}
# testuser 사용자에 정책을 추가
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name testuser

# get-caller-identity 확인
aws sts get-caller-identity --query Arn
"arn:aws:iam::911283464785:user/admin"

kubectl whoami

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

  

Step2. [myeks-bastion-2 운영서버2] testuser 자격증명 설정 및 확인

# 아래 실습 진행을 위해, kind(k8s) 삭제
kind delete cluster --name myk8s
mv ~/.kube/config ~/.kube/config.old

# get-caller-identity 확인 >> 왜 안될까요?
aws sts get-caller-identity --query Arn

# testuser 자격증명 설정
aws configure
AWS Access Key ID [None]: AKIA5ILF2F...
AWS Secret Access Key [None]: ePpXdhA3cP....
Default region name [None]: ap-northeast-2

# get-caller-identity 확인
aws sts get-caller-identity --query Arn
"arn:aws:iam::911283464785:user/testuser"

# kubectl 시도 >> testuser도 AdministratorAccess 권한을 가지고 있는데, 실패 이유는?
kubectl get node -v6
ls ~/.kube

 

Step3. [myeks-bastion] testuser에 system:masters 그룹 부여로 EKS 관리자 수준 권한 설정

# 방안1 : eksctl 사용 >> iamidentitymapping 실행 시 aws-auth 컨피그맵 작성해줌
# Creates a mapping from IAM role or user to Kubernetes user and groups
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
eksctl create iamidentitymapping --cluster $CLUSTER_NAME --username testuser --group system:masters --arn arn:aws:iam::$ACCOUNT_ID:user/testuser

# 확인
kubectl get cm -n kube-system aws-auth -o yaml
...

# 확인 : 기존에 있는 role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-YYYYY 는 어떤 역할/동작을 하는 걸까요?
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
ARN											USERNAME				GROUPS					ACCOUNT
arn:aws:iam::911283464785:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-LHQ7DWHQQRZJ	system:node:{{EC2PrivateDNSName}}	system:bootstrappers,system:nodes	
arn:aws:iam::911283464785:user/testuser							testuser				system:masters

  

Step4. [myeks-bastion-2] testuser kubeconfig 생성 및 kubectl 사용 확인

# testuser kubeconfig 생성 >> aws eks update-kubeconfig 실행이 가능한 이유는?, 3번 설정 후 약간의 적용 시간 필요
CLUSTER_NAME=myeks
aws eks update-kubeconfig --name $CLUSTER_NAME --user-alias testuser

# 운영서버의 config와 비교해보자
cat ~/.kube/config

# kubectl 사용 확인
kubectl ns default
kubectl get node -v6

# rbac-tool 후 확인 >> 기존 계정과 비교해보자
kubectl rbac-tool whoami
{Username: "testuser",
 UID:      "aws-iam-authenticator:911283464785:AIDA5ILF2FJIV65KG6RBM",
 Groups:   ["system:masters",
            "system:authenticated"],
 Extra:    {accessKeyId:  ["AKIA5ILF2FJIZJUZSG4D"],
            arn:          ["arn:aws:iam::911283464785:user/testuser"],
            canonicalArn: ["arn:aws:iam::911283464785:user/testuser"],
...

 

Step5. [myeks-bastion] testuser 의 Group 변경(system:masters → system:authenticated)으로 RBAC 동작 확인

# 방안2 : 아래 edit로 mapUsers 내용 직접 수정 system:authenticated
kubectl edit cm -n kube-system aws-auth
...

# 확인
eksctl get iamidentitymapping --cluster $CLUSTER_NAME

 

Step6. [myeks-bastion-2] testuser kubectl 사용 확인

# 시도
kubectl get node -v6
kubectl api-resources -v5

 

Step7. [myeks-bastion]에서 testuser IAM 맵핑 삭제

# testuser IAM 맵핑 삭제
eksctl delete iamidentitymapping --cluster $CLUSTER_NAME --arn  arn:aws:iam::$ACCOUNT_ID:user/testuser

# Get IAM identity mapping(s)
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
kubectl get cm -n kube-system aws-auth -o yaml

 

Step8. [myeks-bastion-2] testuser kubectl 사용 확인

# 시도
kubectl get node -v6
kubectl api-resources -v5

 [ Check ]


[ 참고 - configmap Sample ]

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  mapRoles: |
    - groups:
      - system:bootstrappers
      - system:nodes
      rolearn: arn:aws:iam::111122223333:role/my-role
      username: system:node:{{EC2PrivateDNSName}}
    - groups:
      - eks-console-dashboard-full-access-group
      rolearn: arn:aws:iam::111122223333:role/my-console-viewer-role
      username: my-console-viewer-role
  mapUsers: |
    - groups:
      - system:masters
      userarn: arn:aws:iam::111122223333:user/admin
      username: admin
    - groups:
      - eks-console-dashboard-restricted-access-group      
      userarn: arn:aws:iam::444455556666:user/my-user
      username: my-user

 

  

 

EC2 Instance Profile(IAM Role)에 맵핑된 k8s rbac 확인 해보기

더보기
https://www.notion.so/gasidaseo/6-EKS-Security-1b150aec5edf808d8d64eb373b7b024b?pvs=4#1b150aec5edf819f8e72fdeb8d0766a9

 Step1. 노드 mapRoles 확인

# 노드에 STS ARN 정보 확인 : Role 뒤에 인스턴스 ID!
for node in $N1 $N2 $N3; do ssh ec2-user@$node aws sts get-caller-identity --query Arn; done
"arn:aws:sts::911283464785:assumed-role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-LHQ7DWHQQRZJ/i-07c9162ed08d23e6f"
"arn:aws:sts::911283464785:assumed-role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-LHQ7DWHQQRZJ/i-00d9d24c0af0d6815"
"arn:aws:sts::911283464785:assumed-role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-LHQ7DWHQQRZJ/i-031e672f89572abe8"

# aws-auth 컨피그맵 확인 >> system:nodes 와 system:bootstrappers 의 권한은 어떤게 있는지 찾아보세요!
# username 확인! 인스턴스 ID? EC2PrivateDNSName?
kubectl describe configmap -n kube-system aws-auth
...
mapRoles:
----
- groups:
  - system:nodes
  - system:bootstrappers
  rolearn: arn:aws:iam::911283464785:role/eksctl-myeks-nodegroup-ng-f6c38e4-NodeInstanceRole-1OU85W3LXHPB2
  username: system:node:{{EC2PrivateDNSName}}
...

# Get IAM identity mapping(s)
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
ARN												USERNAME		GROUPS					ACCOUNT
arn:aws:iam::911283464785:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-1OS1WSTV0YB9X	system:node:{{EC2PrivateDNSName}}	system:bootstrappers,system:nodes
...

 

Step2. awscli 파드를 추가하고, 해당 노드(EC2)의 IMDS 정보 확인

          -  AWS CLI v2 파드 생성 - 링크 , 공식이미지링크

# awscli 파드 생성
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: awscli-pod
spec:
  replicas: 2
  selector:
    matchLabels:
      app: awscli-pod
  template:
    metadata:
      labels:
        app: awscli-pod
    spec:
      containers:
      - name: awscli-pod
        image: amazon/aws-cli
        command: ["tail"]
        args: ["-f", "/dev/null"]
      terminationGracePeriodSeconds: 0
EOF

# 파드 생성 확인
kubectl get pod -owide

# 파드 이름 변수 지정
APODNAME1=$(kubectl get pod -l app=awscli-pod -o jsonpath="{.items[0].metadata.name}")
APODNAME2=$(kubectl get pod -l app=awscli-pod -o jsonpath="{.items[1].metadata.name}")
echo $APODNAME1, $APODNAME2

# awscli 파드에서 EC2 InstanceProfile(IAM Role)의 ARN 정보 확인
kubectl exec -it $APODNAME1 -- aws sts get-caller-identity --query Arn
kubectl exec -it $APODNAME2 -- aws sts get-caller-identity --query Arn

# awscli 파드에서 EC2 InstanceProfile(IAM Role)을 사용하여 AWS 서비스 정보 확인 >> 별도 IAM 자격 증명이 없는데 어떻게 가능한 것일까요?
# > 최소권한부여 필요!!! >>> 보안이 허술한 아무 컨테이너나 탈취 시, IMDS로 해당 노드의 IAM Role 사용 가능!
kubectl exec -it $APODNAME1 -- aws ec2 describe-instances --region ap-northeast-2 --output table --no-cli-pager
kubectl exec -it $APODNAME2 -- aws ec2 describe-vpcs --region ap-northeast-2 --output table --no-cli-pager
 
# EC2 메타데이터 확인 : IDMSv1은 Disable, IDMSv2 활성화 상태, IAM Role - 링크
kubectl exec -it $APODNAME1 -- bash 
-----------------------------------
아래부터는 파드에 bash shell 에서 실행
curl -s http://169.254.169.254/ -v
...

# Token 요청 
curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" ; echo
curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" ; echo

# Token을 이용한 IMDSv2 사용
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
echo $TOKEN
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/ ; echo
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/ ; echo
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/meta-data/iam/security-credentials/ ; echo

# 위에서 출력된 IAM Role을 아래 입력 후 확인
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/meta-data/iam/security-credentials/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-1DC6Y2GRDAJHK
{
  "Code" : "Success",
  "LastUpdated" : "2023-05-27T05:08:07Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "ASIA5ILF2FJI5VPIYJHP",
  "SecretAccessKey" : "rke6HXkaG4B/YLGUyAYtDnd3eMrjXlCpiB4h+9XJ",
  "Token" : "IQoJb3JpZ2luX2VjEAUaDmFwLW5vcnRoZWFzdC0yIkcwRQIhAOLQr2c2k4UwqTR2Iof2wq9Faduno1a2FX07ASHsO/rCAiAvCqQRv/JrSDZNZKNMloaBTR4s91O+RNWfSlfNluimmirLBQg+EAEaDDkxMTI4MzQ2NDc4NSIM1/RJmwkWziNhz8TEKqgFZZr1FpwHmLWNzdCdbNxtPk/YhbqbED6JzFiWJssqdRq4UniamoGrkV75oaf7o0CXQTlgK7r6f07goYA268UlqGx9XHKmeSoUt3ZTG79B1BIiSW22JVFzs4/fMpcwQLFv1lJKcGOqKehXrlq4yQ2zln4QTi/S30rp2ARiUfjgdp2+gkWKzOVWkdgoKtn3OAfdI/hBJHiz1eDPZsqqzv8eyP6sdo1xHJ6OY7xjLtTHWRaQpt6SStKTzsN88sJi9NebBXV63FJ6EkGNaC7eFo/nq9xZtGJqsu3PEuseadl8a8LJzOfNO0NP+4p8o0fMV4oeKSItZUIu88CvinvGd3bp1FWlVItDsGwjo6qOTxCg2ov6p7cAbTudEA5AwSjDlHm/BX08JN4XN7kDKtBQhHoWRbeI3suqZmtLPrSu5NCfgVu2jJpMiwOEhVV9W+fBUica345sIp94qIVVwrVbDnuLC0QDSXKxD+GRhcqdtA54QmUodqxv/bEUlRy1wVUty7Umucxl3B6MYBVSXR7PRzcf2U3vvqbJDJAT5dhFTRI1gK1YcXLzpT1T3wluMsyMPFpEWYMe/QEDAn0UwJ55pZt2pKohioiLJ3amWfNUhzoDkmXXZhAOM71e8gUVdrtAVcnl30MTDjHlIWIOBWrVMshunM5Wfmr4H4BAV+8of6xGz5AhoodWNVE+/x+XifO6h9l+Plwq24Jp8SbiCF3ZFQVe20ijsfDqK6SFAveL4vcVz7sEGLTZXLNLycgeGQmcvkb7Mmmoir/9UwNCWFWBbWXZfsEbNfSLhInw+k53FLb5I+axJPhEDSE5Iqmu+cuvoZfLy+bOailVgQN/jX6vZSL3ihhJwsP7t58urN34tKP+sjOpIBWv2bV2OnntaAqbc24tmc0wjWkaw5IwqKDGowY6sQGFB40kmsXmxihug/yKwcMK/pg5xFknPFO56P6BzErLmt1hcpNF4QBQzh/sdFi7Y/EOh9NqU/XFdFeJLp6KgaxUASLSW/k6ee+RzhbW0aSJb9GYi7tZdArcjg4YaQ6hdXdCFXiYWbNyIMs2MH8APT5jFDnwpbqSnlO2Ao64XY12cm2tMWVH+KTUyLGICHP1az7kD3/tV9glw9rJB2AOL4iA3TTuK+U2o+pHWEHRQOVh3p4=",
  "Expiration" : "2023-05-27T11:09:07Z"
}
## 출력된 정보는 AWS API를 사용할 수 있는 어느곳에서든지 Expiration 되기전까지 사용 가능

# 파드에서 나오기
exit
---

 

  • 워커 노드에 연결된 IAM 역할(정책)을 관리콘솔에서 확인해보자 !!
출처 : https://sharing-for-us.tistory.com/39

 

Step3. awscli 파드에 kubeconfig (mapRoles) 정보 생성 및 확인

# node 의 IAM Role ARN을 변수로 지정
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
NODE_ROLE=<각자 자신의 노드 Role 이름>
NODE_ROLE=eksctl-myeks-nodegroup-ng1-NodeInstanceRole-1DC6Y2GRDAJHK

# awscli 파드에서 kubeconfig 정보 생성 및 확인 >> kubeconfig 에 정보가 기존 iam user와 차이점은?
kubectl exec -it $APODNAME1 -- aws eks update-kubeconfig --name $CLUSTER_NAME --role-arn $NODE_ROLE
kubectl exec -it $APODNAME1 -- cat /root/.kube/config
...
  - --role
  - eksctl-myeks-nodegroup-ng1-NodeInstanceRole-3GQR27I04PAJ

kubectl exec -it $APODNAME2 -- aws eks update-kubeconfig --name $CLUSTER_NAME --role-arn $NODE_ROLE
kubectl exec -it $APODNAME2 -- cat /root/.kube/config

  


참고 1. EC2 metadata - Blog

참고 2. POD에서 메타데이터 접근 가능환경이 처할 수 있는 위험 - Blog 

 

 


3. EKS IRSA & Pod Identity  

☞  IRSA (I AM Roles for Service Accounts) 란?

    : Amazon EKS에서 사용할 수 있는 서비스로, 서비스 계정에 대한 IAM 역할을 관리하는 기능 이다.

 

☞  IRSA를 사용하려면 ...

 1) 클러스터에 OpenID Connect issuer URL 이 있어야 한다.

 2) 컨테이너에 AWS SDK 버전이 있어야 하며, 이 버전은 OpenID Connect 웹 ID 토큰 파일을 통해 IAM 역할을 Assume 할 수 있어야 한다.

 

[ 간단 용어정리 ]

. AWS IAM : AWS 서비스와 리소스에 대한 접근을 제어하는 서비스로, "AWS의 문지기" 역할

. OpenID Connect : OAuth 위에서 동작하는 사용자 인증을 위한 프로토콜

. EKS Pod Identity : 애플리케이션에 대한 자격 증명을 관리하는 기능

출처 : https://aws.amazon.com/ko/blogs/containers/diving-into-iam-roles-for-service-accounts/

 

[ More ... ]

더보기
  • AWS SDK는 AWS_ROLE_ARNAWS_WEB_IDENTITY_TOKEN_FILE 이름의 환경변수를 읽어들여 Web Identity 토큰으로 AssumeRoleWithWebIdentify를 호출함으로써 Assume Role을 시도하여 임시 자격 증명을 획득하고, 특정 IAM Role 역할을 사용할 수 있게 됩니다.
  • 이때 Assume Role 동작을 위한 인증은 AWS가 아닌 외부 Web IdP(EKS IdP)에 위임하여 처리합니다.

 

출처 : https://tech.devsisters.com/posts/pod-iam-role/

 

  • EKS IdP를 identity provider로 등록하고, 파드가 Web Identify 토큰을 통해 IAM 역할을 Assume 할 수 있게 Trust Relationship 설정이 필요합니다.
  • AWS CloudTrail 에 AssumeRoleWithWebIdentity - Link

 

1. Projected service account tokens are identities valid within a Kubernetes cluster. However, you could exchange for a valid token elsewhere.

https://learnk8s.io/authentication-kubernetes

 

2. The Amazon IAM service can receive such tokens and verify their identities by looking into the iss field of the JWT token.

 3. If the identity is legit, it can issue its own token.

  

4. The new token can be used to access services in Amazon Web Services.

  

 

 

  EC2 Instance Profile : 사용하기 편하지만, 최소 권한 부여 원칙에 위배하며 보안상 권고하지 않음 - 링크

더보기
출처 : https://sharing-for-us.tistory.com/40
# 설정 예시 1 : eksctl 사용 시
eksctl create cluster --name $CLUSTER_NAME ... --external-dns-access --full-ecr-access --asg-access

# 설정 예시 2 : eksctl로 yaml 파일로 노드 생성 시
cat myeks.yaml
...
managedNodeGroups:
- amiFamily: AmazonLinux2
  iam:
    withAddonPolicies:
      albIngress: false
      appMesh: false
      appMeshPreview: false
      autoScaler: true
      awsLoadBalancerController: false
      certManager: true
      cloudWatch: true
      ebs: false
      efs: false
      externalDNS: true
      fsx: false
      imageBuilder: true
      xRay: false
...

# 설정 예시 3 : 테라폼
...

 

[ 참고 자료 ]

☞ EKS IMDS 악용사례 : Link 

 

[ 실습 ]

POD 생성 및 S3 연동

더보기
# 파드1 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: eks-iam-test1
spec:
  containers:
    - name: my-aws-cli
      image: amazon/aws-cli:latest
      args: ['s3', 'ls']
  restartPolicy: Never
  automountServiceAccountToken: false
  terminationGracePeriodSeconds: 0
EOF

# 확인
kubectl get pod
kubectl describe pod

# 로그 확인
kubectl logs eks-iam-test1

# 파드1 삭제
kubectl delete pod eks-iam-test1

 

  • CloudTrail 이벤트 ListBuckets 확인 → 기록 표시까지 약간의 시간 필요 - Link
{
...
  "userIdentity": {
    "type": "AssumedRole",
    "principalId": "xxxx",
    "arn": "arn:aws:sts::111122223333:assumed-role/eksctl-eks-oidc-demo-nodegroup-ng-NodeInstanceRole-xxxx/xxxx",
    "accountId": "111122223333",
    "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
    "sessionContext": {
      "sessionIssuer": {
        "type": "Role",
        "principalId": "xxxx",
        "arn": "arn:aws:iam::xxxx:role/eksctl-eks-oidc-demo-nodegroup-ng-NodeInstanceRole-xxxx",
        "accountId": "111122223333",
        "userName": "eksctl-eks-oidc-demo-nodegroup-ng-NodeInstanceRole-xxxx"
      },
      "webIdFederationData": {},
      "attributes": {
        "creationDate": "2021-12-04T14:54:49Z",
        "mfaAuthenticated": "false"
      },
      "ec2RoleDelivery": "2.0"
    }
  },
  "eventTime": "2021-12-04T15:09:20Z",
  "eventSource": "s3.amazonaws.com",
  "eventName": "ListBuckets",
  "awsRegion": "us-east-2",
  "sourceIPAddress": "192.0.2.1",
  "userAgent": "[aws-cli/2.4.5 Python/3.8.8 Linux/5.4.156-83.273.amzn2.x86_64 docker/x86_64.amzn.2 prompt/off command/s3.ls]",
  "errorCode": "AccessDenied",
  "errorMessage": "Access Denied",
  "requestParameters": {
    "Host": "s3.us-east-2.amazonaws.com"
  },
...
}

 

 

▶ Service Account 

더보기
  • Kubernetes Pods are given an identity through a Kubernetes concept called a Kubernetes Service Account.
  • When a Service Account is created, a JWT token is automatically created as a Kubernetes Secret.
  • This Secret can then be mounted into Pods and used by that Service Account to authenticate to the Kubernetes API Server.
# 파드2 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: eks-iam-test2
spec:
  containers:
    - name: my-aws-cli
      image: amazon/aws-cli:latest
      command: ['sleep', '36000']
  restartPolicy: Never
  terminationGracePeriodSeconds: 0
EOF

# 확인
kubectl get pod
kubectl describe pod
kubectl get pod eks-iam-test2 -o yaml 
kubectl exec -it eks-iam-test2 -- ls /var/run/secrets/kubernetes.io/serviceaccount
kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token ;echo

# aws 서비스 사용 시도
kubectl exec -it eks-iam-test2 -- aws s3 ls

# 서비스 어카운트 토큰 확인
SA_TOKEN=$(kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)
echo $SA_TOKEN

# jwt 혹은 아래 JWT 웹 사이트 이용 https://jwt.io/
jwt decode $SA_TOKEN --json --iso8601
...

#헤더
{
  "alg": "RS256",
  "kid": "1a8fcaee12b3a8f191327b5e9b997487ae93baab"
}

# 페이로드 : OAuth2에서 쓰이는 aud, exp 속성 확인! > projectedServiceAccountToken 기능으로 토큰에 audience,exp 항목을 덧붙힘
## iss 속성 : EKS OpenID Connect Provider(EKS IdP) 주소 > 이 EKS IdP를 통해 쿠버네티스가 발급한 토큰이 유요한지 검증
{
  "aud": [
    "https://kubernetes.default.svc"  # 해당 주소는 k8s api의 ClusterIP 서비스 주소 도메인명, kubectl get svc kubernetes
  ],
  "exp": 1716619848,
  "iat": 1685083848,
  "iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/F6A7523462E8E6CDADEE5D41DF2E71F6",
  "jti": "ee823c34-f020-4f77-90f3-61fab4de244a",
  "kubernetes.io": {
    "namespace": "default",
    "node": {
      "name": "ip-192-168-1-70.ap-northeast-2.compute.internal",
      "uid": "f4fabf42-4a9c-43f0-8a1e-edeb2a8fbb42"
    },
    "pod": {
      "name": "eks-iam-test2",
      "uid": "10dcccc8-a16c-4fc7-9663-13c9448e107a"
    },
    "serviceaccount": {
      "name": "default",
      "uid": "acb6c60d-0c5f-4583-b83b-1b629b0bdd87"
    },
    "warnafter": 1685087455
  },
  "nbf": 1685083848,
  "sub": "system:serviceaccount:default:default"
}

# 파드2 삭제
kubectl delete pod eks-iam-test2

 

  • As you can see in the payload of this JWT, the issuer is an OIDC Provider. The audience for the token is https://kubernetes.default.svc. This is the address inside a cluster used to reach the Kubernetes API Server.
  • This compliant OIDC token now gives us a foundation to build upon to find a token that can be used to authenticate to AWS APIs. However, we will need an additional component to inject a second token for use with AWS APIs into our Kubernetes Pods. Kubernetes supports validating and mutating webhooks, and AWS has created an identity webhook that comes preinstalled in an EKS cluster. This webhook listens to create pod API calls and can inject an additional Token into our pods. This webhook can also be installed into self-managed Kubernetes clusters on AWS using this guide.

IRSA - 링크

더보기

☞ IRSA 동작 : k8s파드 → AWS 서비스 사용 시 ⇒ AWS STS/IAM ↔ IAM OIDC Identity Provider(EKS IdP) 인증/인가

출처 : https://aws.amazon.com/ko/blogs/containers/diving-into-iam-roles-for-service-accounts/

 

출처 : https://dev.to/aws-builders/auditing-aws-eks-pod-permissions-4637

 

  • For the webhook to inject a new Token into our Pod, we are going to create a new Kubernetes Service Account, annotate our Service Account with an AWS IAM role ARN, and then reference this new Kubernetes Service Account in a Kubernetes Pod. The eksctl tool can be used to automate a few steps for us, but all of these steps can also be done manually.
  • The eksctl create iamserviceaccount command creates:
    1. A Kubernetes Service Account
    2. An IAM role with the specified IAM policy
    3. A trust policy on that IAM role

 

  • Finally, it will also annotate the Kubernetes Service Account with the IAM Role Arn created.
# Create an iamserviceaccount - AWS IAM role bound to a Kubernetes service account
eksctl create iamserviceaccount \
  --name my-sa \
  --namespace default \
  --cluster $CLUSTER_NAME \
  --approve \
  --attach-policy-arn $(aws iam list-policies --query 'Policies[?PolicyName==`AmazonS3ReadOnlyAccess`].Arn' --output text)

# 확인 >> 웹 관리 콘솔에서 CloudFormation Stack >> IAM Role 확인
# aws-load-balancer-controller IRSA는 어떤 동작을 수행할 것 인지 생각해보자!
eksctl get iamserviceaccount --cluster $CLUSTER_NAME

# Inspecting the newly created Kubernetes Service Account, we can see the role we want it to assume in our pod.
kubectl get sa
kubectl describe sa my-sa
Name:                my-sa
Namespace:           default
Labels:              app.kubernetes.io/managed-by=eksctl
Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::911283464785:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-1MJUYW59O6QGH
Image pull secrets:  <none>
Mountable secrets:   <none>
Tokens:              <none>
Events:              <none>

 

  • Let’s see how this IAM role looks within the AWS Management Console. Navigate to IAM and then IAM Roles and search for the role. You will see the Annotations field when you describe your service account. ⇒ IAM Role 확인
  • Select the Trust relationships tab and select Edit trust relationship to view the policy document.
  • You can see that this policy is allowing an identity system:serviceaccount:default:my-sa to assume the role using sts:AssumeRoleWithWebIdentity action. The principal for this policy is an OIDC provider.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::911283464785:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/F6A7523462E8E6CDADEE5D41DF2E71F6"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "oidc.eks.ap-northeast-2.amazonaws.com/id/F6A7523462E8E6CDADEE5D41DF2E71F6:sub": "system:serviceaccount:default:my-sa",
                    "oidc.eks.ap-northeast-2.amazonaws.com/id/F6A7523462E8E6CDADEE5D41DF2E71F6:aud": "sts.amazonaws.com"
                }
            }
        }
    ]
}

 

  • Now let’s see what happens when we use this new Service Account within a Kubernetes Pod : 신규 파드 만들자!
# 파드3번 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: eks-iam-test3
spec:
  serviceAccountName: my-sa
  containers:
    - name: my-aws-cli
      image: amazon/aws-cli:latest
      command: ['sleep', '36000']
  restartPolicy: Never
  terminationGracePeriodSeconds: 0
EOF

# 해당 SA를 파드가 사용 시 mutatingwebhook으로 Env,Volume 추가함 : AWS IAM 역할을 Pod에 자동으로 주입
kubectl get mutatingwebhookconfigurations pod-identity-webhook -o yaml

# 파드 생성 yaml에 없던 내용이 추가됨!!!!!
# Pod Identity Webhook은 mutating webhook을 통해 아래 Env 내용과 1개의 볼륨을 추가함
kubectl get pod eks-iam-test3
kubectl get pod eks-iam-test3 -o yaml
...
    volumeMounts: 
    - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
      name: aws-iam-token
      readOnly: true
  ...
  volumes: 
  - name: aws-iam-token
    projected: 
      sources: 
      - serviceAccountToken: 
          audience: sts.amazonaws.com
          expirationSeconds: 86400
          path: token
...

kubectl exec -it eks-iam-test3 -- ls /var/run/secrets/eks.amazonaws.com/serviceaccount
token

kubectl exec -it eks-iam-test3 -- cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token ; echo
...

kubectl describe pod eks-iam-test3
...
Environment:
      AWS_STS_REGIONAL_ENDPOINTS:   regional
      AWS_DEFAULT_REGION:           ap-northeast-2
      AWS_REGION:                   ap-northeast-2
      AWS_ROLE_ARN:                 arn:aws:iam::911283464785:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-GE2DZKJYWCEN
      AWS_WEB_IDENTITY_TOKEN_FILE:  /var/run/secrets/eks.amazonaws.com/serviceaccount/token
    Mounts:
      /var/run/secrets/eks.amazonaws.com/serviceaccount from aws-iam-token (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-69rh8 (ro)
...
Volumes:
  aws-iam-token:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  86400
  kube-api-access-sn467:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
...

# 파드에서 aws cli 사용 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
kubectl exec -it eks-iam-test3 -- aws sts get-caller-identity --query Arn
"arn:aws:sts::911283464785:assumed-role/eksctl-myeks-addon-iamserviceaccount-default-Role1-GE2DZKJYWCEN/botocore-session-1685179271"

# 되는 것고 안되는 것은 왜그런가?
kubectl exec -it eks-iam-test3 -- aws s3 ls
kubectl exec -it eks-iam-test3 -- aws ec2 describe-instances --region ap-northeast-2
kubectl exec -it eks-iam-test3 -- aws ec2 describe-vpcs --region ap-northeast-2

 

  • AWS CloudTrail 이벤트 중 AssumeRoleWithWebIdentity - Link
  • If we inspect the Pod using Kubectl and jq, we can see there are now two volumes mounted into our Pod. The second one has been mounted via that mutating webhook. The aws-iam-token is still being generated by the Kubernetes API Server, but with a new OIDC JWT audience.
# 파드에 볼륨 마운트 2개 확인
kubectl get pod eks-iam-test3 -o json | jq -r '.spec.containers | .[].volumeMounts'
[
  {
    "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
    "name": "kube-api-access-sn467",
    "readOnly": true
  },
  {
    "mountPath": "/var/run/secrets/eks.amazonaws.com/serviceaccount",
    "name": "aws-iam-token",
    "readOnly": true
  }
]

# aws-iam-token 볼륨 정보 확인 : JWT 토큰이 담겨져있고, exp, aud 속성이 추가되어 있음
kubectl get pod eks-iam-test3 -o json | jq -r '.spec.volumes[] | select(.name=="aws-iam-token")'
{
  "name": "aws-iam-token",
  "projected": {
    "defaultMode": 420,
    "sources": [
      {
        "serviceAccountToken": {
          "audience": "sts.amazonaws.com",
          "expirationSeconds": 86400,
          "path": "token"
        }
      }
    ]
  }
}

#
kubectl get MutatingWebhookConfiguration
NAME                            WEBHOOKS   AGE
pod-identity-webhook            1          147m
vpc-resource-mutating-webhook   1          147m

# pod-identity-webhook 확인
kubectl describe MutatingWebhookConfiguration pod-identity-webhook 
kubectl get MutatingWebhookConfiguration pod-identity-webhook -o yaml
...
 name: iam-for-pods.amazonaws.com
# iam-for-pods.amazonaws.com은 AWS EKS에서 Pod Identity Webhook의 Mutating Webhook으로, 다음과 같은 작업을 수행합니다:
# Pod 생성 시 호출되어 ServiceAccount의 IAM 역할 정보를 확인.
# Pod에 환경 변수(AWS_ROLE_ARN, AWS_WEB_IDENTITY_TOKEN_FILE)와 토큰 볼륨을 주입.
# Pod이 AWS 리소스에 안전하고 세밀하게 접근할 수 있도록 인증 메커니즘 제공.
  • If we exec into the running Pod and inspect this token, we can see that it looks slightly different from the previous SA Token.
  • You can see that the intended audience for this token is now sts.amazonaws.com, the issuer who has created and signed this token is still our OIDC provider, and finally, the expiration of the token is much shorter at 24 hours. We can modify the expiration duration for the service account using eks.amazonaws.com/token-expiration annotation in our Pod definition or Service Account definition.
  • The mutating webhook does more than just mount an additional token into the Pod. The mutating webhook also injects environment variables.

https://jwt.io/

# AWS_WEB_IDENTITY_TOKEN_FILE 확인
IAM_TOKEN=$(kubectl exec -it eks-iam-test3 -- cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token)
echo $IAM_TOKEN

# JWT 웹 확인 
{
  "aud": [
    "sts.amazonaws.com"
  ],
  "exp": 1685175662,
  "iat": 1685089262,
  "iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/F6A7523462E8E6CDADEE5D41DF2E71F6",
  "kubernetes.io": {
    "namespace": "default",
    "pod": {
      "name": "eks-iam-test3",
      "uid": "73f66936-4d66-477a-b32b-853f7a1c22d9"
    },
    "serviceaccount": {
      "name": "my-sa",
      "uid": "3b31aa85-2718-45ed-8c1c-75ed012c1a68"
    }
  },
  "nbf": 1685089262,
  "sub": "system:serviceaccount:default:my-sa"
}

# env 변수 확인
kubectl get pod eks-iam-test3 -o json | jq -r '.spec.containers | .[].env'
[
  {
    "name": "AWS_STS_REGIONAL_ENDPOINTS",
    "value": "regional"
  },
  {
    "name": "AWS_DEFAULT_REGION",
    "value": "ap-northeast-2"
  },
  {
    "name": "AWS_REGION",
    "value": "ap-northeast-2"
  },
  {
    "name": "AWS_ROLE_ARN",
    "value": "arn:aws:iam::911283464785:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-1MJUYW59O6QGH"
  },
  {
    "name": "AWS_WEB_IDENTITY_TOKEN_FILE",
    "value": "/var/run/secrets/eks.amazonaws.com/serviceaccount/token"
  }
]
  • Now that our workload has a token it can use to attempt to authenticate with IAM, the next part is getting AWS IAM to trust these tokens. AWS IAM supports federated identities using OIDC identity providers. This feature allows IAM to authenticate AWS API calls with supported identity providers after receiving a valid OIDC JWT. This token can then be passed to AWS STS AssumeRoleWithWebIdentity API operation to get temporary IAM credentials.
  • The OIDC JWT token we have in our Kubernetes workload is cryptographically signed, and IAM should trust and validate these tokens before the AWS STS AssumeRoleWithWebIdentity API operation can send the temporary credentials. As part of the Service Account Issuer Discovery feature of Kubernetes, EKS is hosting a public OpenID provider configuration document (Discovery endpoint) and the public keys to validate the token signature (JSON Web Key SetsJWKS) at https://OIDC_PROVIDER_URL/.well-known/openid-configuration.
# Let’s take a look at this endpoint. We can use the aws eks describe-cluster command to get the OIDC Provider URL.
IDP=$(aws eks describe-cluster --name myeks --query cluster.identity.oidc.issuer --output text)

# Reach the Discovery Endpoint
curl -s $IDP/.well-known/openid-configuration | jq -r '.'

# In the above output, you can see the jwks (JSON Web Key set) field, which contains the set of keys containing the public keys used to verify JWT (JSON Web Token). 
# Refer to the documentation to get details about the JWKS properties.
curl -s $IDP/keys | jq -r '.'

 

  • AWS CloudTrail 이벤트 중 AssumeRoleWithWebIdentity - Link

 

  • IRSA를 가장 취약하게 사용하는 방법 : 정보 탈취 시 키/토큰 발급 약용 가능 - 링크
  • AWS는 JWT 토큰의 유효성만 확인 하지만 토큰 파일과 서비스 계정에 지정된 실제 역할 간의 일관성을 보장하지는 않음 → Condition 잘못 설정 시, 토큰과 역할 ARN만 있다면 동일 토큰으로 다른 역할을 맡을 수 있음

▶ 자원 정리 

# 실습 확인 후 파드 삭제 및 IRSA 제거
kubectl delete pod eks-iam-test3
eksctl delete iamserviceaccount --cluster $CLUSTER_NAME --name my-sa --namespace default
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
kubectl get sa

 


[ 실습 결과 - 한 눈에 보기 ]

[ 신기능 ] EKS Pod identity

더보기
출처 : https://www.youtube.com/watch?v=yuXF-NXaelI
https://github.com/awskrug/security-group/blob/main/files/AWSKRUG_2024_02_EKS_ROLE_MANAGEMENT.pdf

 


  • Amazon EKS Pod Identity: a new way for applications on EKS to obtain IAM credentials - Link
  • Amazon EKS Pod Identity simplifies IAM permissions for applications on Amazon EKS clusters - Link
  • [EKS Workshop] EKS Pod Identity : 오픈소스 Agent, Add-on 설치 지원 - Link
출처 : https://youtu.be/iyMcOpXRVWk?si=fFiMV9c7E0pg8Img&t=1409
https://aws.amazon.com/blogs/containers/amazon-eks-pod-identity-a-new-way-for-applications-on-eks-to-obtain-iam-credentials/

 

https://github.com/awskrug/security-group/blob/main/files/AWSKRUG_2024_02_EKS_ROLE_MANAGEMENT.pdf

 

 


 

[ 실습 ]

더보기

Step1. eks-pod-identity-agent 설치

#
ADDON=eks-pod-identity-agent
aws eks describe-addon-versions \
    --addon-name $ADDON \
    --kubernetes-version 1.31 \
    --query "addons[].addonVersions[].[addonVersion, compatibilities[].defaultVersion]" \
    --output text
v1.2.0-eksbuild.1
True
v1.1.0-eksbuild.1
False
v1.0.0-eksbuild.1
False

# 모니터링
watch -d kubectl get pod -A

# 설치
aws eks create-addon --cluster-name $CLUSTER_NAME --addon-name eks-pod-identity-agent
혹은
eksctl create addon --cluster $CLUSTER_NAME --name eks-pod-identity-agent --version 1.3.5

# 확인
eksctl get addon --cluster $CLUSTER_NAME
kubectl -n kube-system get daemonset eks-pod-identity-agent
kubectl -n kube-system get pods -l app.kubernetes.io/name=eks-pod-identity-agent
kubectl get ds -n kube-system eks-pod-identity-agent -o yaml
...
      containers: 
      - args: 
        - --port
        - "80"
        - --cluster-name
        - myeks
        - --probe-port
        - "2703"
        command: 
        - /go-runner
        - /eks-pod-identity-agent
        - server
      ....
      ports: 
        - containerPort: 80
          name: proxy
          protocol: TCP
        - containerPort: 2703
          name: probes-port
          protocol: TCP
      ...
        securityContext: 
          capabilities: 
            add: 
            - CAP_NET_BIND_SERVICE
      ...
      hostNetwork: true
...

# 네트워크 정보 확인
## EKS Pod Identity Agent uses the hostNetwork of the node and it uses port 80 and port 2703 on a link-local address on the node. 
## This address is 169.254.170.23 for IPv4 and [fd00:ec2::23] for IPv6 clusters.
for node in $N1 $N2 $N3; do ssh ec2-user@$node sudo ss -tnlp | grep eks-pod-identit; echo "-----";done
for node in $N1 $N2 $N3; do ssh ec2-user@$node sudo ip -c route; done
for node in $N1 $N2 $N3; do ssh ec2-user@$node sudo ip -c -br -4 addr; done
for node in $N1 $N2 $N3; do ssh ec2-user@$node sudo ip -c addr; done

 

(참고) 노드 EC2 Profile에 2023년 기능 출시 이후 Policy에 업데이트됨 : 워커노드 IAM Role 정보 확인

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "WorkerNodePermissions",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeInstanceTypes",
                "ec2:DescribeRouteTables",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVolumes",
                "ec2:DescribeVolumesModifications",
                "ec2:DescribeVpcs",
                "eks:DescribeCluster",
                "eks-auth:AssumeRoleForPodIdentity"
            ],
            "Resource": "*"
        }
    ]
}

 

  • podidentityassociation 설정
# 
eksctl create podidentityassociation \
--cluster $CLUSTER_NAME \
--namespace default \
--service-account-name s3-sa \
--role-name s3-eks-pod-identity-role \
--permission-policy-arns arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
--region ap-northeast-2

# 확인
kubectl get sa
eksctl get podidentityassociation --cluster $CLUSTER_NAME
ASSOCIATION ARN											                                                      NAMESPACE	SERVICE ACCOUNT NAME	IAM ROLE ARN
arn:aws:eks:ap-northeast-2:911283464785:podidentityassociation/myeks/a-blaanudo8dc1dbddw	default		s3-sa			            arn:aws:iam::911283464785:role/s3-eks-pod-identity-role

aws eks list-pod-identity-associations --cluster-name $CLUSTER_NAME | jq
{
  "associations": [
    {
      "clusterName": "myeks",
      "namespace": "default",
      "serviceAccount": "s3-sa",
      "associationArn": "arn:aws:eks:ap-northeast-2:911283464785:podidentityassociation/myeks/a-pm07a3bg79bqa3p24",
      "associationId": "a-pm07a3bg79bqa3p24"
    }
  ]
}

# ABAC 지원을 위해 sts:Tagsession 추가
aws iam get-role --query 'Role.AssumeRolePolicyDocument' --role-name s3-eks-pod-identity-role | jq .
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "pods.eks.amazonaws.com"
      },
      "Action": [
        "sts:AssumeRole",
        "sts:TagSession"
      ]
    }
  ]
}

 

  • 테스트용 파드 생성 및 확인 : AssumeRoleForPodIdentity - Link
출처 : https://youtu.be/iyMcOpXRVWk?si=J4q7vOe-W4UhQ1wu&t=2501

Step2. (심화 참고) 일반적인 메타데이터 서비스 처리 Flow

  • AWS CloudTrail 중 AssumeRoleForPodIdentity - Link
# 서비스어카운트, 파드 생성
kubectl create sa s3-sa

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: eks-pod-identity
spec:
  serviceAccountName: s3-sa
  containers:
    - name: my-aws-cli
      image: amazon/aws-cli:latest
      command: ['sleep', '36000']
  restartPolicy: Never
  terminationGracePeriodSeconds: 0
EOF

#
kubectl get pod eks-pod-identity -o yaml | kubectl neat
kubectl exec -it eks-pod-identity -- aws sts get-caller-identity --query Arn
kubectl exec -it eks-pod-identity -- aws s3 ls
kubectl exec -it eks-pod-identity -- env | grep AWS
AWS_STS_REGIONAL_ENDPOINTS=regional
AWS_DEFAULT_REGION=ap-northeast-2
AWS_REGION=ap-northeast-2
AWS_CONTAINER_CREDENTIALS_FULL_URI=http://169.254.170.23/v1/credentials
AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE=/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token

# 토큰 정보 확인
kubectl exec -it eks-pod-identity -- ls /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/
kubectl exec -it eks-pod-identity -- cat /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token

Step3. 실습 리소스 정리

eksctl delete podidentityassociation --cluster $CLUSTER_NAME --namespace default --service-account-name s3-sa
kubectl delete pod eks-pod-identity
kubectl delete sa s3-sa

 

[ 도전과제 ] IAM Session tags → Support for session tags 실습 도전해보세요 - Link Blog

 

더보기
https://youtu.be/iyMcOpXRVWk?si=dGAnJ6x2qCc6YaQY&t=1680

 

[ IRSA vs EKS Pod Identity ]

 
  IRSA EKS Pod Identity
Role extensibility You have to update the IAM role’s trust policy with the new EKS cluster OIDC provider endpoint each time you want to use the role in a new cluster. You have to setup the role one time, to establish trust with the newly introduced EKS service principal “pods.eks.amazonaws.com”. After this one-time step, you don’t need to update the role’s trust policy each time it is used in a new cluster.
Account scalability EKS cluster has an OpenID Connect (OIDC) issuer URL associated with it. To use IRSA, a unique OpenID connect provider needs to be created in IAM for each EKS cluster. IAM OIDC provider has a default global limit of 100 per AWS account. Keep this limit in consideration as you grow the number of EKS clusters per account. EKS Pod Identity doesn’t require users to setup IAM OIDC provider, so this limit doesn’t apply.
Role scalability In IRSA, you define the trust relationship between an IAM role and service account in the role’s trust policy. By default, the length of trust policy size is 2048. This means that you can typically define four trust relationships in a single policy. While you can get the trust policy length limit increased, you are typically limited to a maximum of eight trust relationships within a single policy. EKS Pod Identity doesn’t require users to define trust relationship between IAM role and service account in IAM trust policy, so this limit doesn’t apply.
Role reusability IAM role session tags are not supported. IAM credentials supplied by EKS Pod Identity include support for role session tags. Role session tags enable administrators to author a single IAM role that can be used with multiple service accounts, with different effective permissions, by allowing access to AWS resources based on tags attached to them.
Cluster readiness IAM roles used in IRSA need to wait for the cluster to be in a “Ready” state, to get the cluster’s OpenID Connect Provider URL to complete the IAM role trust policy configuration IAM roles used in Pod identity can be created ahead of time.
Environments supported IRSA can be used in EKS, EKS-A, ROSA, self-managed Kubernetes clusters on Amazon EC2 EKS Pod Identity is purpose built for EKS.
Supported EKS versions All supported EKS versions EKS version 1.24 and above. See EKS user guide for details.
Cross account access Cross account here refers to the scenario where your EKS cluster is in one AWS account and the AWS resources that are being accessed by your applications is in another AWS account. In IRSA, you can configure cross account IAM permissions either by creating an IAM identity provider in the account your AWS resources live or by using chained AssumeRole operation. See EKS user guide on IRSA Cross-account IAM permissions for details. EKS Pod Identity supports cross account access through resource policies and chained AssumeRole operation. See the previous section “How to perform cross account access with EKS Pod Identity” for details.
Mapping inventory You can find the mapping of IAM roles to service accounts by parsing individual IAM role’s trust policy or by inspecting the annotations added to service accounts. EKS Pod Identity offers a new ListPodIdentityAssociations API to centrally see the mapping of roles to service accounts.
  • 고려사항
    • SDK 최신 버전 확인 - Link
    • 워커노드에 IAM Policy 확인 : Action(eks-auth:AssumeRoleForPodIdentity)
    • 보안 솔루션으로 링크 로컬 주소 사용 가능 여부 확인, 혹은 이미 사용 중인 주소인지, iptables 로 막혀있는지 확인
    • How to migrate from IRSA to EKS Pod Identity : 기존 IRSA → PodIdentity 마이그레이션 - Link

 

 


[ 실습 후, 자원 삭제 ]

더보기

1. [운영서버 EC2]에서 원클릭 삭제 진행 : Karpenter 실습 환경 준비를 위해서 현재 EKS 실습 환경 전부 삭제

# eksctl delete cluster --name $CLUSTER_NAME && aws cloudformation delete-stack --stack-name $CLUSTER_NAME
nohup sh -c "eksctl delete cluster --name $CLUSTER_NAME && aws cloudformation delete-stack --stack-name $CLUSTER_NAME" > /root/delete.log 2>&1 &

# (옵션) 삭제 과정 확인
tail -f delete.log

 

2. testuser IAM User는 AWS 웹 관리콘솔에서 삭제


[ 마무리 ]

이번 과정을 통해 보안의 중요성에 대해 다시 한 번 깊게 생각해 보게 된 것 같다. EKS 환경이 스케일링의 자동화 등 관리의 편의성을 제공하는 반면, 보안에 대한 지식과 설정이 부족하다면 그에 따르는 보안적 Risk 가 크다는 것을 알게 되었다. 방대한 양을 쫓아가기가 힘들지만, 요소 요소 중요한 포인트를 잡아서 따라잡고 또 실무에 적용점들에 대해 고민해 보게 되는 시간이었던 것 같다.


[ 참고 링크 모음 ]

 

1. 필수 시청 영상 - 생활코딩

 - 암호학 기초 수업 - Link , 암호 테스트 온라인 사이트 - Link

더보기
  1. 수업소개 https://www.youtube.com/watch?v=NBrcJSkgYmA
  2. 단방향 암호화 방법 https://www.youtube.com/watch?v=qP1H2dwnAVA
  3. 양방향 암호화 - 대칭키 방식 https://www.youtube.com/watch?v=0nPDwJPxOVQ
  4. 양방향 암호화 - 비대칭키(공개키 방식) - 기밀성을 위해서 사용하기 https://www.youtube.com/watch?v=MR4sCU82tgo
  5. 양방향 암호화 - 비대칭키(공개키 방식) - 전자 서명하는 방법 https://www.youtube.com/watch?v=O7SiDuTCysM
  6. 수업을 마치며 https://www.youtube.com/watch?v=AJjOJdJjLzg

[ 심화 - 추천 영상 * ]

더보기

1. [RSA 2024] Kubernetes Security: Attacking and Defending Modern Infrastructure

☞  https://www.youtube.com/watch?v=iCzUv6-9zrI

 

2. [RSA 2024] Containers Everywhere: Advanced Threat Actors Heavily Leverage Them

☞  https://www.youtube.com/watch?v=F5TdkCxrKbg

 

3. Third-party App으로 인해 위협받는 Kubernetes - 안서현

https://www.youtube.com/watch?v=AdJBOKwOc7w 

 

4. AWS re:Invent 2023 - Securing Kubernetes workloads in Amazon EKS (CON335) - Link

☞  https://www.youtube.com/watch?v=iyMcOpXRVWk

 

5. [RSA Conference] 3사 퍼블릭 클라우드 인증/인가와 IMDS류와 OIDC(IRSA 류)에 대한 동작 및 취약점 소개

☞  https://youtu.be/1rmg2QfLJtY

 

6. [RSA Conference] 쿠버네티스 환경 탐색 및 침투와 알려진 취약점 공격 후 공격 대응을 위한 발견 등 방안 소개

☞  https://youtu.be/N7myhEg00b4

 

7. [RSA Conference] Container Escape: All You Need Is Cap (Capabilities)

☞  https://youtu.be/iALZWtWwRyc

 

8. [RSA Conference] Destroying Long-Lived Cloud Credentials with Workload Identity Federation

☞  https://youtu.be/Loj4eOIu-zo

 

9. 생활코딩 : JWT

https://www.youtube.com/watch?v=36lpDzQzVXs

  

10. [추천 영상] [코맹탈출] RSA 작동원리 - Youtube , [NHN] 웹 서버 인증서 - Youtube

 

2. New References

더보기

[ learnk8s* ]

  1. User and workload identities in Kubernetes - Link
  2. Limiting access to Kubernetes resources with RBAC - Link
  3. Implementing a custom Kubernetes authentication method - Link
  4. Authentication between microservices using Kubernetes identities - Link

[ AWS Korea Blog EKS 정보 ]

  1. 리전 AWS STS 엔드포인트 사용하기 - Link
  2. 간소화된 Amazon EKS 액세스 관리 제어 톺아보기 - Link
  3. Amazon EKS 환경에서 Pod Security Standard 구현하기 - 링크
  4. Amazon Detective – 보안 조사를 위해 EKS에서 Kubernetes 워크로드 지원 - 링크

[ AWS Blog EKS 정보 ]

a. Container - 링크

  • Automating AL2023 custom hardened AMI updates for Amazon EKS managed nodes - Link
  • Using OPA to validate Amazon EKS Blueprint Templates - Link
  • Protecting your Amazon EKS web apps with AWS WAF - Link
  • Amazon EKS Pod Identity: a new way for applications on EKS to obtain IAM credentials - Link
  • Measure cluster performance impact of Amazon GuardDuty EKS Agent - Link
  • Managing access to Amazon Elastic Kubernetes Service clusters with X.509 certificates - 링크
  • Managing Pod Security on Amazon EKS with Kyverno - 링크
  • Implementing Pod Security Standards in Amazon EKS - 링크
  • Building Amazon Linux 2 CIS Benchmark AMIs for Amazon EKS - 링크
  • Implementing Pod Security Standards in Amazon EKS - 링크
  • Secure Bottlerocket deployments on Amazon EKS with KubeArmor - 링크
  • Diving into IAM Roles for Service Accounts - 링크

b. AWS News Blog - 링크

  • Amazon EKS Pod Identity simplifies IAM permissions for applications on Amazon EKS clusters - Link
  • Amazon GuardDuty Now Supports Amazon EKS Runtime Monitoring - 링크
  • Amazon Detective Supports Kubernetes Workloads on Amazon EKS for Security Investigations - 링크

c. AWS Open Source Blog - 링크

  • Achieving Zero Trust Security on Amazon EKS with Istio - Link
  • Configure Keycloak on Amazon Elastic Kubernetes Service (Amazon EKS) using Terraform - Link
  • Supply Chain Security on Amazon Elastic Kubernetes Service (Amazon EKS) using AWS Key Management Service (AWS KMS), Kyverno, and Cosign - 링크
  • Authenticating with Amazon Managed Grafana Using Open Source Keycloak on Amazon EKS - 링크

d. AWS Security - 링크

  • Connect your on-premises Kubernetes cluster to AWS APIs using IAM Roles Anywhere - Link
  • Announcing ASCP integration with Pod Identity: Enhanced security for secrets management in Amazon EKS - Link
  • Making sense of secrets management on Amazon EKS for regulated institutions - Link
  • How to create a pipeline for hardening Amazon EKS nodes and automate updates - Link
  • How to use AWS Secrets Manager and ABAC for enhanced secrets management in Amazon EKS - Link
  • How to investigate and take action on security issues in Amazon EKS clusters with Amazon Detective – Part 2 - Link
  • How to detect security issues in Amazon EKS clusters using Amazon GuardDuty – Part 1 - Link
  • Use AWS Network Firewall to filter outbound HTTPS traffic from applications hosted on Amazon EKS and collect hostnames provided by SNI - Link
  • How to use new Amazon GuardDuty EKS Protection findings - Link
  • Access token security for microservice APIs on Amazon EKS - Link
  • TLS-enabled Kubernetes clusters with ACM Private CA and Amazon EKS - Link

[ AWS Youtube EKS 정보 ]

  • Securing Kubernetes workloads in Amazon EKS (KUB315) - Link
  • Securing Kubernetes workloads in Amazon EKS (CON335) - Link

[ AWS Workshop & Best Practices EKS 정보]

  • EKS Workshop Security - Link
  • EKS Advanced Workshop 중 보안 관련 - 링크
  • [한글/whchoi98] EKS Hands On LAB 중 보안 관련 - Link
  • Amazon EKS Security Immersion Workshop - Link
  • EKS Best Practices Guides 중 Security - Link

◎ External Secrets와 AWS Secrets Manager, SSM Parameter Store 연동하기 - Blog


  

 

[ 도전과제 ]

더보기

도전과제1.  K8S 모든 과정을 직접 설치해보기 ‘K8S The Hard Way’ - Github , KrBlog (CA 인증서*)

도전과제2.  cert-manager 는 TLS 인증서 발급 자동화 이외에도 사용자 인증서 발급에도 활용 가능하니, 설치 후 사용! - https://cert-manager.io/

 

 

 

'AEWS' 카테고리의 다른 글

AEWS 8주차 - K8S CI/CD  (0) 2025.03.25
AEWS 7주차 - EKS Mode/Nodes (Fargate, Auto-mode)  (0) 2025.03.17
AEWS 5주차 - EKS Autoscaling  (0) 2025.03.08
AEWS 4주차 - EKS Observability  (0) 2025.02.24
AEWS 3주차 - EKS Storage, Managed Node Groups  (1) 2025.02.17