13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] k8s 보안

  • [K8s] Pod Security Admission 1년 사용 후기 및 실수담

    [K8s] Pod Security Admission 1년 사용 후기 및 실수담

    K8s Pod Security Admission, 1년 사용 후기 및 실수담

    안녕하세요, 13년차 서버실 주인장입니다. 오늘은 Kubernetes(이하 K8s) 환경에서 보안을 한층 강화해주는 Pod Security Admission(PSA)에 대해 이야기해보려 합니다. 제가 운영하는 홈랩 환경에서 PSA를 도입한 지 어느덧 1년이 되었는데요, 처음에는 조금 헷갈렸지만 지금은 없어서는 안 될 기능이 되었답니다. 오늘은 1년 동안 PSA를 사용하면서 겪었던 시행착오와 함께, 어떻게 하면 좀 더 효율적으로 PSA를 활용할 수 있을지에 대한 경험을 솔직하게 공유해 드릴게요. 혹시 K8s 보안에 대해 고민하고 계셨다면, 오늘 제 이야기가 작게나마 도움이 되기를 바랍니다. 😊

    Kubernetes 클러스터의 전반적인 아키텍처와 Pod Security Admission이 어떤 위치에 있는지 보여주는 다이어그램

    K8s Pod Security Admission, 왜 필요할까요?

    K8s는 유연하고 강력한 컨테이너 오케스트레이션 도구이지만, 그만큼 보안 설정에 신경 써야 할 부분이 많습니다. 특히 Pod(파드)는 K8s의 가장 기본적인 배포 단위인데요, 이 Pod가 실행될 때 어떤 보안 정책을 따라야 하는지 명확하게 제어하지 않으면 예상치 못한 보안 취약점이 발생할 수 있습니다. 예를 들어, 특권(privileged) 컨테이너가 실수로 실행되거나, 호스트 파일 시스템에 접근하는 등의 위험한 상황이 생길 수 있죠.

    이런 문제를 해결하기 위해 K8s에서는 Pod Security Admission(PSA)이라는 기능을 제공합니다. 쉽게 말해, Pod를 생성하거나 업데이트할 때 미리 정의된 보안 기준에 부합하는지 자동으로 검사하고, 기준에 맞지 않으면 해당 Pod의 생성을 막아주는(Admission Controller) 기능이라고 생각하시면 됩니다. 💡

    Pod Security Admission, 어떻게 작동하나요?

    PSA는 K8s API 서버의 Admission Controller 중 하나로 작동합니다. Pod 생성 요청이 API 서버에 전달되면, PSA는 해당 Pod가 특정 Pod Security Standards(PSS)를 준수하는지 확인합니다. PSS에는 크게 세 가지 레벨이 있습니다:

    • Restricted (제한): 가장 엄격한 보안. Pod는 격리되고 제한된 권한만 가지며, 최신 보안 기능(예: Seccomp, AppArmor, SELinux)을 사용해야 합니다.
    • Baseline (기준): 최소한의 보안을 보장. 알려진 취약점을 악용하기 어려운 수준으로, 대부분의 워크로드에 권장됩니다.
    • Privileged (특권): 가장 낮은 수준의 보안. 컨테이너가 호스트 시스템에 대한 거의 모든 권한을 갖게 되므로, 매우 신중하게 사용해야 합니다.

    이 세 가지 레벨 외에도, 각 네임스페이스(Namespace)별로 Enforce, Audit, Warn 모드를 설정할 수 있습니다.

    • 1. Enforce (강제): 보안 정책을 위반하는 Pod의 생성을 차단합니다. 가장 강력한 모드죠.
    • 2. Audit (감사): 정책을 위반하더라도 Pod 생성을 차단하지는 않지만, 해당 이벤트를 로그로 기록합니다. 보안 감사에 유용합니다.
    • 3. Warn (경고): 정책을 위반하는 Pod에 대해 사용자에게 경고 메시지를 보냅니다. Pod 생성은 허용됩니다.

    실전! Pod Security Admission 설정하기 (제 경험담)

    제가 처음 PSA를 도입할 때 가장 헷갈렸던 부분이 바로 이 네임스페이스별 정책 설정이었습니다. 저희 홈랩에는 개발용, 테스트용, 운영용 등 다양한 환경의 네임스페이스가 있었기 때문에, 각기 다른 보안 정책을 적용하고 싶었거든요.

    K8s 클러스터 전체에 PSA를 활성화하는 것은 API 서버 설정에서 간단히 할 수 있습니다. 하지만 실제로는 각 네임스페이스별로 정책을 세밀하게 조정하는 것이 중요합니다. 저는 다음과 같은 방식으로 설정을 진행했습니다.

    1단계: 네임스페이스별 레이블 설정

    먼저, 각 네임스페이스에 어떤 보안 정책을 적용할지 명시하는 레이블을 붙여줍니다. 예를 들어, 보안이 중요한 운영 네임스페이스에는 pod-security.kubernetes.io/enforce=baseline과 같이 설정할 수 있습니다.

    kubectl label --overwrite ns production pod-security.kubernetes.io/enforce=baseline
    kubectl label --overwrite ns production pod-security.kubernetes.io/audit=baseline
    kubectl label --overwrite ns production pod-security.kubernetes.io/warn=baseline
    
    kubectl label --overwrite ns development pod-security.kubernetes.io/enforce=privileged
    kubectl label --overwrite ns development pod-security.kubernetes.io/audit=baseline
    kubectl label --overwrite ns development pod-security.kubernetes.io/warn=baseline
    
    네임스페이스별 Pod Security Admission 정책 설정 예시

    각 네임스페이스에 할당된 Pod Security Standards 레벨과 모드를 보여주는 예시 화면

    2단계: PSA 동작 확인 (Audit 모드 활용)

    처음부터 enforce 모드로 설정하면, 예상치 못한 Pod 배포 실패로 인해 서비스 장애가 발생할 수 있습니다. 그래서 저는 먼저 audit 모드를 활용하여 어떤 Pod들이 보안 정책을 위반하는지 파악하는 단계를 거쳤습니다. K8s API 서버 감시 로그를 주기적으로 확인하면서, 어떤 Pod가 어떤 이유로 위반되는지 분석했죠.

    💡 팁: kube-apiserver의 감시 로그(audit log)를 통해 PSA 관련 감사 정보를 확인할 수 있습니다. 로컬 클러스터에서는 kubectl describe nodes 또는 클러스터 설정에 따라 로그 파일에서 감시 로그를 조회할 수 있습니다.

    3단계: Enforce 모드로 전환 및 검증

    Audit 모드를 통해 문제를 파악하고 수정했다면, 이제 enforce 모드로 전환할 차례입니다. enforce 모드로 전환한 후, 중요한 워크로드부터 순차적으로 배포해보면서 문제가 없는지 꼼꼼하게 검증했습니다.

    kubectl label --overwrite ns production pod-security.kubernetes.io/enforce=baseline
    

    Pod Security Admission 정책을 위반했을 때 API 서버 로그에 기록되는 내용

    1년간 사용해보니… 삽질과 깨달음

    PSA를 1년 가까이 사용하면서 정말 많은 것을 배웠습니다. 처음에는 단순히 PSS 레벨을 설정하면 되는 줄 알았는데, 실제로는 Pod의 설정 하나하나가 PSS와 충돌할 수 있다는 것을 깨달았죠.

    가장 흔하게 겪었던 실수담은 바로 privileged: true 설정이었습니다. 저희 팀에서 사용하는 특정 사이드카(Sidecar) 컨테이너가 네트워킹 관련 기능을 위해 이 설정을 필요로 했는데, restricted 또는 baseline PSS에서는 당연히 막히더라고요. 처음에는 왜 Pod 생성이 안 되는지 한참을 헤맸습니다. 😂

    이런 문제를 해결하기 위해 다음과 같은 방법을 사용했습니다:

    • Pod Security Admission 이해하기: Pod Security Policies(PSP)는 K8s 1.25에서 deprecated 되었고 1.28에서 완전히 제거되었습니다. 대신 PSA로 전환하는 과정에서, PSA는 훨씬 간결하고 명확하게 정책을 적용할 수 있다는 걸 체감했습니다.
    • Pod Spec 검토 및 수정: 사이드카 컨테이너의 Pod Spec을 면밀히 검토하여, privileged: true 설정 없이도 동일한 기능을 구현할 수 있는지 확인했습니다. 결국, 필요한 권한만 최소한으로 부여하도록 수정하여 baseline PSS를 만족시킬 수 있었습니다.
    • Audit 모드를 적극 활용: 새로운 애플리케이션을 배포하거나 기존 설정을 변경할 때, 바로 enforce 모드로 전환하기보다는 audit 모드로 먼저 테스트하면서 잠재적인 충돌을 미리 파악하는 습관을 들였습니다.

    PSA는 K8s 클러스터의 보안 수준을 크게 향상시켜주는 강력한 기능입니다. 하지만 모든 Pod가 완벽하게 PSS를 준수하는 것은 아니므로, Service Account, RBAC(Role-Based Access Control)와 함께 종합적으로 고려하여 보안 전략을 수립하는 것이 중요합니다.

    Pod Security Admission과 Pod Security Policy의 주요 차이점 비교

    Pod Security Admission과 이전의 Pod Security Policy의 주요 차이점을 비교한 표

    결론: K8s 보안, PSA로 한 단계 업그레이드하세요!

    Pod Security Admission은 K8s 환경의 보안을 강화하는 데 필수적인 요소입니다. 1년간의 경험을 통해 PSA가 단순히 복잡한 설정이 아니라, 실질적인 보안 위협을 줄여주는 강력한 방어선이라는 것을 체감했습니다.

    물론 초기 설정 과정에서 시행착오를 겪을 수 있습니다. 하지만 audit 모드를 활용하고, Pod Spec을 꼼꼼히 검토하는 습관을 들인다면, 충분히 안정적으로 PSA를 운영할 수 있더라고요.

    혹시 아직 PSA를 도입하지 않으셨다면, 지금 바로 시작해보시는 것을 강력히 추천합니다! 먼저 개발 네임스페이스부터 baseline PSS로 설정하고 audit 모드로 운영해보면서 점차 확대해나가는 것을 권장합니다.

    다음 글에서는 K8s 네트워크 보안의 또 다른 핵심 요소인 Network Policy에 대해 다뤄볼 예정이니, 많은 기대 부탁드립니다! 😉

  • [k8s] 쿠버네티스 보안 강화: 베스트 프랙티스 가이드

    쿠버네티스 보안, 왜 지금 더 중요해졌나요?

    솔직히 말씀드리면, 저도 처음 쿠버네티스를 도입했을 때는 “일단 돌아가면 됐지”라는 마음이 컸어요. Pod가 뜨고, 서비스가 노출되고, 배포 파이프라인이 연결되면 그걸로 충분하다고 생각했거든요. 근데 운영 2년차쯤 됐을 때 실제로 클러스터 하나가 크립토마이닝 공격에 당하는 걸 목격하고 나서… 그때부터 쿠버네티스 보안을 진지하게 공부하기 시작했습니다.

    최근 들어 클라우드 네이티브 환경이 보편화되면서 쿠버네티스(Kubernetes) 클러스터를 겨냥한 공격도 눈에 띄게 늘었어요. 잘못 설정된 RBAC(Role-Based Access Control, 역할 기반 접근 제어), 노출된 API 서버, 권한 과잉 서비스 계정… 이런 것들이 실제로 침해 사고로 이어지는 경우가 많더라고요.

    이 글에서는 제가 13년간 인프라를 운영하면서 직접 적용해보고, 실제로 효과를 확인한 쿠버네티스 보안 베스트 프랙티스를 정리해드릴게요. 개념만 나열하는 게 아니라 실제 적용 가능한 YAML 설정과 명령어도 함께 다룰 겁니다.

    ▲ 쿠버네티스 클러스터의 주요 보안 레이어 — API 서버, RBAC, 네트워크 정책, Pod 보안이 어떻게 계층적으로 동작하는지 보여주는 아키텍처 다이어그램


    쿠버네티스 보안의 핵심 개념 먼저 짚고 가기

    쿠버네티스 보안은 크게 4가지 영역으로 나뉘어요. 흔히 “4C 보안 모델”이라고 부르는데, 쉽게 말해 Cloud → Cluster → Container → Code 순서로 각 레이어를 지켜야 한다는 개념이에요.

    레이어 설명 주요 관리 포인트
    Cloud 클라우드 인프라 수준 보안 IAM, VPC, 방화벽, 노드 OS 보안
    Cluster 쿠버네티스 클러스터 수준 보안 API 서버 접근 제어, RBAC, Audit 로깅
    Container 컨테이너 런타임 수준 보안 이미지 취약점 스캔, securityContext 설정
    Code 애플리케이션 코드 수준 보안 시크릿 관리, TLS 통신, 의존성 취약점

    이 중에서 Cluster와 Container 레이어가 실제로 가장 많이 놓치는 부분이에요. Cloud는 CSP(클라우드 서비스 제공자)가 어느 정도 기본 보호를 해주고, Code는 개발팀이 챙기는 경우가 많은데, 정작 클러스터 내부 설정은 인프라팀도 개발팀도 서로 남의 일이라고 생각하는 경우가 많거든요. 제가 딱 그랬었어요 ㅎㅎ.


    RBAC 설정: 최소 권한 원칙을 철저히 지켜라

    RBAC(Role-Based Access Control)는 쿠버네티스 보안의 핵심 중 핵심입니다. “필요한 권한만, 필요한 리소스에만”이라는 최소 권한 원칙(Principle of Least Privilege)을 RBAC로 구현하는 거예요.

    흔히 보이는 실수가 뭔지 아세요? 빠르게 개발하려고 ServiceAccount에 cluster-admin 권한을 줘버리는 거예요. 저도 초반에 “일단 개발 환경이니까”라며 그냥 넘어간 적이 있는데, 그 습관이 프로덕션까지 이어지면 진짜 큰일 납니다.

    나쁜 예시 — 절대 이렇게 하지 마세요

    # ⚠️ 절대 금지: 모든 권한을 서비스 계정에 부여
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: dangerous-binding
    subjects:
    - kind: ServiceAccount
      name: my-app
      namespace: default
    roleRef:
      kind: ClusterRole
      name: cluster-admin  # 이거 쓰면 안 됩니다!
      apiGroup: rbac.authorization.k8s.io
    

    좋은 예시 — 최소 권한으로 Role 정의하기

    # ✅ 권장: 특정 네임스페이스의 특정 리소스에만 접근 허용
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: production
      name: pod-reader
    rules:
    - apiGroups: [""]  # core API 그룹
      resources: ["pods", "pods/log"]
      verbs: ["get", "list", "watch"]  # 읽기 전용만 허용
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: read-pods
      namespace: production
    subjects:
    - kind: ServiceAccount
      name: monitoring-agent
      namespace: production
    roleRef:
      kind: Role
      name: pod-reader
      apiGroup: rbac.authorization.k8s.io
    

    💡 팁: 현재 클러스터에서 과도한 권한이 있는 바인딩을 빠르게 확인하려면 아래 명령어를 써보세요.

    # cluster-admin 권한을 가진 바인딩 전체 조회
    kubectl get clusterrolebindings -o json | \
      jq '.items[] | select(.roleRef.name == "cluster-admin") | .metadata.name'
    
    # 특정 서비스 계정의 권한 확인
    kubectl auth can-i --list --as=system:serviceaccount:production:my-app
    

    네트워크 정책으로 Pod 간 통신 제어하기

    기본적으로 쿠버네티스 클러스터 내 모든 Pod는 서로 통신할 수 있어요. 이게 편리하긴 한데, 보안 관점에서는 꽤 위험한 기본값이에요. 만약 하나의 Pod가 침해당하면 클러스터 내 모든 서비스로 횡적 이동(Lateral Movement)이 가능하거든요.

    NetworkPolicy(네트워크 정책)는 Pod 간 또는 Pod와 외부 간의 트래픽을 화이트리스트 방식으로 제어하는 k8s 리소스예요. 처음엔 이게 뭔가 복잡해 보였는데, 개념만 잡으면 생각보다 직관적이더라고요.

    기본 원칙: 먼저 모든 트래픽 차단 후 필요한 것만 열기

    # 1단계: 특정 네임스페이스의 모든 인바운드/아웃바운드 트래픽 차단
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: default-deny-all
      namespace: production
    spec:
      podSelector: {}  # 네임스페이스 내 모든 Pod에 적용
      policyTypes:
      - Ingress
      - Egress
    
    # 2단계: 필요한 트래픽만 허용 (예: frontend -> backend 통신)
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-frontend-to-backend
      namespace: production
    spec:
      podSelector:
        matchLabels:
          app: backend  # 이 정책이 적용될 Pod
      policyTypes:
      - Ingress
      ingress:
      - from:
        - podSelector:
            matchLabels:
              app: frontend  # frontend Pod에서 오는 트래픽만 허용
        ports:
        - protocol: TCP
          port: 8080
    

    ⚠️ 주의사항: NetworkPolicy는 CNI(Container Network Interface) 플러그인이 지원해야 동작해요. Calico, Cilium, Weave Net 등은 지원하지만, 기본 flannel은 NetworkPolicy를 지원하지 않아요. 클러스터 구성 전에 꼭 확인하세요!

    ▲ NetworkPolicy 적용 전후 Pod 간 트래픽 흐름 비교 — 기본 개방 상태와 화이트리스트 방식 적용 후 허용된 경로만 표시된 다이어그램


    컨테이너 보안 컨텍스트 설정하기

    컨테이너 보안에서 제일 많이 놓치는 부분이 바로 SecurityContext(시큐리티 컨텍스트)예요. 이 설정 하나만 제대로 해도 컨테이너 탈출(Container Escape) 공격을 상당 부분 방어할 수 있거든요.

    제가 보안 감사를 해드린 한 팀의 클러스터를 보니까, 거의 모든 Pod가 root 권한으로 실행되고 있었어요. 개발 편의를 위해 그렇게 설정했다고 하는데, 그건 컨테이너 안에서 root 권한을 얻은 공격자가 호스트 노드까지 공격할 수 있는 발판을 주는 거나 마찬가지예요.

    apiVersion: v1
    kind: Pod
    metadata:
      name: secure-pod
      namespace: production
    spec:
      securityContext:
        runAsNonRoot: true          # root로 실행 금지
        runAsUser: 1000             # 특정 UID로 실행
        runAsGroup: 3000            # 특정 GID로 실행
        fsGroup: 2000               # 볼륨 파일시스템 그룹
        seccompProfile:
          type: RuntimeDefault      # 기본 seccomp 프로파일 적용
      containers:
      - name: app
        image: my-app:1.0.0
        securityContext:
          allowPrivilegeEscalation: false  # 권한 상승 금지 (핵심!)
          readOnlyRootFilesystem: true     # 루트 파일시스템 읽기 전용
          capabilities:
            drop:
            - ALL                          # 모든 Linux 기능(capability) 제거
            add:
            - NET_BIND_SERVICE             # 필요한 것만 다시 추가
        resources:
          limits:
            cpu: "500m"
            memory: "128Mi"
          requests:
            cpu: "250m"
            memory: "64Mi"
    

    💡 핵심 포인트! allowPrivilegeEscalation: false는 반드시 설정하세요. 이 설정이 없으면 컨테이너 내부에서 sudo나 setuid 바이너리를 통해 권한 상승이 가능해요.

    Pod Security Admission으로 클러스터 전체에 정책 적용하기

    쿠버네티스 1.25부터 기존의 PodSecurityPolicy(PSP)가 제거되고 Pod Security Admission(PSA)이 정식 출시됐어요. 네임스페이스 레벨에서 보안 프로파일을 강제할 수 있는데, 세 가지 레벨이 있어요.

    레벨 설명 적용 권장 환경
    privileged 제한 없음 (기본값) 시스템 네임스페이스 (kube-system 등)
    baseline 최소한의 보안 제한 적용 일반 애플리케이션 네임스페이스
    restricted 가장 강력한 보안 제한 보안이 중요한 프로덕션 환경
    # 네임스페이스에 PSA 레벨 적용 (enforce: 위반 시 Pod 생성 거부)
    kubectl label namespace production \
      pod-security.kubernetes.io/enforce=restricted \
      pod-security.kubernetes.io/enforce-version=latest
    
    # warn: 경고만 (생성은 허용), audit: 감사 로그만 기록
    kubectl label namespace staging \
      pod-security.kubernetes.io/warn=baseline \
      pod-security.kubernetes.io/audit=restricted
    

    시크릿 관리와 etcd 암호화

    이건 진짜 많은 분들이 모르고 지나치는 부분인데요. 쿠버네티스 Secret은 기본적으로 암호화되지 않은 채로 etcd에 저장돼요. Base64 인코딩이 되어 있긴 하지만, 이건 암호화가 아니라 그냥 인코딩이에요. etcd에 직접 접근하면 바로 읽을 수 있거든요.

    # etcd에서 시크릿 평문 확인 (이게 되면 안 되는 거예요!)
    ETCDCTL_API=3 etcdctl get /registry/secrets/default/my-secret \
      --endpoints=https://127.0.0.1:2379 \
      --cacert=/etc/kubernetes/pki/etcd/ca.crt \
      --cert=/etc/kubernetes/pki/etcd/server.crt \
      --key=/etc/kubernetes/pki/etcd/server.key | hexdump -C
    

    etcd 암호화 설정하기

    # /etc/kubernetes/encryption-config.yaml
    apiVersion: apiserver.config.k8s.io/v1
    kind: EncryptionConfiguration
    resources:
    - resources:
      - secrets
      - configmaps  # configmap도 같이 암호화 권장
      providers:
      - aescbc:     # AES-CBC 암호화 방식
          keys:
          - name: key1
            secret: 
      - identity: {}  # 암호화 안 된 기존 데이터 읽기 위해 fallback
    
    # kube-apiserver에 암호화 설정 파일 적용 (kubeadm 기준)
    # /etc/kubernetes/manifests/kube-apiserver.yaml에 아래 플래그 추가
    # --encryption-provider-config=/etc/kubernetes/encryption-config.yaml
    
    # 기존 시크릿 모두 재암호화 (설정 후 반드시 실행!)
    kubectl get secrets --all-namespaces -o json | kubectl replace -f -
    

    ⚠️ 중요: 암호화 키는 반드시 안전하게 보관하세요. 키를 잃어버리면 모든 시크릿을 복구할 수 없어요. 실제 프로덕션에서는 AWS KMS, HashiCorp Vault, Azure Key Vault 같은 외부 키 관리 서비스(KMS)와 연동하는 걸 강력히 권장합니다.


    감사 로깅과 런타임 보안 모니터링

    보안은 예방도 중요하지만, 이상 행동을 빠르게 탐지하는 것도 똑같이 중요해요. Audit Logging(감사 로깅)을 설정하면 API 서버에 대한 모든 요청을 기록할 수 있어요.

    # /etc/kubernetes/audit-policy.yaml
    apiVersion: audit.k8s.io/v1
    kind: Policy
    rules:
    # 시크릿 접근은 반드시 RequestResponse 레벨로 상세 기록
    - level: RequestResponse
      resources:
      - group: ""
        resources: ["secrets"]
    
    # 인증 실패 이벤트 기록
    - level: Request
      users: ["system:anonymous"]
    
    # exec 명령어 실행 기록 (공격자가 주로 사용)
    - level: RequestResponse
      resources:
      - group: ""
        resources: ["pods/exec", "pods/attach", "pods/portforward"]
    
    # 그 외 일반 요청은 메타데이터만 기록
    - level: Metadata
      omitStages:
      - RequestReceived
    

    런타임 보안 모니터링 도구로는 Falco를 많이 사용해요. Falco는 CNCF(Cloud Native Computing Foundation) 프로젝트로, 커널 시스템 콜을 분석해서 컨테이너 내부의 이상 행동을 실시간으로 탐지해줘요.

    # Helm으로 Falco 설치
    helm repo add falcosecurity https://falcosecurity.github.io/charts
    helm repo update
    helm install falco falcosecurity/falco \
      --namespace falco \
      --create-namespace \
      --set falco.grpc.enabled=true \
      --set falco.grpc_output.enabled=true
    
    # Falco 로그 확인 (이상 탐지 이벤트)
    kubectl logs -l app.kubernetes.io/name=falco -n falco -f
    

    ▲ Falco 런타임 보안 모니터링 — 컨테이너 내부의 의심스러운 시스템 콜과 이상 행동이 실시간으로 탐지되는 대시보드 예시


    이미지 보안: 공급망 공격 방어

    최근 몇 년간 컨테이너 이미지를 통한 공급망 공격이 크게 늘었어요. 신뢰할 수 없는 이미지를 클러스터에 배포하면 그 자체가 침해의 시작이 될 수 있거든요.

    • ✅ 이미지 취약점 스캔: Trivy, Grype 같은 도구로 CI/CD 파이프라인에서 이미지 스캔 필수화
    • ✅ 이미지 서명 검증: Cosign + Sigstore로 이미지 서명 및 검증 (공급망 무결성 보장)
    • ✅ 신뢰할 수 있는 레지스트리만 허용: Admission Webhook으로 허용된 레지스트리 이미지만 배포 가능하도록 제한
    • ✅ latest 태그 금지: 이미지 버전을 명확하게 고정 (mutable tag는 보안 위험)
    • ✅ distroless 또는 minimal 이미지 사용: 불필요한 바이너리가 없는 이미지를 쓰면 공격 표면 자체가 줄어요
    # Trivy로 이미지 취약점 스캔
    trivy image --severity HIGH,CRITICAL nginx:1.25.3
    
    # Cosign으로 이미지 서명
    cosign sign --key cosign.key my-registry.io/my-app:1.0.0
    
    # Cosign으로 이미지 서명 검증
    cosign verify --key cosign.pub my-registry.io/my-app:1.0.0
    

    전체 보안 체크리스트 정리 및 다음 단계

    ▲ 쿠버네티스 보안 베스트 프랙티스 전체 체크리스트 — RBAC, 네트워크 정책, 컨테이너 보안, 시크릿 관리, 모니터링 항목이 단계별로 정리된 요약 인포그래픽

    여기까지 꽤 많은 내용을 다뤘는데요, 핵심을 정리해드릴게요.

    1. RBAC 최소 권한 원칙 — cluster-admin은 진짜 필요한 경우에만, 서비스 계정은 네임스페이스 범위 Role로 제한
    2. 네트워크 정책(k8s 보안의 방화벽) — 기본 차단 후 필요한 트래픽만 허용, CNI 지원 여부 먼저 확인
    3. SecurityContext 설정 — root 실행 금지, 권한 상승 차단, 읽기 전용 파일시스템 적용
    4. etcd 암호화 — Secret은 반드시 암호화, 가능하면 외부 KMS 연동
    5. 감사 로깅 + 런타임 모니터링 — 예방만큼 탐지도 중요, Falco 도입 검토
    6. 이미지 보안 — 스캔, 서명, 신뢰 레지스트리 제한까지 CI/CD에 통합

    처음부터 모든 걸 한 번에 적용하려고 하면 오히려 지쳐서 포기하게 돼요. 제 경험상 RBAC 정리 → NetworkPolicy → SecurityContext 순서로 하나씩 적용해나가는 게 가장 현실적이더라고요.

    다음 글에서는 OPA Gatekeeper를 활용한 쿠버네티스 정책 자동화를 다룰 예정이에요. Admission Webhook으로 보안 정책을 코드로 관리하는 방법인데, 이걸 도입하면 위에서 설명한 SecurityContext 설정 같은 것들을 개발자가 실수로 빠뜨려도 자동으로 차단하거나 수정할 수 있거든요. 꽤 강력합니다.

    혹시 이 글 읽으면서 “우리 클러스터 이거 안 돼 있는데…” 싶은 항목 있으셨나요? 댓글로 공유해주시면 같이 고민해볼게요. 저도 아직 배우는 중이거든요 😄


    자주 묻는 질문 (FAQ)

    Q. RBAC 설정이 복잡한데, 자동으로 감사하는 도구가 있나요?

    네! rbac-tool이나 kubectl-who-can 같은 플러그인을 사용하면 현재 클러스터의 RBAC 설정을 시각화하고 과도한 권한을 쉽게 찾을 수 있어요. kubectl krew install rbac-tool로 설치할 수 있습니다.

    Q. 관리형 쿠버네티스(EKS, GKE, AKS)를 쓰면 보안 설정이 덜 필요한가요?

    아니요. 관리형 서비스는 컨트롤 플레인(마스터 노드) 보안을 CSP가 담당하지만, RBAC, NetworkPolicy, SecurityContext, 시크릿 관리 같은 워크로드 수준의 보안은 여전히 사용자 책임이에요. 오히려 관리형이라고 방심하는 경우가 더 위험할 수 있어요.

    Q. 컨테이너 보안 스캔은 언제 하는 게 좋나요?

    이상적으로는 Shift Left 보안 원칙에 따라 개발자 로컬 환경 → CI 파이프라인 → 레지스트리 푸시 전 → 배포 전 총 4단계에서 스캔하는 게 좋아요. 최소한 CI 파이프라인에는 반드시 포함시키세요.