6주차 - EKS Security

bocopile·2025년 3월 15일

AEWS 3기 스터디 

목록 보기
12/18

기본 이론

암호/복호 과정

  • 평문을 제 3자가 해독할수 없는 암호문으로 변환하여 전송하고, 수신측에서 암호문으로 부터 평문을 복원 하는 과정
  • 이 과정에서 사용되는 알고리즘을 암호 알고리즘, 암호화/복호화를 하는데 있어서 핵심이 되는 역할은 Key이다.
  • 암호화/복호화 과정에서 쌍방이 확보할 수 있는 방법에는 공유 비밀키 (Shard Secret Key) 와 공개키 (Public Key) 방식이 존재한다.
    • 공유 비밀키 암호화 방식 (shared secret key) : DES, 3DES, RC4/5
    • 공개키 암호화 방식 (public key) : RSA
    • 키 분배 방식 : ‘DH방식, RSA공개키, 키 분배 센터(KDC)’을 이용한 공유 비밀키 분배 방법

암/복호화 예시

  • 송신자 → 수신자에게 ‘ABC’ 문장을 다음과 같은 규칙을 사용하여 전송한다 가정을 한다.

  • 이 경우 “ABC” 문자열을 구성하는 ‘0x41,0x42,0x43’ 값은 각각 0x44, 0x45, 0x46으로 변환되어 “DEF”로 전송된다.

  • 이 규칙을 사전에 알고 있는 수신측에서는 바이트 열에 각각 3씩 빼서 원래의 ‘ABC’ 문자열을 복원한다.

  • 이러한 전송과정과 수신과정에서 사용되는 변환 규칙인 “각 문자의 ASCII 코드 값에 x씩 더하여 전송한다”의 개념을 암호 알고리즘이라고 하며 ‘x=3” 를 키 값

    • 여기서 암호 알고리즘은 제 3자에게 공개되어도 되지만, 키 값은 쌍방만이 알고 있어야 한다.

공유 비밀키 암호 방식 (Shard Secret Key)

  • 수신자, 송신자가 공유하는 하나의 비밀키를 사용하여 암호화, 복호화 하는 방식
  • 대칭(symmetric) 혹은 관용 (conventional) 암호 방식이라고 한다.
  • 블록 암호화 방식 (Block cipher) : DES, 3DES, IDEA, RC4/5 등이 있음
  • 평문을 일정길이 단위로 분할한 블록들에 대해 암호화 하는 방식

단방향 알고리즘

  • 파일 무결성 확인 방법 : 파일 전체를 비교 → 파일의 지문과 비교 (해시 함수 적용의 결과값[다이제스트]을 비교)
  • 일정 크기 출력 : 해시 값의 길이는 메세지 길이와 관련없이 고정된 길의 해시 값을 출력
  • 메세지가 1비트라도 변화시, 해시 값은 매우 높은 확률로 다른 값이 되어야 함
  • 해시 값으로 부터 메세지를 역산 할수 없음
  • 출동 내성 : 충돌을 발견하는 것이 어려운 성질

공개키 암호방식

  • Public / Private Key를 쌍으로 만들어 Public Key로 암호화 하고, Private Key로 복호화 하는 방식 (비대칭 암호 방ㅎ식)
  • 공개키 암호에서는 서로 다른 두개의 키를 사용하고 있어 항상 공개키와 비밀키를 모두 생성해야 한다.
  • 대표적으로 RSA가 존재한다.
  • 대칭 키 방식의 경우 쌍방이 알고 있어야 하는데, 대칭키 값을 안전하게 분배하기 어렵다.
  • 반면에 공개키는 이러한 방법을 해결할수 있다.
  • 즉 A-B와 은닉통신을 하고자 할때 B는 {개인키, 공개키} 쌍으로 생성 한 후에 자신의 공개키를 A에게 제공한다.
  • 이 과정에서 공개키가 제 3자에게 노출 될수도 있으나 이것을 도청하는 제 3자에게는 B의 개인키를 모르기 때문에 암호화된 내용을 복호화 할수 없다.

실습환경 배포

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

AWS EKS 설치 확인

# 변수 지정
CLUSTER_NAME=myeks
SSHKEYNAME=bocopile-key

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

