상세 컨텐츠

본문 제목

6주차 - EKS Security

K8S - EKS

by 존자르징어 2025. 3. 15. 23:50

본문

본 글은 CloudNet@ 팀 가시다님의 'AWS EKS Hands-on' 스터디를 내용을 기반으로 정리하였습니다.
Kubernetes(이하 k8s)에 대한 지식(아키텍처, 사용법 등)이 있다고 가정하고 작성했습니다.
잘못된 정보가 있으면 언제든지 알려주시기 바랍니다.

목차

0. 실습 환경 배포 & 소개

1. K8S 인증/인가

2. EKS 인증/인가

3. EKS IRSA & Pod Identity

4. OWASP Kubernetes Top Ten

5. Kyverno

 

0. 실습 환경 배포 & 소개

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

   - Bastion 2대 : 운영서버1, 운영서버2

      . 각 운영서버는 2명의 직원이 나눠서 사용한다고 가정

      . 운영서버2 : kind를 설치하여 인증서 등 테스트

# 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에서 EKS 설치 확인 (스택 생성 시작 후 20분 뒤 접속)

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

#
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

 

 - 노드 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 설치 

# 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) 설치 확인 

 

- 배포 후 실습 편의를 위한 설정

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)

echo $CLUSTER_NAME $VPCID $PubSubnet1 $PubSubnet2 $PubSubnet3
echo $N1 $N2 $N3 $MyDomain $MyDnzHostedZoneId

 

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

# 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

# 확인
# 설치된 파드 정보 확인
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

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

 

 

> 기초이론

- 정보 보안 3요소

    . 기밀성 : 권한있는 사용자만 접근 (암호화, 접근제어)

    . 무결성 : 허가되지 않은 방식의 변경/손상 방지 (해시, 전자 서명)

    . 가용성 : 언제든 접근과 사용 가능 (백업, 장애, 침해 대응)

 

- 액세스 제어

    . 인증 : 신원 확인 (ID/Password, 생체 인식, 토큰 등)

    . 인가 : 권한 부여 (RBAC, PBAC 등)

    . 감사 : 활동 기록 및 추적 (감사 로그 등)

 

- 암/복호화

    . 암호화 : 평문을 제 3자가 해동할 수 없는 암호문으로 변환

    . 복호화 : 암호문으로부터 평문으로 복원

    . 암호 알고리즘 : 암/복호화에 사용하는 알고리즘

    . 키 : 암/복호화의 핵심 매개

 

- 키 교환 방식 [암호화 실습 : https://emn178.github.io/online-tools/rsa/sign/]

    . 공유 비밀키 암호화 방식 : 암호화 복호화에 동일한 비밀키 사용 (안전한 키 교환 필요)

      . DES, 3DES, RC4/5

      . 보내는 사람과 받는 사람 신원 확인 필요 : 서명

        - RSA 디지털 서명, DSA 디지털 서명

      . 중간에 데이터를 가로챈 뒤 변조 가능 : 해시

        - 해시 함수를 사용하여 메시지에 대한 고정 길이의 해시 코드 값 생성하여 메시지에 부착 전송

        - 일정한 크기

        - 메시지가 다르면 해시도 다름

        - hash collison 주의 : 강한 충돌 내성 필요

        - 이방향성 : 해시 역연산 불가

        - MD5, SHA

MD5

    . 공개키 암호화 방식 : 암호화 복호화에 다른 키 사용, 공개키, 비밀키(개인키) 두 가지 사용

      . 처리속도가 느림 : 비밀키를 안전하게 교환하기 위해 공개키 방식을 사용하교 키 교환 후에는 대칭키(공유 비밀키) 사용


      . RSA 따라해보기 (https://emn178.github.io/online-tools/rsa/key-generator/)

        > Private Key 와 Public Key 메모

-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIeNrBKPKNzuG3Fc
1kV4hXuToXSVRWu6zpDZ/O3r4c4Lyv4lrb/3I0a4pPfPN0MiASbBXx/s8hUcMqWg
DS3ZwH8QsljiawNEF4OYIGnTgJmBuWdR5e+twmw6IAoNAY4kyU1x6BxJF3uDFm9K
a1Rc+Guk489lDfXtFBaoCHowJP4NAgMBAAECgYADyHNl7TLhv49qgYHFXJC1GzCl
VUkjsYn0RvElHrElk/StVRXdRqNoZNzNwa20JO3NTBZAiNdUuX28W5QilHInzy5+
2ub/a+S//pX96qtK1nz4i9N4v/h+KH5ijUuSso/JyGGlQyVCUl12g5eOBqIuauGI
qn8QLLpz6AlX4Ek/4QJBANPskiqSSIUPijbcaYbVXa4+rnPeuYCwXtx42m3YlQyQ
nIFqFOwfRus/FuPTIrFBu3JirsjcqGkGWIInzL8YDfkCQQCjvumnfbSaVfOYInqJ
ziePwxSTANUd64sO6l0n4/hgPI/iJ9vc05vNMuaZiG5j4aaruQmmumBwylRnfMDP
F0W1AkEAiPl0M+3ez5oOtIzb7BlGdpPu/9dqQMI+XfQDAlKla7ygW4ksQr2oge6C
JfjWiIk61aDw5cSxWUiPtnhw/uZWSQJAZbmS2pTDgCXpgRfaXIYQGcWtoG2h+EZ+
SzPZz5BWmyLEmFD+y79CSUZX8AXL3o0ux/vaPRQIGcn4iZn9BiqFCQJBALRTBX+Q
FbqWODH/64Yg1SGUKekm64I96MkBUB+WOszS8W+mGvlBAMBIL35QsyN5BbcF/oD2
h02BYGnTaRjVbrk=
-----END PRIVATE KEY-----

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHjawSjyjc7htxXNZFeIV7k6F0
lUVrus6Q2fzt6+HOC8r+Ja2/9yNGuKT3zzdDIgEmwV8f7PIVHDKloA0t2cB/ELJY
4msDRBeDmCBp04CZgblnUeXvrcJsOiAKDQGOJMlNcegcSRd7gxZvSmtUXPhrpOPP
ZQ317RQWqAh6MCT+DQIDAQAB
-----END PUBLIC KEY-----

 

      > Encryption : public key(붙여넣기), Input(mypass!) 출력 메모

       

       > Decription : private key(위 메모값 붙여넣기) , Input(바로 위 암호 출력 값) → 출력 확인

 

    . 키 분배 방식 : 키를 교환 방법

      . DH (Deffie-Hellman) : 통신 당사자 간 비밀키 교환

      . RSA 공개키 : 공개키 암호화를 통해 키를 교환

      . KDC (Key Distribution Center) : 중앙 서버를 통해 키를 분배

 

- 메시지 인증 : 무결성 제공

    1. 해시 : 고정된 길이의 값으로 변환

    2. Message Authentication Code(MAC) - 메시지 무결성, 상대방 인증 수행 : 메시지 + 비밀키(해시값) 결합

    3. Hashed MAC : IPSec/SSL에서 사용

    4. 메시지 암호 방법에 의한 메시지 인증 방법 : 메시지 복호형 디지털 서명 기능

 

- 디지털 서명 : 부인 봉쇄 - 상대방 인증 필요

    . RSA 디지털 서명 : 양방향 암복호화 (평문 -공개키-> 암호문 -(비공개키)-> 평문 -(비공개키)->암호문-(공개키)->평문)

1. A는 자신의 공개키를 공개 ⇒ B가 공개키를 획득
2. {A는 평문 메시지, (평문 메시지 + 자신의 개인키)암호화 값} 를 B에게 전달 ⇒ B가 {평문 메시지와 암호화 값}을 획득
3. B는 암호화 값을 A의 공개키로 복호화하여 평문 메시지를 추출하고, 같이 전달받은 평문 메시지와 비교함.
4. 이때 같을 경우, 반드시 A가 보낸 것임을 확인 ⇒ 이것을 **전자 서명**이라고 함 (부인봉쇄!)

 

        >  RSA 전자 서명 실습 (https://emn178.github.io/online-tools/rsa/key-generator/)
        - Private Key 와 Public Key 메모해두기

-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIeNrBKPKNzuG3Fc
1kV4hXuToXSVRWu6zpDZ/O3r4c4Lyv4lrb/3I0a4pPfPN0MiASbBXx/s8hUcMqWg
DS3ZwH8QsljiawNEF4OYIGnTgJmBuWdR5e+twmw6IAoNAY4kyU1x6BxJF3uDFm9K
a1Rc+Guk489lDfXtFBaoCHowJP4NAgMBAAECgYADyHNl7TLhv49qgYHFXJC1GzCl
VUkjsYn0RvElHrElk/StVRXdRqNoZNzNwa20JO3NTBZAiNdUuX28W5QilHInzy5+
2ub/a+S//pX96qtK1nz4i9N4v/h+KH5ijUuSso/JyGGlQyVCUl12g5eOBqIuauGI
qn8QLLpz6AlX4Ek/4QJBANPskiqSSIUPijbcaYbVXa4+rnPeuYCwXtx42m3YlQyQ
nIFqFOwfRus/FuPTIrFBu3JirsjcqGkGWIInzL8YDfkCQQCjvumnfbSaVfOYInqJ
ziePwxSTANUd64sO6l0n4/hgPI/iJ9vc05vNMuaZiG5j4aaruQmmumBwylRnfMDP
F0W1AkEAiPl0M+3ez5oOtIzb7BlGdpPu/9dqQMI+XfQDAlKla7ygW4ksQr2oge6C
JfjWiIk61aDw5cSxWUiPtnhw/uZWSQJAZbmS2pTDgCXpgRfaXIYQGcWtoG2h+EZ+
SzPZz5BWmyLEmFD+y79CSUZX8AXL3o0ux/vaPRQIGcn4iZn9BiqFCQJBALRTBX+Q
FbqWODH/64Yg1SGUKekm64I96MkBUB+WOszS8W+mGvlBAMBIL35QsyN5BbcF/oD2
h02BYGnTaRjVbrk=
-----END PRIVATE KEY-----

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHjawSjyjc7htxXNZFeIV7k6F0
lUVrus6Q2fzt6+HOC8r+Ja2/9yNGuKT3zzdDIgEmwV8f7PIVHDKloA0t2cB/ELJY
4msDRBeDmCBp04CZgblnUeXvrcJsOiAKDQGOJMlNcegcSRd7gxZvSmtUXPhrpOPP
ZQ317RQWqAh6MCT+DQIDAQAB
-----END PUBLIC KEY-----

        - Sign Message : Private Key, Input(mysign!) -> 출력 메모

        - Sign Verification : Public Key, Signature-Data(Sign Message), Input(mysign!)

    . DSA 디지털 서명

      . Digital Signature Standard(DSS)에서 사용하는 공개키 방식의 디지털 서명 방식

      . Diffie-Helman과 유사한 ElGamal 방식의 공개키 값을 사용한다.

 

> X.509 인증서와 PKI

   - X.509 : 디지털 인증서 표준

   - PKI : 공개키 암호화와 인증서를 활용하여 보안 통신을 가능하게 하는 시스템

    > 제 3의 공인된 인증기관(CA)에 각자 공개키를 등록

    > 공개키가 수납된 공인 인증서 발급 (공개키, 유효기간, 사용자 ID, 발급기관)

    > 인증서는 CA의 개인키에 의한 디지털 서명 추가 (변조 방지)

   - CA가 사용자 신분을 보장, 동봉된 키가 사용자의 공개키가 확실함을 보장

 

> x.509 인증서 확인 (운영서버2 kind)

  - 운영서버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

  - 인증서 정보 확인

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

CA 인증서 기본 정보
하위 인증서 기본 정보 - apiserver-kublet 통신 인증서
인증서 발급 요청 (CSR)

- kind 설치자의 kubeconfig 정보 확인

# 아래 출력되는 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...

CA에게 서명해서 전달받은 나의 인증서
나의 비밀키
루트 인증서

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

    > 신규 직원 입사로 새로운 유저 생성하여 api서버와 통신할 수 있는 신규 인증서 발급

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

 

> k8s API 구조

  1. 리소스 및 동사

   - RESTful API

   - 리소스 : 상호작용 대상 엔티티

 

#
kubectl run nginx --image=nginx

#
kubectl get --raw /api/v1/namespaces/default/pods | jq
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "resourceVersion": "650"
  },
...

#
kubectl get pod -v6
...
I0309 00:37:08.775999   18829 round_trippers.go:560] GET https://127.0.0.1:51633/api/v1/namespaces/default/pods?limit=500 200 OK in 10 milliseconds

#
kubectl get pod -v8
...
I0309 00:37:58.728427   18905 helper.go:113] "Response Body" body="{\"kind\":\"Table\",\"apiVersion\":\"meta.k8s.io/v1\",\"metadata\":{\"resourceVersion\":\"1588\"},\"columnDefinitions\":[{\"name\":\"Name\",\"type\":\"string\",\"format\":\"name\",\"description\":\"Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names\",\"priority\":0},{\"name\":\"Ready\",\"type\":\"string\",\"format\":\"\",\"description\":\"The aggregate readiness state of this pod for accepting traffic.\",\"priority\":0},{\"name\":\"Status\",\"type\":\"string\",\"format\":\"\",\"description\":\"The aggregate status of the containers in this pod.\",\"priority\":0},{\"name\":\"Restarts\",\"type\":\"string\",\"format\":\"\",\"description\":\"The number of times the containers in this pod have been restarted and when the last container in this pod has restarted.\",\"priority\":0},{\"n [truncated 3887 chars]"