# 
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 에서 SSH 접속 확인

# 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

운영서버 1에서 각 노드로 접근이 되는 것을 확인

mac 환경 설정

# 실습 완료 후 삭제 할 것!
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=bocopile.com # 각자 자신의 도메인 이름 입력
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

해당 파라미터 조회 되는 것을 확인

AWS LB Controller 설치

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 StorageClass 생성

# 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

gp3 StorageClass 생성 및 Default 설정이 완료된 것을 확인

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

# kube-ops-view 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
    • AWS LB Controller, CoreDNS, ExternalDNS, Kube-ops-view 파드 실행 확인
  • service, ep, ingress 확인
    kubectl get ingress,svc,ep -n kube-system
  • kube-ops-view 확인
      

Kube-ops-view 사이트 접근

open "https://kubeopsview.$MyDomain/#scale=1.5" # macOS

kubeopsview 접근 되는 것을 확인

프로메테우스 & 그라파나 설치

# 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

프로메테우스 및 그라파나 사이트 접속 되는 것을 확인

그라파나 대시보드 Import 작업 진행

  1. import 작업 : 17900 - Link
  2. 대시보드 생성 된것을 확인
  3. 조회 되지 않는 지표 PromQL/Variables 수정 (namespace, PVC 등)
    1. 4주차 Grafana 참고 - Link

K8S 인증/인가

Access to the K8S API

missing 출처 : https://kubetm.github.io/k8s/07-intermediate-basic-resource/authentication/
  • 클러스터 내부 및 외부에서 kube-apiserver와 상호작용하는 방식
  • k8s API는 클러스터 상태를 조회하고, 리소스 생성/수정/삭제 할수 있도록 RESTful API 형태로 제공

K8S API Server 요청 흐름

missing 출처 : https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/
  1. Authentication (인증)
  2. Authorization (인가)
  3. Admission Control
  4. ETCD 저장

1) Authentication (인증)

요청을 보낸 사용자가 신뢰 할수 있는지 확인

missing 출처 : https://kubetm.github.io/k8s/07-intermediate-basic-resource/authentication
  • X.509 Client Certs : kubeconfig에 CA crt(발급 기관 인증서), Client crt (클라이언트 인증서), Client
  • kubectl : 여러 클러스터 (kubeconfig)를 관리 기능 - Contexts에 클러스터 유저 및 인증서/키를 참고한다.
  • Service Account : 서명된 bearer token을 사용하여, 요청을 검정하는 자동활성화 된 인증서

2) Authorization (인가)

사용자가 해당 요청을 수행할 권한이 있는지를 확인

missing 출처 : https://kubetm.github.io/k8s/07-intermediate-basic-resource/authentication
  • 인가 방식 : RBAC (Role-Based Access Control), ABAC(Attribute-Based Access Control), Webhook, Node Authorization을 적용
  • RBAC : 역할 기반의 권한 관리 , 사용자와 역할을 별개로 선언한 뒤 두가지를 바인딩 해서 사용자에게 권한을 부여 하여 kubectl. API로 관리 가능
  • ABAC : 속성 기반 접근 제어 방식, 사용자, 요청, 리소스의 각 속성을 기반으로 접근 권한을 결정
비교 항목RBACABAC
접근 제어 기준역할 (Role)속성 (Attributes)
유연성중간 (고정된 역할 기반)매우 높음 (다양한 조건에서 적용 가능)
정책 적용 방식Role, RoleBinding / ClusterRole, ClusterRoleBinding 을 사용JSON 파일 등으로 정의
적용 예시특정 사용자 그룹에 대한 리소스 접근 허용특정 네트워크 대역에서만 허용

3) Admision Control

  1. Mutating Admission Webhooks : 요청을 변경 (기본값 설정, 사이드카 자동 추가 등)
  2. Validation Admission Webhooks : 요청을 검증 (보안 정책 위반 여부 등)

4) ETCD 저장

검증이 끝난 요청을 etcd에 저장 하고 클러스터에 반영