kubectl 원시 모드(raw)는 Kubernetes API와 직접 상호 작용하여 일부 내장  kubectl 기능을 우회할 수 있는 특수 기능

 

2. API 그룹 및 버전

  - 그룹 : 

     . core group : /api - 핵심 리소스 (apiVersion: v1)

     . named group : /apis/<group-name> - 코어 그룹 외 모든 리소스 (네트워킹, 스토리지 등 특정 영역)

  - 버전:

    . alpha : 실험적

    . beta : 많은 테스트 거쳤지만 변경 가능

    . stable / GA : 안정

 

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

    - Pod, Ingress, Deployment 등 => 특정 객체가 어떻게 보이고 동작하는지 정의

 

1. K8S 인증/인가

- K8S Api의 접근 제어

  . Admission Process :

    . Mutating(변경) : pod spec에 추가

    . Validating(검사) : spec 적용 확인

  . Authentication (인증) :

    . x.509 : 클라이언트 인증서 기반

    . HTTP 인증 : 헤더 토큰 정보 기반

    . OIDC 인증 : OIDC Connect 인증 방식 - identity provider와 연동 (google, kakao 등)

    . webhook

    . Proxy 인증 : proxy 통해 외부 인증 시스템 인증

 

  . Authorization (인가) :

    . RBAC : 역할 기반

    . ABAC : 속성 기반

    . Webhook : webhook 토큰 기반 외부 인가 시스템 사용

    . Node : 노드 접근 제어, 할당 파드에 따라 kubelet에 권한 부여

    . AlwaysAllow/AlwaysDeny : 모든 요청 허용/차단

 

  .  kubeconfig 파일

    . clusters : api 서버의 접속 정보 목록

    . users : 사용자 인증 정보 목록 (서비스 어카운트 토큰, 인증서 데이터 등)

    . context : cluster + user

 

> 실습 환경

    -  쿠버네티스에 사용자를 위한 서비스 어카운트(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

 

# 각각 네임스피이스에 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

계정에 pod 조회 권한이 없음

 

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

  - 롤(Role) : apiGroups와 resources로 지정된 리소스에 대해 verbs 권한을 인가

  - 실행 가능한 조작(verbs) : *(모두 처리), create(생성), delete(삭제), get(조회), list(목록조회), patch(일부업데이트), update(업데이트), watch(변경감시)

 

# 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

모든 리소스에 모든 동작 가능
서비스 어카운트에 롤 바인딩

> pod 조회 및 생성 테스트

# 각각 파드로 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

Pod 조회, 실행, 삭제 가능, 노드 조회 불가

 

2. EKS 인증/인가

> RBAC 관련 krew 플러그인 설치

# 설치
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"

> EKS 인증/인가 확인

- 인증은 AWS IAM, 인가는 K8S RBAC에서 처리

https://devlos.tistory.com/75

 

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

  . STS (Security Token Service) : AWS 리소스에 대한 액세스 제어 가능한 임시 보안 자격 증명 생성하여 제공

  . AWS CLI 버전 1.16.156 이상에서 aws-iam-authenticator 설ㅊ 없이 aws eks get-token 으로 사용 가능

# 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
...

kubeconfig에서 토큰을 가져오도록 설정됨

 

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

# 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 반환

# 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.

 

> Token-Review는 AWS IAM-Authentication Server를 통해 사용자 검증

> aws-auth configmap을 통해 k8s group 비교

 

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

- IAM User/Role 확인이 되면 k8s aws-auth configmap에서 mapping 정보 확인

- 컨피그맵에 'IAM 사용자, 역할 arm, K8S 오브젝트' 로 권한 확인 후 k8s 인가 허가가 되면 최종적으로 동작 실행

# 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

configmap에서 사용자를 삭제하면 문제 발생 -> api 방식으로 변경되어 표출되지 않음

 

> 신입 사원을 위한 myeks-bastion-2 (운영서버2)에 설정 (aws-auth configmp 방식)

  1) [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

2) [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

> admin 권한을 주었지만, kubeconfig가 없음

 

3) [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

 

4) [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"],
...

 

5) [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

6) [myeks-bastion-2] testuser kubectl 사용 확인

불가

7) [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

8) [myeks-bastion-2] testuser kubectl 사용 확인

> 이런 문제로 aws-auth configmap 방식 deprecated -> access entry (api)

 

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

 

1) 노드 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
...

 

- 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
---

pod는 노드의 IAM Role 사용 가능

 

- A deep dive into simplified Amazon EKS access management controls (Access Entry)

> EKS → 액세스 : IAM 액세스 항목

> EKS → 액세스 구성 모드 확인 : EKS API 및 ConfigMap ← 정책 중복 시 EKS API 우선되며 ConfigMap은 무시됨

  . configmap에 없어도 권한 부여

  . api로 바꾸면 configmap으로 복구 안 됨 (api에 선 부여 필요)

> 기본 정보 확인 : access policy, access entry, associated-access-policy

# EKS API 액세스모드로 변경
aws eks update-cluster-config --name $CLUSTER_NAME --access-config authenticationMode=API

# List all access policies : 클러스터 액세스 관리를 위해 지원되는 액세스 정책
# https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html
## AmazonEKSClusterAdminPolicy – 클러스터 관리자
## AmazonEKSAdminPolicy – 관리자
## AmazonEKSEditPolicy – 편집
## AmazonEKSViewPolicy – 보기
...
aws eks list-access-policies | jq

# 맵핑 클러스터롤 정보 확인
kubectl get clusterroles -l 'kubernetes.io/bootstrapping=rbac-defaults' | grep -v 'system:'
NAME                                                                   CREATED AT
admin                                                                  2024-04-06T05:58:32Z
cluster-admin                                                          2024-04-06T05:58:32Z
edit                                                                   2024-04-06T05:58:32Z
view                                                                   2024-04-06T05:58:32Z

kubectl describe clusterroles admin
kubectl describe clusterroles cluster-admin
kubectl describe clusterroles edit
kubectl describe clusterroles view

#
aws eks list-access-entries --cluster-name $CLUSTER_NAME | jq
{
  "accessEntries": [
    "arn:aws:iam::911283...:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-t4MD9Py4ZCyK",
    "arn:aws:iam::911283...:user/admin"
  ]
}

# 확인 : macOS - 뒤에 admin 은 자신의 IAM User로 변경해서 실행 할 것!
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID\:user/admin | jq # macOS

# 확인 : Linux (운영서버, WSL2 등) - 뒤에 admin 은 자신의 IAM User로 변경해서 실행 할 것!
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/admin | jq # Linux
{
  "associatedAccessPolicies": [
    {
      "policyArn": "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy",
      "accessScope": {
        "type": "cluster",
        "namespaces": []
      },
      "associatedAt": "2024-04-06T14:53:36.982000+09:00",
      "modifiedAt": "2024-04-06T14:53:36.982000+09:00"
    }
  ],
  "clusterName": "myeks",
  "principalArn": "arn:aws:iam::91128...:user/admin"
}