.kube/config 파일 내용

  • clusters : kubectl이 사용할 k8s API 서버의 접속 정보 목록, 원격의 k8s API 서버의 주소를 추가해 사용 가능

  • users : k8s API 서버에 접속하기 위한 사용자 인증 정보 목록 (SA의 Token, 인증서 데이터 등)

  • context : Cluster 항목과 users 항목에 정의된 값을 조합해 최종적으로 사용할 k8s 클러스터 정보

  • 예시

cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJTHROY2RXbnUvSm93RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBek1UUXdNak0yTWpKYUZ3MHpOVEF6TVRJd01qUXhNakphTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUUN0dExRSFliYlM1bmhYcUQrenF6eWMybHFENlo4c2IreWJmaFp1OVFYVWNRSHVRYnpiU1hjTWxiVXEKUlJtNFplbWJRMFFDZDEyRlU1QTR0TjY0ZmJtclh0TjNpNVI5MmNyUUZRY2dXQW9zbXNFTHhiUUNIT3h5V2ptbApTVTlhR0JqaVo5d2l6UnlFaU81a3Y5dVdsMzA1SzF0M0p5MFdUOTkxV2cyRzhzSUJFM1cxdXc3UHdzOFVKR09ICkdzVjdMc1ZpYWdmdFcrQUpSTW0wTlFGWlVaT25RVUM1WE5rMHB1OE5wNWY4SUg5MVhUaHpkbDdqanM5T3JiQ2EKVHdsZ3dXVDIzODJBSWJDQlZQM0J4K0tRN05VaTNPSk5uVUw5ZlVSTW56dnNFWUE2MzYyRFJEcmF4Z1ZBdUQydgpGS0pCajI1VzYrajM5MEhqcDFPWWhuTzB1RDBwQWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJSdExEaW9WZzJtWm9pcUkzUExWMHdRR1JrRGpUQVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQkVKY3I1QmxyRQozY25TTWQxTnE3bGtFSm1zV2VVWFhZcVBlYU0yNVNsd1RSNDlobVJoazJ2N0xyTFV6MlovTTNQc2JJUVNqeEYyCkQzeHcxcHM1RDhNUmU0VHhpazVXU3pqQjVCZVhUVGVkeXh5cS8rQ2dhbFV0WTdiekdwL1krYzhGdVRKMmxvWm4KOEZjaHI2UHJEdFdITkd4KzNvTE5ZSkRuOUdkalI2RTB4YWE4aWsyL1dzU3ZBeUZkblJ1UzM3ZENrMklzTHdNbApHUDV1cjlHVEtZazROU3V0aEpSakt3MVJxMW1YMU1PUG9TUk9ZNlpiVllQdWFRNGY3WkxtWXNlVnNxcmxnL0ZZClI4TlF4c0JCcjNVODUzU28wN2l1R21PRGVOYU9uUVJlTHplNzhLdTV1cW5WMnpLTnk1ZjB2dWU0WjRCdTMyb0IKQVc2RXhPb0xUR05VCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
    server: https://D4B86138FEDFFE355BF3A3AEF71AD927.sk1.ap-northeast-2.eks.amazonaws.com
  name: arn:aws:eks:ap-northeast-2:867344478065:cluster/myeks
contexts:
- context:
    cluster: arn:aws:eks:ap-northeast-2:867344478065:cluster/myeks
    namespace: default
    user: bocopile
  name: bocopile
current-context: bocopile
kind: Config
preferences: {}
users:
- name: bocopile
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - --region
      - ap-northeast-2
      - eks
      - get-token
      - --cluster-name
      - myeks
      - --output
      - json
      command: aws
      env: null
      interactiveMode: IfAvailable
      provideClusterInfo: false
- name: bocopile@bocopile-karpenter-demo.ap-northeast-2.eksctl.io
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - eks
      - get-token
      - --output
      - json
      - --cluster-name
      - bocopile-karpenter-demo
      - --region
      - ap-northeast-2
      command: aws
      env:
      - name: AWS_STS_REGIONAL_ENDPOINTS
        value: regional
      interactiveMode: IfAvailable

네임스페이스 서비스 어카운트 생성

네임스페이스 생성

kubectl create namespace dev-team
kubectl create ns infra-team

네임스페이스 확인

kubectl get ns

서비스 어카운트 생성

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 -n infra-team

SA를 지정하여 파드 생성 후 권한 테스트

파드 생성

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