# 위에서 출력된 nodegroup IAM Role ARN 을 아래 입력 해서 실행 할 것!
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID\:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-t4MD9Py4ZCyK | jq
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-t4MD9Py4ZCyK | jq
{
  "associatedAccessPolicies": [],
  "clusterName": "myeks",
  "principalArn": "arn:aws:iam::9112834...:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-t4MD9Py4ZCyK"
}

#
aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID\:user/admin | jq
aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/admin | jq
...
    "kubernetesGroups": [],
    ...
    "username": "arn:aws:iam::9112...:user/admin",
    "type": "STANDARD"
...

aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID\:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-t4MD9Py4ZCyK | jq
aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-t4MD9Py4ZCyK | jq
...
    "kubernetesGroups": [
      "system:nodes"
    ...
    "username": "system:node:{{EC2PrivateDNSName}}",
    "type": "EC2_LINUX"
...

 

- 신입사원(testuser) 설ㅈ어

# testuser 의 access entry 생성
aws eks create-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser
aws eks list-access-entries --cluster-name $CLUSTER_NAME | jq -r .accessEntries[]

# testuser에 AmazonEKSClusterAdminPolicy 연동
aws eks associate-access-policy --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser \
  --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy --access-scope type=cluster

#
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser | jq
aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser | jq

> [myeks-bastion-2]에서 testuser로 확인

# testuser 정보 확인
aws sts get-caller-identity --query Arn
kubectl whoami

# kubectl 시도
kubectl get node -v6
kubectl api-resources -v5
kubectl rbac-tool whoami
kubectl auth can-i delete pods --all-namespaces
kubectl get cm -n kube-system aws-auth -o yaml
eksctl get iamidentitymapping --cluster $CLUSTER_NAME

sctl get iamidentitymapping --cluster $CLUSTER_NAME
컨피그맵에 없음

> Access entry와 kubernetes group을 활용해서 권한 제어하기 (viewer, admin)

# 기존 testuser access entry 제거
aws eks delete-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser
aws eks list-access-entries --cluster-name $CLUSTER_NAME | jq -r .accessEntries[]

#
cat <<EoF> ~/pod-viewer-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-viewer-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["list", "get", "watch"]
EoF

cat <<EoF> ~/pod-admin-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-admin-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["*"]
EoF

kubectl apply -f ~/pod-viewer-role.yaml
kubectl apply -f ~/pod-admin-role.yaml

#
kubectl create clusterrolebinding viewer-role-binding --clusterrole=pod-viewer-role --group=pod-viewer
kubectl create clusterrolebinding admin-role-binding --clusterrole=pod-admin-role --group=pod-admin

#
aws eks create-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser --kubernetes-group pod-viewer
...
    "accessEntry": {
        "clusterName": "myeks",
        "principalArn": "arn:aws:iam::91128...:user/testuser",
        "kubernetesGroups": [
            "pod-viewer"
        ],

#
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser
aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser | jq
...
    "kubernetesGroups": [
      "pod-viewer"
    ],
...

조회는 되지만 삭제는 안됨

- admin 권한 부여

#
aws eks update-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser --kubernetes-group pod-admin | jq -r .accessEntry
...
  "kubernetesGroups": [
    "pod-admin"
...
aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser | jq
...
    "kubernetesGroups": [
      "pod-admin"
    ],
...

조회, 삭제 모두 가능

3. EKS IRSA & Pod Identity

  . Pod가 최소 권한으로 AWS 자원을 사용 가능하도록 인증/인가 처리를 위한 방법

  . EC2 인스턴스 프로파일 : 사용하기 편하나, 노드 권한을 그대로 사용하여 최소 권한 부여 원칙 위배

# 설정 예시 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 : 테라폼
...

 

> 필요 지식

  - Service Account Token (SAT) Volume Projection

    . 서비스 계정 토큰 시크릿 기반 볼륨 대신 'projected volume' 사용

    => 토큰 사용 대상, 유효기간 등 토큰 속성 지정 가능

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - mountPath: /var/run/secrets/tokens
      name: vault-token
  serviceAccountName: build-robot
  volumes:
  - name: vault-token
    projected:
      sources:
      - serviceAccountToken:
          path: vault-token
          expirationSeconds: 7200
          audience: vault

 

> Configure a Pod to Use a Projected Volume for Storage : 시크릿 컨피그맵 downwardAPI serviceAccountToken의 볼륨 마운트를 하나의 디렉터리에 통합

apiVersion: v1
kind: Pod
metadata:
  name: test-projected-volume
spec:
  containers:
  - name: test-projected-volume
    image: busybox:1.28
    args:
    - sleep
    - "86400"
    volumeMounts:
    - name: all-in-one
      mountPath: "/projected-volume"
      readOnly: true
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: user
      - secret:
          name: pass
          
---

# Create the Secrets:
## Create files containing the username and password:
echo -n "admin" > ./username.txt
echo -n "1f2d1e2e67df" > ./password.txt

## Package these files into secrets:
kubectl create secret generic user --from-file=./username.txt
kubectl create secret generic pass --from-file=./password.txt

# 파드 생성
kubectl apply -f https://k8s.io/examples/pods/storage/projected.yaml

# 파드 확인
kubectl get pod test-projected-volume -o yaml | kubectl neat
...
volumes:
  - name: all-in-one
    projected:
      defaultMode: 420
      sources:
      - secret:
          name: user
      - secret:
          name: pass
  - name: kube-api-access-n6n9v
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace

# 시크릿 확인
kubectl exec -it test-projected-volume -- ls /projected-volume/
password.txt  username.txt

kubectl exec -it test-projected-volume -- cat /projected-volume/username.txt ;echo
admin

kubectl exec -it test-projected-volume -- cat /projected-volume/password.txt ;echo
1f2d1e2e67df

# 삭제
kubectl delete pod test-projected-volume && kubectl delete secret user pass

 

 

- Addmission Control

  . Admisstion Control 권한이 있는 사용자에 한해서 관리자(Admin)가 특정 행동을 제한(validate) 혹은 변경(mutate)

  . Admission Control은 Webhook을 통해 API를 제공하고, 사용자는 자신만의 Admission Controller를 구현할 수 있음
  . Dynamic Admission Controller는 크게 MutatingWebhook과 ValidatingWebhook으로 나뉨
  . MutatingWebhook은 요청을 수정하고, ValidatingWebhook은 요청을 거부하는 역할을 함

 

 

- JWT

  . Bearer type - JWT(JSON Web Token) X.509 Certificatelightweight JSON 버전

  . JWT는 Header, Payload, Signature로 구성되어 토큰의 변조 여부를 검증
  . private key와 public key를 통해 서명과 검증을 처리
  . 쿠버네티스뿐만 아니라 다양한 웹사이트에서 인증, 권한 관리에 사용되는 JSON 기반의 토큰 형식

 

- OIDC

   . 사용자를 인증해 사용자에게 액세스 권한을 부여할 수 있게 해주는 프로토콜

    . OAuth 2.0 : 권한허가 처리 프로토콜, 다른 서비스에 접근할 수 있는 권한을 획득 또는 다른 서비스에게 권한을 부여

    . 위임 권한 부여 (Delegated Authorization) : 사용자 인증 보다는 제한된 사람에게(혹은 시스템) 제한된 권한을 부여

        예) 페이스북 posting 권한

    . Access Token : 발급처(OAuth 2.0), 서버의 리소스 접근 권한

    . OpenID : 비영리기관인 OpenID Foundation에서 추진하는 개방형 표준 및 분산 인증 Authentication 프로토콜, 사용자 인증 및 사용자 정보 제공(id token)

    . ID Token : 발급처(OpenID Connect), 유저 프로필 정보 획득

    . OIDC OpenID Connect = OpenID 인증 + OAuth2.0 인가, JSON 포맷을 이용한 RESful API 형식으로 인증

      - iss: 토큰 발행자

      - sub: 사용자를 구분하기 위한 유니크한 구분자

      - email: 사용자의 이메일

      - iat: 토큰이 발행되는 시간을 Unix time으로 표기한 것

      - exp: 토큰이 만료되는 시간을 Unix time으로 표기한 것

      - aud: ID Token이 어떤 Client를 위해 발급된 것인지.

    . IdP Open Identify Provider : 구글, 카카오와 같이 OpenID 서비스를 제공하는 신원 제공자.

       - OpenID Connect에서 IdP의 역할을 OAuth가 수행

    . RP Relying Party : 사용자를 인증하기 위해 IdP에 의존하는 주체

 

> IRSA

. 파드가 특정 IAM 역할로 Assume 할 때 토큰을 AWS에 전송, AWS는 토큰과 EKS IdP를 통해 IAM 사용 가능 여부 검증

> 동작 방식

 

> 실습

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

> 권한 없음 실패

 

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

> Service Account에 IAM Role 부착

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

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

# 파드에 볼륨 마운트 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 리소스에 안전하고 세밀하게 접근할 수 있도록 인증 메커니즘 제공.

pod 생성시 mutating webhook에 의해 iam 토큰 주입
s3는 조회되지만, ec2는 조회되지 않음

> 정보 탈취 시 키/토큰 발급 악용 가능

> 토큰 변조 유무만 검사, 서비스 어카운트에 부여된 역할과 실제 수임하려는 역할이 같은지 검사 X

> 신뢰 관계에 "*"로 serviceaccount 지정하고 IAM Role만 알면 똑같은 권한 수임 가능

> ODIC Provider는 public이며, 클러스터 신규 생성시 매번 갱신 필요

==> Pod Identity의 등장

 

- Pod Identity

  . Pod Identity Agent를 통해 외부 OIDC 프로바이더를 거치지 않고 내부 처리

 

> 설치 및 실습

#
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

- 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"
      ]
    }
  ]
}