파드의 SA Token 정보 확인

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

권한 테스트

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
  • 1번 , 2번 모두 권한 없음

Role 생성, SA 바인딩

Role

  • Role : apiGroups, resourcs로 지정된 리소스에 대한 verbs 권한을 인가
  • verb
    명칭권한
    *모든 권한
    create생성
    delete삭제
    get조회
    list목록 조회
    patch일부 업데이트
    update업데이트
    watch변경 감지

각 네임스페이스에 모든 권한에 대한 롤 생성

# 각각 네임스페이스내의 모든 권한에 대한 롤 생성
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 get roles -n infra-team -o yaml

롤바인딩 생성

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 get rolebindings -n infra-team -o yaml

kubectl describe rolebindings roleB-dev-team -n dev-team
kubectl describe rolebindings roleB-infra-team -n infra-team

권한 재테스트


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 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
k2 auth can-i get pods
  • 1번 : dev-team 네임스페이스에서 get, create, delete 실행 가능(나머진 권한 없음)
  • 2번 : infra-team 네임스페이스 get, create, delete 실행 가능(나머진 권한 없음)
  • 1번, 2번 각각 kubecrl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
k2 auth can-i get pods

리소스 삭제

kubectl delete ns dev-team infra-team

EKS 인증/인가

RBAC 관련 krew 플러그인

설치

kubectl krew install access-matrix rbac-tool ~~rbac-view~~ rolesum whoami

k8s 인증된 주체 확인

kubectl whoami

서버 리소스에 대한 RBAC 엑세스 매트릭스 확인

kubectl access-matrix # Review access to cluster-scoped resources
kubectl access-matrix --namespace default # Review access to namespaced resources in 'default'

Subject (User, Group, SA) 이름별 RBAC 조회

kubectl rbac-tool lookup
kubectl rbac-tool lookup system:masters

EKS RBAC 조회

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

Subject (User, Group, SA) 이름에 대한 RBAC 목록 정책 규칙 조회

kubectl rbac-tool policy-rules
kubectl rbac-tool policy-rules -e '^system:.*'
kubectl rbac-tool policy-rules -e '^system:authenticated'

현재 컨텍스트에 대한 Subject 확인

kubectl rbac-tool whoami

Subject에 대한 RBAC 역할 요약 조회 (SA, User, Group kubectl)

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

RBAC 권한을 시각화하는 도구 실행

# EC2에서 실행할 것
echo -e "RBAC View Web http://$(curl -s ipinfo.io/ip):8800"
kubectl rbac-view
  • 사이트가 접근 되는 것을 확인
  • (참고) 약어
    약어Verbs설명
    GGet리소스를 조회할 수 있음 (get)
    LList리소스를 목록으로 나열할 수 있음 (list)
    WWatch리소스를 감시할 수 있음 (watch)
    CCreate새 리소스를 생성할 수 있음 (create)
    UUpdate기존 리소스를 수정할 수 있음 (update)
    PPatch리소스의 일부를 패치할 수 있음 (patch)
    DDelete리소스를 삭제할 수 있음 (delete)
    DCDelete Collection리소스의 컬렉션(여러 개)을 삭제할 수 있음 (deletecollection)

EKS 인증 / 인가 확인

전체 내용

missing 출처 : https://devlos.tistory.com/75/

진행 순서

  1. kubectl 명령 → aws eks get-token → STS에 토큰 요청 → 응답값 디코드

    • AWS 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::867344478065:user/bocopile"
    
    # kubeconfig 정보 확인
    cat ~/.kube/config
    
    # 조회 결과
    - name: bocopile@bocopile-karpenter-demo.ap-northeast-2.eksctl.io
      user:
        exec:
          apiVersion: client.authentication.k8s.io/v1beta1
          args:
          - eks
          - get-token
          - --output
          - json
          - --cluster-name
          - bocopile-karpenter-demo
          - --region
          - ap-northeast-2
          command: aws
          env:
          - name: AWS_STS_REGIONAL_ENDPOINTS
            value: regional
          interactiveMode: IfAvailable
          provideClusterInfo: false
          
    #임시 보안 자격 증명(토큰)을 요청 : 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

  1. 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.....
  2. EKS API는 Token Review 를 Webhook token authenticator에 요청 ⇒ (STS GetCallerIdentity 호출) AWS IAM 해당 호출 인증 완료 후 User/Role에 대한 ARN 반환

    # tokenreviews api 리소스 확인 
    kubectl api-resources | grep authentication
    
    # List the fields for supported resources.
    kubectl explain tokenreviews

    • 참고로 webhook token authenticator는 aws-iam-authenticator를 사용한다.
  3. [ConfigMap 방식] 이제 쿠버네티스 RBAC 인가를 처리

    • IAM User/Role 확인이 되면 k8s aws-auth configmap에서 mapping 정보를 확인
    • ws-auth 컨피그맵에 'IAM 사용자, 역할 arm, K8S 오브젝트' 로 권한 확인 후 k8s 인가 허가가 되면 최종적으로 동작 실행
    • 참고로 EKS를 생성한 IAM principal은 aws-auth 와 상관없이 kubernetes-admin Username으로 system:masters 그룹에 권한을 가짐
    # aws-auth 컨피그맵 확인 : 현재는 IAM access entry 방식 우선 적용으로 아래 출력 내용과 다를 수 있습니다.
    kubectl get cm -n kube-system aws-auth -o yaml
    
    # EKS 설치한 IAM User 정보 
    kubectl rbac-tool whoami

# 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

# cluster-admin 의 PolicyRule 확인 : 모든 리소스  사용 가능!
kubectl describe clusterrole cluster-admin

# 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 IAM, 인가는 K8S RBAC에서 처리

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

실습

testuser 사용자 생성

  • 사용자 생성 및 권한 부여
    # testuser 사용자 생성
    aws iam create-user --user-name testuser
    # 사용자에게 프로그래밍 방식 액세스 권한 부여
    aws iam create-access-key --user-name testuser
    
    # 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
  • EC2 IP 확인
    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

testuser 자격증명 설정 및 확인

  • 아래 실습을 위한 kind 삭제
    # 아래 실습 진행을 위해, 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
  • get-caller-identify 확인
    aws sts get-caller-identity --query Arn
  • kubectl 명령어 실행
    kubectl get node -v6
    is ~/.kube
    • kubeconfig 가 설정 되어 있지 않아 조회가 안됨

testuser에 EKS 관리자 수준 설정

  • 권한 생성
    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
    eksctl get iamidentitymapping --cluster $CLUSTER_NAME

testuser kubeconfig 생성 및 확인

  • test config 생성
    CLUSTER_NAME=myeks
    aws eks update-kubeconfig --name $CLUSTER_NAME --user-alias testuser
    
  • kubeconfig 조회
    cat ~/.kube/config
  • kubectl 사용 확인
    kubectl ns default
    kubectl get node -v6
  • rbac-tool 확인
    kubectl rbac-tool whoami

testuser Group 변경 후 RBAC 동작 확인

  • system:master → system:authenticated 변경
    kubectl edit cm -n kube-system aws-auth
    
    eksctl get iamidentitymapping --cluster $CLUSTER_NAME

testuser kubectl 사용 확인

kubectl get node -v6
kubectl api-resources -v5

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

testuser kubectl 사용 확인

  • 조회가 되지 않음을 확인
kubectl get node -v6
kubectl api-resources -v5

EKS IRSA & Pod indentify

IRSA(IAM Roles for Service Account)

파드가 특정 IAM 역할로 Assume 할떄 토큰을 AWS에 전송하고, AWS는 토큰과 EKS IdP를 통해 해당 IAM 역할을 사용할수 있는지를 검증

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

IRSA 구성요소

  • OpenID Connect(OIDC) 제공자
  • IAM 역할
  • Kubernetes 서비스 계정 + 특별 어노테이션

IRSA 동작원리

  1. Pod에 서비스 계정을 할당
  2. 서비스 계정에는 AWS IAM 역할 ARN을 지정하는 어노테이션 추가
  3. EKS Pod Identity 에이전트(aws-node DaemonSet의 일부)가 AWS STS 토큰을 관리
  4. 컨테이너 내부에서는 환경 변수를 통해 AWS SDK가 자동으로 자격 증명 사용

실습 1

파드 생성