# 서비스어카운트, 파드 생성
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

  • 고려사항
    • SDK 최신 버전 확인
    • 워커노드에 IAM Policy 확인 : Action(eks-auth:AssumeRoleForPodIdentity)
    • 보안 솔루션으로 링크 로컬 주소 사용 가능 여부 확인, 혹은 이미 사용 중인 주소인지, iptables 로 막혀있는지 확인

4. OWASP Kubernetes Top Ten

  - Kubelet 미흡한 인증/인가 설정 시 위험 + kubeletct 툴 

# 노드의 kubelet API 인증과 인가 관련 정보 확인
ssh ec2-user@$N1 sudo cat /etc/kubernetes/kubelet/config.json | jq
...
  "authentication": {
    "x509": {
      "clientCAFile": "/etc/kubernetes/pki/ca.crt"
    },
    "webhook": {
      "enabled": true,
      "cacheTTL": "2m0s"
    },
    "anonymous": {
      "enabled": false
    }
  },
  "authorization": {
    "mode": "Webhook",
    "webhook": {
      "cacheAuthorizedTTL": "5m0s",
      "cacheUnauthorizedTTL": "30s"
    }
  },
...

ssh ec2-user@$N1 sudo openssl x509 -in /etc/kubernetes/pki/ca.crt -noout -text
...