# 파드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 logs eks-iam-test1

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

파드 확인

  • 에러 발생
# 확인
kubectl get pod
kubectl describe pod

로그 확인

  • 권한 문제로 AccessDenied 발생

해당 내용은 Console에서도 확인이 가능하다 -link

파드 삭제

kubectl delete pod eks-iam-test1

실습2 - Service Account

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

권한이 존재하지 않아 다음과 같은 에러 발생

Service Account Token 확인

SA_TOKEN=$(kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)
echo $SA_TOKEN

해당 값을 디코딩 할 경우 다음과 같은 데이터를 볼수 있다.

파드 2 삭제

kubectl delete pod eks-iam-test2

실습 3 - IRSA

iamserviceaccount 생성

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)

생성 확인

eksctl get iamserviceaccount --cluster $CLUSTER_NAME
kubectl describe sa my-sa

신규 파드 생성

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

파드 확인

  • Token 생성 된것을 확인
kubectl describe pod eks-iam-test

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

파드에서 AWS CLI 사용 확인

  • iamserviceaccount 가 사용되고 있음을 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
kubectl exec -it eks-iam-test3 -- aws sts get-caller-identity --query Arn

파드에 볼륨 마운트 확인

kubectl get pod eks-iam-test3 -o json | jq -r '.spec.containers | .[].volumeMounts'c

aws-iam-token 볼륨 정보 확인

kubectl get pod eks-iam-test3 -o json | jq -r '.spec.volumes[] | select(.name=="aws-iam-token")'

JWT 토큰이 담겨저 있고, exp, aud 속성이 추가 되어 있음

pod-identity-webhook 확인

kubectl describe MutatingWebhookConfiguration pod-identity-webhook 

AWS Web Identify Token File 확인

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

JWT Token을 디코드 한 결과 Service Account my-sa 가 추가 되어 있음을 확인할수 있다.

{
  "aud": [
    "sts.amazonaws.com"
  ],
  "exp": 1742121038,
  "iat": 1742034638,
  "iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/0A4C5694EDFA8ED215368B22641EDED6",
  "jti": "bce359d1-431d-4ec6-969b-966900101e82",
  "kubernetes.io": {
    "namespace": "default",
    "node": {
      "name": "ip-192-168-3-242.ap-northeast-2.compute.internal",
      "uid": "0b514978-b731-4492-9948-00fafcbea330"
    },
    "pod": {
      "name": "eks-iam-test3",
      "uid": "f26b44a2-f857-44c9-bde1-8069737d369f"
    },
    "serviceaccount": {
      "name": "my-sa",
      "uid": "595d5ce0-58e0-4212-9265-fea12b609836"
    }
  },
  "nbf": 1742034638,
  "sub": "system:serviceaccount:default:my-sa"
}

env 확인

kubectl get pod eks-iam-test3 -o json | jq -r '.spec.containers | .[].env'

리소스 삭제

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

OWASP kubernetes Top Ten

OWASP Kubernetes Top Ten 목록은 OWASP 재단이 주도하는 오픈 프로젝트로, 전 세계 보안 전문가, 개발자, 그리고 클라우드 네이티브 커뮤니티의 기여와 데이터를 기반으로 정한다.

다양한 조직의 실제 운영 경험, 보안 연구 결과, 커뮤니티 설문조사 및 취약점 분석 데이터를 종합해 가장 중요한 보안 리스크를 도출한다.

K01: Insecure Workload Configurations

  • 설명:
    컨테이너가 불필요하게 높은 권한(예: root 또는 privileged)으로 실행되거나, 리소스 제한 및 보안 컨텍스트 설정이 미흡한 경우
  • 대응 방안:
    • 비루트(non-root) 사용자 실행 및 securityContext, readOnlyRootFilesystem 등 적절한 보안 설정 적용
    • Pod Security Standards(예: OPA Gatekeeper, Kyverno)를 통해 자동화된 정책 적용
    • 리소스 제한 및 요청(requests & limits)을 명확히 설정