# 노드의 kubelet 사용 포트 확인 
ssh ec2-user@$N1 sudo ss -tnlp | grep kubelet
LISTEN 0      4096       127.0.0.1:10248      0.0.0.0:*    users:(("kubelet",pid=2940,fd=20))
LISTEN 0      4096               *:10250            *:*    users:(("kubelet",pid=2940,fd=21))

# 데모를 위해 awscli 파드 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: myawscli
spec:
  #serviceAccountName: my-sa
  containers:
    - name: my-aws-cli
      image: amazon/aws-cli:latest
      command: ['sleep', '36000']
  restartPolicy: Never
  terminationGracePeriodSeconds: 0
EOF

# 파드 사용
kubectl exec -it myawscli -- aws sts get-caller-identity --query Arn
kubectl exec -it myawscli -- aws s3 ls
kubectl exec -it myawscli -- aws ec2 describe-instances --region ap-northeast-2 --output table --no-cli-pager
kubectl exec -it myawscli -- aws ec2 describe-vpcs --region ap-northeast-2 --output table --no-cli-pager

# 노드1 접속 
ssh ec2-user@$N1
-----------------------------
# 미흡한 인증/인가 설정으로 변경
sudo vi /etc/kubernetes/kubelet/config.json
...
"authentication": {
    "anonymous": {
      "enabled": true
...
  },
  "authorization": {
    "mode": "AlwaysAllow",
...

# kubelet restart
sudo systemctl restart kubelet
systemctl status kubelet
-----------------------------

<bastion2>

# 파드 목록 확인
curl -s -k https://$N1:10250/pods | jq

# kubelet-config.json 설정 내용 확인
curl -k https://$N1:10250/configz | jq

# kubeletct 사용
# Return kubelet's configuration
kubeletctl -s $N1 configz | jq

# Get list of pods on the node
kubeletctl -s $N1 pods

# Scans for nodes with opened kubelet API > Scans for for all the tokens in a given Node
kubeletctl -s $N1 scan token

# 단, 아래 실습은 워커노드1에 myawscli 파드가 배포되어 있어야 실습이 가능. 물론 노드2~3에도 kubelet 수정하면 실습 가능함.
# kubelet API로 명령 실행 : <네임스페이스> / <파드명> / <컨테이너명>
curl -k https://$N1:10250/run/default/myawscli/my-aws-cli -d "cmd=aws --version"

# Scans for nodes with opened kubelet API > remote code execution on their containers
kubeletctl -s $N1 scan rce

# Run commands inside a container
kubeletctl -s $N1 exec "/bin/bash" -n default -p myawscli -c my-aws-cli
--------------------------------
export
aws --version
aws ec2 describe-vpcs --region ap-northeast-2 --output table --no-cli-pager
exit
--------------------------------

# Return resource usage metrics (such as container CPU, memory usage, etc.)
kubeletctl -s $N1 metrics

토큰 정보, pod 등 인증/인가 없이 바로 요청 가능

5. Kyverno

  . Kubernetes 네이티브 정책 관리 엔진

  . Policy-as-Code 방식으로 리소스를 관리

  . validate, mutate, generate 기능 제공
  . 정책은 YAML로 작성하고 이미지 서명 검증, 리소스 동기화, 정책 위반 보고 등의 기능 지원
  . Dynamic Admission Control을 통해 Mutating/Validating Admission에서 리소스를 허용하거나 거부함

# 설치
# EKS 설치 시 참고 https://kyverno.io/docs/installation/platform-notes/#notes-for-eks-users
# 모니터링 참고 https://kyverno.io/docs/monitoring/
cat << EOF > kyverno-value.yaml
config:
  resourceFiltersExcludeNamespaces: [ kube-system ]

admissionController:
  serviceMonitor:
    enabled: true

backgroundController:
  serviceMonitor:
    enabled: true

cleanupController:
  serviceMonitor:
    enabled: true

reportsController:
  serviceMonitor:
    enabled: true
EOF
kubectl create ns kyverno
helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno --version 3.3.7 -f kyverno-value.yaml -n kyverno

# 확인
kubectl get all -n kyverno
kubectl get crd | grep kyverno
kubectl get pod,svc -n kyverno

# (참고) 기본 인증서 확인 https://kyverno.io/docs/installation/customization/#default-certificates
# step-cli 설치 https://smallstep.com/docs/step-cli/installation/
wget https://dl.smallstep.com/cli/docs-cli-install/latest/step-cli_amd64.rpm
sudo rpm -i step-cli_amd64.rpm

#
kubectl -n kyverno get secret
kubectl -n kyverno get secret kyverno-svc.kyverno.svc.kyverno-tls-ca -o jsonpath='{.data.tls\.crt}' | base64 -d
kubectl -n kyverno get secret kyverno-svc.kyverno.svc.kyverno-tls-ca -o jsonpath='{.data.tls\.crt}' | base64 -d | step certificate inspect --short
X.509v3 Root CA Certificate (RSA 2048) [Serial: 0]
  Subject:     *.kyverno.svc
  Issuer:      *.kyverno.svc
  Valid from:  2024-04-07T06:05:52Z
          to:  2025-04-07T07:05:52Z

#
kubectl get validatingwebhookconfiguration kyverno-policy-validating-webhook-cfg -o jsonpath='{.webhooks[0].clientConfig.caBundle}' | base64 -d | step certificate inspect --short
X.509v3 Root CA Certificate (RSA 2048) [Serial: 0]
  Subject:     *.kyverno.svc
  Issuer:      *.kyverno.svc
  Valid from:  2024-04-07T06:05:52Z
          to:  2025-04-07T07:05:52Z

 

각 규칙은 match선언, 선택적 exclude선언 및 validate, mutate, generate또는 verifyImages선언 중 하나로 구성 각 규칙에는 단일 validate, mutate, generate또는 verifyImages하위 선언만 포함

# 모니터링
watch -d kubectl get pod -n kyverno

# ClusterPolicy 적용
kubectl apply -f- << EOF
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-team
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "label 'team' is required"
      pattern:
        metadata:
          labels:
            team: "?*"
EOF

# 확인
kubectl get validatingwebhookconfigurations
kubectl get ClusterPolicy
NAME             ADMISSION   BACKGROUND   VALIDATE ACTION   READY   AGE   MESSAGE
require-labels   true        true         Enforce           True    12s   Ready

# 디플로이먼트 생성 시도
kubectl create deployment nginx --image=nginx
error: failed to create deployment: admission webhook "validate.kyverno.svc-fail" denied the request: 

resource Deployment/default/nginx was blocked due to the following policies 

require-labels:
  autogen-check-team: 'validation error: label ''team'' is required. rule autogen-check-team
    failed at path /spec/template/metadata/labels/team/'

# 디플로이먼트 생성 시도
kubectl run nginx --image nginx --labels team=backend
kubectl get pod -l team=backend

# 확인
kubectl get policyreport -o wide
NAME                                   KIND         NAME                          PASS   FAIL   WARN   ERROR   SKIP   AGE
e1073f10-84ef-4999-9651-9983c49ea76a   Pod          nginx                         1      0      0      0       0      29s

kubectl get policyreport e1073f10-84ef-4999-9651-9983c49ea76a -o yaml
apiVersion: wgpolicyk8s.io/v1alpha2
kind: PolicyReport
metadata: 
  labels: 
    app.kubernetes.io/managed-by: kyverno
  name: e1073f10-84ef-4999-9651-9983c49ea76a
  namespace: default
results: 
- message: validation rule 'check-team' passed.
  policy: require-labels
  result: pass
  rule: check-team
  scored: true
  source: kyverno
  timestamp: 
    nanos: 0
    seconds: 1712473900
scope: 
  apiVersion: v1
  kind: Pod
  name: nginx
  namespace: default
  uid: e1073f10-84ef-4999-9651-9983c49ea76a
summary: 
  error: 0
  fail: 0
  pass: 1
  skip: 0
  warn: 0

# 정책 삭제
kubectl delete clusterpolicy require-labels

#
kubectl apply -f- << EOF
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-labels
spec:
  rules:
  - name: add-team
    match:
      any:
      - resources:
          kinds:
          - Pod
    mutate:
      patchStrategicMerge:
        metadata:
          labels:
            +(team): bravo
EOF

# 확인
kubectl get mutatingwebhookconfigurations
kubectl get ClusterPolicy
NAME         ADMISSION   BACKGROUND   VALIDATE ACTION   READY   AGE     MESSAGE
add-labels   true        true         Audit             True    6m41s   Ready

# 파드 생성 후 label 확인
kubectl run redis --image redis
kubectl get pod redis --show-labels

# 파드 생성 후 label 확인 : 바로 위와 차이점은?
kubectl run newredis --image redis -l team=alpha
kubectl get pod newredis --show-labels

# 삭제
kubectl delete clusterpolicy add-labels

 

 

 

 

 

 

'K8S - EKS' 카테고리의 다른 글

8주차 - K8S CI/CD  (0) 2025.03.29
7주차 - EKS Mode/Nodes  (0) 2025.03.22
5주차 - EKS Autoscaling  (0) 2025.03.07
4주차 - EKS Observability  (0) 2025.02.28
3주차 - EKS Storage, Managed Node Groups  (1) 2025.02.22

관련글 더보기