K02: Supply Chain Vulnerabilities

  • 설명:
    신뢰할 수 없는 컨테이너 이미지, 취약한 서드파티 컴포넌트, 그리고 CI/CD 파이프라인에서 발생하는 공급망 취약점
  • 대응 방안:
    • 신뢰할 수 있는 레지스트리 사용 및 이미지 서명, SBOM(Software Bill of Materials) 관리
    • Trivy, Grype 등 이미지 취약점 스캐닝 도구 도입
    • CI/CD 파이프라인에 취약점 검사 자동화를 적용

K03: Overly Permissive RBAC Configurations

  • 설명:
    과도한 권한(예: cluster-admin)을 부여하거나, 잘못된 Role/RoleBinding 설정으로 인해 불필요한 접근이 허용되는 경우
  • 대응 방안:
    • 최소 권한 원칙(Least Privilege)을 준수하여 RBAC를 세분화
    • 정기적인 RBAC 감사 도구(예: RBAC Audit, Kubiscan, Krane)로 설정 검토 및 개선

K04: Lack of Centralized Policy Enforcement

  • 설명:
    여러 클러스터나 멀티클라우드 환경에서 보안 정책이 분산되어 적용되어 일관성이 부족한 경우
  • 대응 방안:
    • OPA Gatekeeper, Kyverno 등 중앙집중식 정책 관리 도구를 활용하여 모든 클러스터에 일관된 정책 배포
    • GitOps와 같은 자동화 파이프라인을 통해 정책 변경 사항을 신속하게 반영

K05: Inadequate Logging and Monitoring

  • 설명:
    감사 로그, 이벤트 기록, 모니터링 시스템이 미흡하여 침해 탐지 및 대응에 어려움이 있는 경우
  • 대응 방안:
    • Kubernetes Audit Logs 활성화 및 중앙집중식 로그 수집 (예: Fluentd, ELK 스택)
    • Prometheus, Grafana를 이용한 모니터링 체계 구축 및 Falco와 같은 런타임 보안 도구 도입

K06: Broken Authentication Mechanisms

  • 설명:
    인증 메커니즘의 설정 오류나 약한 구성으로 인해 무단 접근이 가능해지는 경우
  • 대응 방안:
    • MFA(다단계 인증)와 같은 강력한 인증 수단 적용
    • 서비스 계정 토큰 및 인증 토큰을 짧은 수명으로 관리
    • 인증 관련 설정(예: API Server, kubelet 인증)을 정기적으로 점검

K07: Missing Network Segmentation Controls

  • 설명:
    기본적으로 평면 네트워크 구조로 인해 클러스터 내에서 공격자가 자유롭게 이동할 수 있는 경우
  • 대응 방안:
    • NetworkPolicy를 활용해 포드 간 통신을 제한하고, 최소 권한 네트워크 접근을 구현
    • Istio, Cilium 등의 서비스 메시 또는 CNI 플러그인을 도입하여 세밀한 네트워크 제어 적용

K08: Secrets Management Failures

  • 설명:
    Kubernetes Secret이 기본적으로 평문(base64 인코딩)으로 저장되거나, 부적절하게 관리되어 민감 정보가 노출되는 경우
  • 대응 방안:
    • etcd 암호화 기능을 활성화하여 시크릿 데이터를 암호화 저장
    • HashiCorp Vault, Sealed Secrets와 같은 외부 시크릿 관리 솔루션 활용
    • 접근 제어 및 감사 로깅을 통해 시크릿 사용 내역 모니터링

K09: Misconfigured Cluster Components

  • 설명:
    API 서버, kubelet, etcd 등 클러스터 핵심 구성 요소의 잘못된 설정으로 인한 취약점
  • 대응 방안:
    • CIS Benchmarks를 기반으로 정기적인 구성 감사 및 보안 패치 적용
    • kubelet의 익명 인증 비활성화(–anonymous-auth=false), API 서버와 etcd 간 TLS 통신 등 보안 설정 강화

K10: Outdated and Vulnerable Kubernetes Components

  • 설명:
    구버전 Kubernetes나 취약점이 알려진 구성 요소를 사용하는 경우
  • 대응 방안:
    • 정기적인 업데이트와 패치 관리, CVE 데이터베이스 모니터링
    • 자동화된 취약점 스캐닝 도구(예: kubescape, kubeclarity) 도입하여 위험 요소 식별 및 제거
profile
DevOps Engineer

0개의 댓글