13년차의 서버실

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

[태그:] 네임스페이스 보안

  • [Kubernetes] Kubernetes PodSecurity 도입 전후 비교: 보안 강화 사례 연구

    [Kubernetes] Kubernetes PodSecurity 도입 전후 비교: 보안 강화 사례 연구

    [Kubernetes] Kubernetes PodSecurity 도입 전후 비교: 보안 강화 사례 연구

    Kubernetes PodSecurity 도입을 고민하시는 분들은 아마 한 번쯤 이런 순간이 있으셨을 겁니다. 워크로드는 잘 돌아가는데, 막상 보안 점검을 해보면 privileged(특권 모드) 컨테이너가 섞여 있거나, hostPath(호스트 경로 마운트) 같은 위험한 설정이 아무 제어 없이 배포되는 경우 말이죠. 저도 처음엔 “네임스페이스만 잘 나누면 되지 않을까?” 싶었는데, 실제로 운영 환경과 홈랩에서 계속 만져보니 결국 배포 시점의 기본 보안 가드레일이 있어야 하더라고요. 그래서 이번 글에서는 Kubernetes PodSecurity 도입 전후를 어떻게 비교했는지, 어떤 문제가 줄었는지, 그리고 적용하면서 어디서 삽질했는지 경험 기반으로 정리해보겠습니다.

    특히 이 글은 Kubernetes 보안, Pod Security Standards(파드 보안 표준), 보안 정책을 실제 운영에 녹이는 관점으로 읽으시면 도움이 됩니다. 이론만 설명하는 글이 아니라, 제가 직접 해보니 어디서 걸리고 어떤 기준으로 정리해야 덜 힘든지 그 흐름을 보여드릴게요.

    PodSecurity 도입 전에는 제어가 느슨하고, 도입 후에는 네임스페이스 정책과 허용 범위가 명확해진 구조를 한눈에 보여주는 개요 이미지입니다.

    Kubernetes PodSecurity 도입이 왜 중요한가요

    쉽게 말해 PodSecurity는 “이 파드(Pod)는 어디까지 위험한 설정을 써도 되는가”를 네임스페이스 단위로 관리하는 방식입니다. 예전에는 팀마다 매니페스트를 제각각 작성하다 보니, 어떤 워크로드는 runAsNonRoot가 잘 들어가 있고, 어떤 건 아예 빠져 있고, 또 어떤 건 디버깅한다고 privileged: true를 넣어둔 채 남아 있기도 했습니다. 이게 한두 개면 눈으로 보겠는데, 서비스가 늘어나면 사람의 기억으로 통제하는 건 불가능하더라고요.

    여기서 중요한 포인트! 보안은 좋은 설정을 권장하는 것만으로는 부족합니다. 실제로는 잘못된 설정이 들어왔을 때 막아줘야 합니다. 제가 현장에서 느낀 것도 그거였습니다. 리뷰에서 빠지고, 급한 장애 대응 중엔 원칙이 밀리고, 결국 가장 약한 워크로드가 전체 클러스터 위험도를 끌어올리거든요.

    Pod Security Standards(파드 보안 표준)를 먼저 이해해야 합니다

    Pod Security Standards는 파드 보안 수준을 세 단계로 나눠서 생각하게 해줍니다. 저도 처음엔 이름만 보고 좀 딱딱하다고 느꼈는데, 실제로 써보니까 기준점이 분명해서 오히려 팀 합의가 빨라졌습니다.

    수준 설명 적합한 상황
    Privileged 제한이 거의 없는 수준입니다. 특수한 시스템 워크로드, 아주 제한적인 운영 도구
    Baseline 명백히 위험한 설정을 막는 기본선입니다. 일반적인 애플리케이션 네임스페이스의 첫 단계
    Restricted 가장 엄격한 수준으로, 안전한 기본값을 강하게 요구합니다. 보안 민감 서비스, 표준화가 잘 된 앱 워크로드

    제가 보통 권하는 방식은 이렇습니다.

    • 처음부터 전부 Restricted로 밀어붙이지 않습니다.
    • 기존 레거시 워크로드가 많다면 먼저 Baseline으로 현재 상태를 정리합니다.
    • 새로 만드는 네임스페이스나 표준화된 앱은 Restricted를 기본으로 잡습니다.

    이 접근이 중요한 이유는, 보안 정책은 강하면 좋은 게 아니라 운영에 정착해야 좋은 것이기 때문입니다. 너무 급하게 올리면 예외만 늘어나고 결국 정책이 무력화되더라고요.

    도입 전 환경에서 실제로 보였던 문제들

    제가 PodSecurity를 넣기 전에 먼저 한 일은 “무슨 설정이 돌아다니고 있는지”를 보는 것이었습니다. 막연히 위험할 것 같다가 아니라, 실제 매니페스트와 실행 중인 파드를 기준으로 봐야 하거든요. 그때 자주 보였던 문제는 아래와 같았습니다.

    • securityContext가 아예 없는 배포가 생각보다 많았습니다.
    • allowPrivilegeEscalation 설정이 빠져 있었습니다.
    • 루트(root) 권한 기반 이미지가 관성적으로 사용되고 있었습니다.
    • 운영 중 잠깐 쓰려고 만든 디버그용 파드가 그대로 남아 있었습니다.
    • 예외가 문서화되지 않아, 왜 허용했는지 아무도 설명 못 하는 설정이 있었습니다.

    이런 상태에서 보안 점검이 들어오면 굉장히 피곤해집니다. “왜 이 컨테이너는 루트로 뜨나요?” 같은 질문이 나오면, 실제 이유가 있어서가 아니라 그냥 기본값이라서 그런 경우가 많거든요. 사실 제일 무서운 건 악의적인 공격보다도 무심코 허용된 기본값입니다.

    Kubernetes PodSecurity 도입 절차: 제가 실제로 밟은 순서

    여기서는 복잡하게 가지 않고, 운영에서 비교적 덜 아픈 순서로 설명해볼게요. 핵심은 한 번에 차단(enforce)하지 말고 먼저 관찰부터 하는 겁니다.

    1. 보호할 네임스페이스를 분류합니다.
    2. audit(감사)와 warn(경고) 중심으로 먼저 적용합니다.
    3. 실패하는 워크로드를 수정합니다.
    4. 문제가 없는 네임스페이스부터 enforce(강제)로 전환합니다.
    5. 예외 워크로드는 별도 네임스페이스로 분리합니다.

    예를 들어 애플리케이션용 네임스페이스에 먼저 Baseline 경고와 감사 정책을 걸어볼 수 있습니다.

    kubectl label namespace app-team \
      pod-security.kubernetes.io/audit=baseline \
      pod-security.kubernetes.io/warn=baseline --overwrite

    이 상태에서는 배포가 바로 막히지는 않지만, 어떤 설정이 기준을 벗어나는지 확인하기 좋아요. 저는 처음부터 차단했다가 CI/CD 파이프라인이 우르르 깨지는 바람에 한 번 크게 삽질했었습니다. 그 뒤로는 무조건 경고와 감사부터 봅니다.

    조금 정리됐다 싶으면 강제로 올립니다.

    kubectl label namespace app-team \
      pod-security.kubernetes.io/enforce=baseline \
      pod-security.kubernetes.io/enforce-version=latest --overwrite

    운영에서는 latest 대신 조직에서 검증한 기준 버전을 명시적으로 관리하는 팀도 많습니다. 저는 팀 표준이 아직 흔들릴 때는 버전 기준을 문서화해두는 쪽이 더 낫다고 봅니다. 기준이 자주 바뀌면 개발팀이 체감상 더 힘들어하거든요.

    Kubernetes PodSecurity 도입 시 네임스페이스 정책 적용 흐름 이미지

    네임스페이스에 audit, warn, enforce 라벨을 붙이면서 단계적으로 정책을 강화하는 흐름을 설명하는 이미지입니다.

    Restricted(제한) 수준을 목표로 할 때 매니페스트 예시

    다음은 비교적 안전한 기본 형태의 예시입니다. 모든 앱이 이대로 되진 않겠지만, 팀 표준의 시작점으로 잡기 좋습니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: web-app
      namespace: app-team
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: web-app
      template:
        metadata:
          labels:
            app: web-app
        spec:
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          containers:
            - name: web
              image: nginx:stable
              ports:
                - containerPort: 80
              securityContext:
                allowPrivilegeEscalation: false
                capabilities:
                  drop:
                    - ALL

    여기서 자주 보는 포인트는 아래입니다.

    • runAsNonRoot: true로 비루트 실행을 강제합니다.
    • allowPrivilegeEscalation: false로 권한 상승 가능성을 줄입니다.
    • capabilities.drop: [ALL]로 불필요한 리눅스 capability(리눅스 커널 권한 집합)를 제거합니다.
    • seccompProfile.type: RuntimeDefault로 기본 시스템 호출 필터를 사용합니다.

    도입 전후 비교: 무엇이 달라졌나

    정량 수치를 억지로 붙이기보다, 운영 체감 기준으로 말씀드리는 게 더 정확할 것 같습니다. Kubernetes PodSecurity 도입 전에는 “문제 있는 매니페스트가 배포된 뒤 나중에 발견되는 구조”였다면, 도입 후에는 “기준에 맞지 않으면 배포 단계에서 바로 드러나는 구조”로 바뀌었습니다. 이 차이가 생각보다 큽니다.

    비교 항목 도입 전 도입 후
    보안 기준 문서나 리뷰에 의존 네임스페이스 정책으로 강제
    위험 설정 발견 시점 배포 후 또는 점검 시 배포 직전 또는 배포 중
    팀 간 일관성 사람마다 다름 정책 기준으로 통일
    예외 관리 구두 합의가 많음 별도 네임스페이스와 문서로 관리

    제가 직접 해보니 제일 편했던 건, 리뷰에서 감정 소모가 줄어든다는 점이었습니다. 예전엔 “이 설정 위험하지 않나요?” 같은 대화가 사람 대 사람의 의견 충돌처럼 번질 때가 있었는데, 정책을 두고 나면 “이건 Baseline 기준에서 걸립니다”처럼 훨씬 명확해집니다. 이거 진짜 편하더라고요.

    ⚠️ 적용하면서 많이 막혔던 문제와 해결 방법

    이 섹션은 꼭 넣고 싶었습니다. 문서만 보면 간단해 보이는데, 실제로는 여기서 다들 한 번씩 막히거든요.

    1. 기존 이미지가 non-root 실행을 전제로 만들어지지 않은 경우

    Restricted 수준으로 올리면 가장 먼저 터지는 부분 중 하나입니다. 애플리케이션은 문제 없어 보여도, 이미지 내부 디렉터리 권한이나 엔트리포인트 스크립트가 루트 권한을 전제하는 경우가 있습니다. 저도 처음엔 “분명 앱은 잘 뜨는데 왜 이게 안 되지?” 싶었는데, 알고 보니 컨테이너 시작 시 쓰기 권한이 필요한 경로가 있었어요.

    이럴 때는 아래 순서로 봤습니다.

    1. 이미지가 비루트 실행을 지원하는지 확인합니다.
    2. 쓰기 경로가 꼭 필요한지 줄입니다.
    3. 필요하면 Dockerfile 단계에서 권한을 정리합니다.
    4. 정말 예외가 필요한 워크로드만 별도 분리합니다.

    2. 운영 도구와 일반 앱을 같은 기준으로 묶은 경우

    로그 수집기, CNI 관련 컴포넌트, 노드 접근이 필요한 에이전트는 일반 앱과 요구 조건이 다를 수 있습니다. 그런데 이걸 한 네임스페이스 정책으로 퉁치면 꼭 어딘가서 충돌이 납니다. 저는 한동안 “왜 어떤 건 꼭 예외가 생기지?” 하다가, 결국 애플리케이션 네임스페이스와 인프라 네임스페이스를 분리하면서 정리가 되더라고요.

    3. warn만 보고 끝내는 경우

    이건 진짜 자주 봅니다. 경고는 보이는데 바빠서 미루다 보면, 3개월 뒤에도 같은 경고가 그대로 쌓여 있어요. 그래서 저는 warn → audit → enforce 전환 일정을 미리 잡아두는 편입니다. 일정이 없으면 정책은 거의 장식품이 됩니다.

    Kubernetes PodSecurity 도입 후 경고와 배포 실패 분석 이미지

    경고 단계에서 어떤 항목이 걸리는지 확인하고, enforce 전환 전에 수정 포인트를 찾는 과정을 보여주는 이미지입니다.

    검증은 이렇게 했습니다

    보안 정책은 넣는 것보다 검증이 더 중요합니다. 정책이 존재해도 실제로 막히지 않으면 의미가 없으니까요. 제가 보통 하는 검증은 두 가지입니다. 하나는 정상 매니페스트가 잘 배포되는지, 다른 하나는 의도적으로 위험한 설정을 넣었을 때 차단되는지 확인하는 겁니다.

    예를 들어 아래처럼 위험한 설정이 들어간 테스트 파드를 만들어 봅니다.

    apiVersion: v1
    kind: Pod
    metadata:
      name: privileged-test
      namespace: app-team
    spec:
      containers:
        - name: test
          image: busybox:1.36
          command: ["sh", "-c", "sleep 3600"]
          securityContext:
            privileged: true

    그리고 배포를 시도합니다.

    kubectl apply -f privileged-test.yaml

    정상이라면 보안 정책 위반으로 거부되는 흐름이 나와야 합니다. 반대로, 팀 표준 매니페스트는 무리 없이 통과해야 하고요. 여기서 중요한 건 단순히 “막혔다”가 아니라, 왜 막혔는지 개발자도 이해할 수 있어야 한다

    추가로 확인했던 항목은 아래와 같습니다.

    • 새 네임스페이스 생성 시 기본 라벨 정책이 누락되지 않는지
    • CI/CD에서 배포 실패 메시지가 충분히 읽히는지
    • 예외 네임스페이스가 무분별하게 늘어나지 않는지
    • 운영 문서와 실제 클러스터 라벨 상태가 일치하는지
    Kubernetes PodSecurity 도입 후 배포 검증 결과 이미지

    정상 배포와 정책 위반 배포가 어떻게 구분되는지, 운영자가 어떤 식으로 결과를 확인하는지 보여주는 이미지입니다.

    운영 기준을 문서화해야 도입이 끝납니다

    사실 PodSecurity는 라벨 몇 개 붙인다고 끝나지 않습니다. 진짜 끝은 팀 운영 기준이 문서로 남고, 다음 사람도 같은 방식으로 적용할 수 있을 때입니다. 저도 처음엔 클러스터에만 반영해두고 안심했었는데, 시간이 지나니 “이 네임스페이스는 왜 baseline이지?” 같은 질문이 계속 나오더라고요.

    그래서 저는 아래 항목을 최소 문서 세트로 남깁니다.

    • 네임스페이스별 목표 수준: baseline 또는 restricted
    • 예외 허용 기준: 누가 승인하고 언제 재검토하는지
    • 개발팀용 체크리스트: 보안 컨텍스트 기본 예시
    • 배포 실패 시 확인 순서: 어떤 필드를 먼저 볼지

    혹시 이런 경험 있으신가요? 정책은 분명 있는데, 새 프로젝트가 생길 때마다 같은 설명을 또 하고 또 하게 되는 상황 말이죠. 이런 반복을 줄이려면 결국 문서화와 템플릿화가 답입니다. 다음 글에서는 OPA Gatekeeper(오픈 정책 에이전트 게이트키퍼)나 Kyverno(카이버노) 같은 정책 엔진과 PodSecurity를 어떻게 역할 분담할지 다뤄볼 예정입니다. 이전 글에서 다룬 네임스페이스 표준화 내용이 있으시다면 같이 연결해서 보시는 것도 좋습니다.

    도입 전후의 차이, 운영 체크리스트, 다음 단계까지 한 장으로 요약한 인포그래픽 이미지입니다.

    정리: Kubernetes 보안은 작은 강제에서 시작됩니다

    Kubernetes PodSecurity 도입은 거창한 보안 프로젝트처럼 보일 수 있지만, 실제로는 “위험한 기본값을 그냥 두지 않겠다”는 아주 현실적인 출발점에 가깝습니다. 제가 여러 번 적용해보니 가장 효과적인 방식은 이렇습니다. 먼저 경고와 감사로 현재 상태를 파악하고, 그다음 Baseline으로 정리한 뒤, 준비된 워크로드부터 Restricted로 올리는 흐름이었습니다. 처음엔 이게 뭔가 싶었는데, 한 번 기준이 잡히고 나면 운영이 훨씬 편해집니다. 드디어 됐다! 싶은 순간이 오더라고요.

    마지막으로 한 줄 요약하면 이겁니다. Pod Security Standards는 문서가 아니라 운영 습관으로 들어와야 합니다. 보안 정책이 실제 배포 과정에 녹아들면, 리뷰 품질도 좋아지고 예외도 줄고, 나중에 감사 대응도 덜 힘들어집니다. Kubernetes 보안을 어디서부터 손대야 할지 막막하셨다면, PodSecurity부터 차근차근 시작해보세요.

    FAQ: 자주 묻는 질문

    모든 네임스페이스를 바로 Restricted로 가야 하나요?

    아닙니다. 레거시 워크로드가 많다면 Baseline부터 정리하는 편이 현실적입니다. 무리하게 올리면 예외만 늘어날 수 있습니다.

    PodSecurity만 있으면 보안 정책이 충분한가요?

    기본 보안 가드레일로는 매우 유용하지만, 조직별 세부 규칙까지 모두 대신하진 못합니다. 필요한 경우 별도 정책 엔진과 역할을 나눠가는 게 좋습니다.

    가장 먼저 점검할 필드는 무엇인가요?

    runAsNonRoot, allowPrivilegeEscalation, privileged, capabilities, hostPath 같은 항목부터 보는 걸 권합니다.

  • [k8s] Pod Security Standards 마이그레이션: Kubernetes PSP에서 안전하게 전환하기

    [k8s] Pod Security Standards 마이그레이션: Kubernetes PSP에서 안전하게 전환하기

    Pod Security Standards 마이그레이션: Kubernetes PSP에서 안전하게 전환하기

    Kubernetes 클러스터를 오래 운영했다면 PSP(PodSecurityPolicy) 때문에 한 번쯤 머리가 아팠을 겁니다. 저도 그랬습니다. 그런데 PSP는 Kubernetes 1.21에서 deprecated 되었고, Kubernetes 1.25에서 완전히 제거됐습니다. 그래서 Pod Security Standards 마이그레이션은 이제 선택이 아니라 업그레이드와 운영 안정성을 위해 꼭 챙겨야 할 작업이 됐습니다. 이번 글에서는 Kubernetes 보안 관점에서 PSP 대체 수단인 PSS(Pod Security Standards)와 Pod Security Admission으로 어떻게 안전하게 전환하는지, 실무 기준으로 차근차근 정리해보겠습니다.

    처음엔 저도 PSS가 너무 단순해 보여서 오히려 불안했습니다. PSP처럼 세부 필드를 다 적는 방식에 익숙하면 더 그렇게 느껴지거든요. 그런데 실제로 운영해보니 팀 공통 보안 기준을 맞추는 데는 훨씬 현실적이더라고요. 대신 전환 순서를 잘못 잡으면 배포가 갑자기 막힐 수 있습니다. 여기서 핵심은 처음부터 enforce로 가지 말고 warn, audit로 먼저 관찰하는 것입니다.

    Pod Security Standards 마이그레이션 개요를 보여주는 Kubernetes 보안 아키텍처 이미지

    PSP에서 PSS와 Pod Security Admission으로 넘어가는 흐름을 한눈에 보여주는 개요 이미지입니다.

    왜 Pod Security Standards 마이그레이션이 중요한가

    예전 방식인 PSP는 표현력은 강했지만 운영 피로도도 높았습니다. 반면 PSS는 Privileged, Baseline, Restricted라는 공통 보안 레벨을 제공해서 팀 간 기준을 맞추기 훨씬 쉽습니다. 여러 네임스페이스를 운영하는 환경에서는 긴 정책 객체를 계속 유지하는 것보다, 보안 수준을 레벨로 선언하는 편이 관리가 훨씬 단순합니다.

    제가 직접 겪어보니 Pod Security Standards 마이그레이션의 장점은 분명했습니다. 신규 팀원에게 설명하기 쉽고, 클러스터 업그레이드 때 정책 호환성 이슈가 크게 줄어듭니다. 다만 PSP처럼 아주 세밀한 예외 제어를 기대하면 아쉬울 수 있습니다. 그런 경우에는 OPA Gatekeeper나 Kyverno 같은 정책 엔진을 함께 쓰는 구성이 더 잘 맞습니다.

    Pod Security Standards 마이그레이션 기준: PSP와 PSS는 무엇이 다를까

    처음 보면 이름만 바뀐 것처럼 느껴질 수 있는데 구조는 꽤 다릅니다. PSP는 정책 리소스를 만들고 RBAC으로 사용자나 서비스어카운트와 연결하는 방식이었습니다. 반면 PSS는 네임스페이스에 보안 수준을 라벨로 선언하고, Pod Security Admission이 그 기준으로 파드를 검사합니다.

    항목 PSP PSS + Pod Security Admission
    정책 방식 세부 필드 기반 정책 객체 사전 정의된 보안 표준 레벨
    적용 범위 RBAC과 연결해 사용 네임스페이스 라벨 기반 적용
    운영 난이도 높은 편 상대적으로 단순
    이식성 클러스터별 편차 큼 표준화하기 좋음
    세밀한 예외 처리 강점 제한적, 필요 시 별도 정책 엔진 보완

    PSS의 핵심 레벨은 아래처럼 이해하면 편합니다.

    • Privileged: 사실상 제한이 거의 없는 수준입니다. 시스템 워크로드나 인프라성 컴포넌트에 가깝습니다.
    • Baseline: 일반 애플리케이션에 적용하기 좋은 현실적인 최소 보호선입니다.
    • Restricted: 현재 권장되는 강한 하드닝 기준입니다. 대신 기존 애플리케이션은 여기서 많이 걸릴 수 있습니다.

    Pod Security Admission 적용 방법: 전환 전에 꼭 확인할 것

    Pod Security Admission은 파드 생성 시점에 PSS 기준을 검사하는 내장 Admission Controller입니다. 다만 여기서 하나 짚고 갈 점이 있습니다. warn과 audit는 Deployment 같은 워크로드 리소스에도 경고를 보여주지만, enforce는 최종적으로 생성되는 Pod에 적용됩니다. 이 차이를 알고 있어야 배포 시 메시지를 덜 헷갈립니다.

    1. enforce: 정책을 어기면 Pod 생성이 거부됩니다.
    2. audit: 생성은 허용되지만 감사 로그에 위반 정보가 남습니다.
    3. warn: 생성은 허용되지만 클라이언트에 경고가 표시됩니다.

    실무에서 자주 하는 실수가 바로 여기입니다. 바로 enforce부터 켜버리면 그동안 관성적으로 돌아가던 워크로드가 한꺼번에 실패할 수 있거든요. 저도 테스트 환경에서 ingress controller가 안 떠서 꽤 오래 본 적이 있습니다. 알고 보니 hostNetwork와 securityContext 설정이 기준에 안 맞았더라고요. 이런 경험을 한 번 하면 warn, audit부터 가야 하는 이유가 확실히 보입니다.

    전환 전 체크리스트

    • 현재 클러스터에서 PSP를 실제로 쓰는 네임스페이스가 어디인지 확인합니다.
    • 권한 상승 허용 여부를 점검합니다.
    • root 실행, hostPath 마운트, hostNetwork 사용 여부를 확인합니다.
    • DaemonSet, CSI, 모니터링 에이전트처럼 예외가 필요한 워크로드를 분리합니다.
    • 애플리케이션 네임스페이스와 시스템 네임스페이스를 같은 기준으로 묶지 않습니다.

    실전 구현: Pod Security Standards 마이그레이션 순서

    여기서는 제가 실제로 권장하는 순서를 정리해보겠습니다. 핵심은 단순합니다. 관찰 먼저, 강제는 나중. 이 순서만 지켜도 사고 확률이 확실히 줄어듭니다.

    1. 현재 네임스페이스 라벨 상태 확인

    kubectl get ns --show-labels

    기존에 이미 pod-security 관련 라벨이 붙어 있는지 먼저 확인합니다. 다른 운영자가 먼저 설정해둔 경우도 생각보다 자주 있습니다. 이 상태를 모르고 덮어쓰면 원인 파악이 더 어려워집니다.

    2. 먼저 warn, audit 모드로 Baseline 적용

    kubectl label ns my-app \
      pod-security.kubernetes.io/warn=baseline \
      pod-security.kubernetes.io/audit=baseline \
      --overwrite

    처음부터 Restricted로 가고 싶어도 일단 Baseline부터 보는 편이 안전합니다. 여기서 어떤 워크로드가 경고를 내는지 파악해야 다음 단계가 보입니다. 이 단계가 생각보다 중요하더라고요.

    3. 버전 라벨도 함께 명시해 드리프트 줄이기

    kubectl label ns my-app \
      pod-security.kubernetes.io/warn-version=v1.36 \
      pod-security.kubernetes.io/audit-version=v1.36 \
      --overwrite

    버전 라벨은 선택 사항이지만 운영에선 거의 필수에 가깝습니다. PSS 해석 기준은 Kubernetes 마이너 버전에 따라 달라질 수 있어서, 테스트와 운영 클러스터의 결과가 어긋나는 일을 줄여주거든요. 다만 예시 값을 그대로 복붙하기보다는 현재 클러스터의 마이너 버전에 맞춰 적는 게 맞습니다.

    4. 경고 메시지로 문제 워크로드 찾기

    kubectl apply -f deployment.yaml

    배포 시 warn 메시지가 뜨면 그 내용을 기준으로 수정합니다. warn과 audit는 Deployment 같은 워크로드 리소스에도 적용되기 때문에, 이 단계에서 꽤 많은 힌트를 얻을 수 있습니다. 흔히 손보게 되는 포인트는 아래와 같습니다.

    • runAsNonRoot: non-root 실행 강제
    • allowPrivilegeEscalation: false 설정
    • seccompProfile: RuntimeDefault 적용
    • capabilities: 불필요한 Linux capability 제거
    Pod Security Admission과 네임스페이스 라벨 기반 PSS 적용 방법을 설명하는 이미지

    네임스페이스에 warn, audit, enforce 라벨을 붙이는 방식과 적용 흐름을 보여주는 이미지입니다.

    5. 매니페스트 보안 컨텍스트 정리

    아래 예시는 Restricted로 가기 전에 가장 자주 쓰는 기본 골격입니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: web-app
      namespace: my-app
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: web-app
      template:
        metadata:
          labels:
            app: web-app
        spec:
          securityContext:
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          containers:
            - name: web-app
              image: nginx:stable
              securityContext:
                allowPrivilegeEscalation: false
                capabilities:
                  drop:
                    - ALL
              ports:
                - containerPort: 80

    이 예시는 아주 화려하지는 않지만, 실제로 많이 걸리는 조건을 담고 있습니다. 특히 runAsNonRoot는 이미지 자체가 non-root 실행을 지원해야 제대로 동작합니다. 오래된 이미지라면 매니페스트만 고쳐서는 해결이 안 되고, 컨테이너 이미지 베이스부터 손봐야 할 때가 있습니다.

    6. 문제 없으면 enforce 전환

    kubectl label ns my-app \
      pod-security.kubernetes.io/enforce=baseline \
      pod-security.kubernetes.io/enforce-version=v1.36 \
      --overwrite

    여기서도 한 번에 모든 네임스페이스를 바꾸는 건 추천하지 않습니다. 서비스 영향이 낮은 곳부터 묶어서 적용하고, 모니터링으로 이상이 없는지 확인한 뒤 확대하는 방식이 제일 덜 아픕니다. 이거 진짜 차이가 큽니다.

    Restricted까지 가려면 어떤 점을 더 봐야 하나

    Pod Security Standards 마이그레이션을 시작하면 많은 팀이 최종 목표를 Restricted로 잡습니다. 방향은 맞습니다. 다만 현실적으로 모든 워크로드가 바로 들어가지는 않더라고요. 특히 아래 항목은 자주 발목을 잡습니다.

    1. 레거시 이미지가 root 실행을 전제로 만들어져 있음
    2. initContainer에서 과한 권한을 사용함
    3. 모니터링, 스토리지, 네트워크 에이전트가 호스트 접근을 필요로 함
    4. hostPath 사용이 습관처럼 들어가 있음

    그래서 저는 보통 네임스페이스를 이렇게 나눕니다.

    네임스페이스 유형 권장 레벨 비고
    일반 애플리케이션 Baseline 또는 Restricted 신규 서비스는 Restricted 목표
    운영 도구 Baseline 필요 권한 확인 후 점진 강화
    시스템 워크로드 Privileged 또는 별도 예외 관리 CNI, CSI, 일부 에이전트 주의

    트러블슈팅: Pod Security Standards 마이그레이션에서 자주 막히는 지점

    문서만 보면 금방 끝날 것 같지만, 운영 환경에 붙이면 여기서 한 번씩 다 막힙니다. 저도 몇 번은 꽤 돌아갔습니다. 그래서 아래 포인트는 미리 보고 들어가는 편이 좋습니다.

    1. 배포가 갑자기 거부될 때

    enforce가 켜진 네임스페이스에 정책 위반 Pod가 들어가면 바로 거부됩니다. 이 경우 이벤트와 매니페스트를 같이 봐야 합니다.

    kubectl describe pod <pod-name> -n my-app
    kubectl get events -n my-app --sort-by=.lastTimestamp

    경고 문구만 보고 대충 고치면 같은 문제를 반복하기 쉽습니다. 어떤 필드가 위반인지 정확히 확인하고, Pod 템플릿 기준으로 수정해야 합니다.

    2. 시스템 네임스페이스까지 묶어서 막힐 때

    이 부분은 정말 조심해야 합니다. kube-system 같은 곳에 일반 앱과 같은 Restricted를 걸면 예상치 못한 장애가 날 수 있습니다. 네트워크 플러그인, 스토리지 드라이버, 노드 에이전트가 영향을 받는 경우가 대표적입니다. 실제 운영에선 시스템성 워크로드를 별도 기준으로 다루는 게 훨씬 안전합니다.

    3. warn은 뜨는데 배포가 되니까 그냥 넘길 때

    처음엔 “배포는 되네” 하고 넘기기 쉽습니다. 그런데 나중에 enforce로 바꾸는 순간 한꺼번에 터집니다. 그래서 warn 단계에서 바로 티켓을 만들고, 팀별 수정 일정을 잡아두는 편이 훨씬 낫습니다.

    4. PSP 기능과 1:1 대응을 기대할 때

    PSP 대체라고 해서 완전히 같은 경험을 기대하면 실망할 수 있습니다. PSS는 표준 보안 레벨을 제공하는 방식이고, 세밀한 조직별 규칙은 별도 정책 도구가 더 적합합니다. 이 차이를 이해하고 설계해야 전환 이후 불만도 줄어듭니다.

    검증: Pod Security Admission이 제대로 동작하는지 확인하는 방법

    적용 후에는 라벨만 붙였다고 끝이 아닙니다. 검증이 꼭 필요합니다. 제가 보통 확인하는 항목은 아래와 같습니다.

    1. 네임스페이스 라벨이 의도한 값으로 들어갔는지 확인
    2. warn 메시지가 줄거나 사라졌는지 확인
    3. 문제 Pod 없이 롤링 업데이트가 완료되는지 확인
    4. 시스템 워크로드가 영향 없이 유지되는지 확인
    kubectl get ns my-app --show-labels
    kubectl rollout status deploy/web-app -n my-app
    kubectl get pods -n my-app

    조금 더 확실히 보려면 의도적으로 정책 위반 Pod를 하나 던져보는 것도 방법입니다. 다만 이 테스트는 운영 네임스페이스가 아니라 테스트 네임스페이스에서만 하는 편이 안전합니다.

    apiVersion: v1
    kind: Pod
    metadata:
      name: pss-test
      namespace: my-app
    spec:
      hostNetwork: true
      containers:
        - name: busybox
          image: busybox:1.36
          command: ["sh", "-c", "sleep 3600"]
          securityContext:
            allowPrivilegeEscalation: true

    Baseline이나 Restricted enforce가 걸려 있다면 이런 Pod는 거부되는 게 정상입니다. hostNetwork는 Baseline부터 금지되고, allowPrivilegeEscalation은 Restricted에서 금지되기 때문에 테스트용으로 확인하기 좋습니다.

    Pod Security Standards 마이그레이션 검증 결과를 보여주는 Kubernetes 보안 이미지

    정책 위반 테스트와 정상 배포가 어떻게 다르게 보이는지 검증 결과를 시각화한 이미지입니다.

    운영 팁: 네임스페이스 전략을 먼저 정하면 훨씬 편합니다

    제가 여러 번 해보니, PSS 적용 방법에서 제일 중요한 건 YAML 문법보다 운영 기준이었습니다. 다시 말해 “어떤 네임스페이스를 어떤 신뢰 수준으로 볼 것인가”를 먼저 정해야 합니다. 이 기준이 없으면 팀마다 예외 요청이 쌓이고, 결국 정책이 누더기가 되더라고요.

    • 신규 서비스는 기본적으로 Baseline 또는 Restricted로 시작합니다.
    • 예외가 필요한 시스템성 워크로드는 별도 네임스페이스로 분리합니다.
    • warn과 audit 결과를 주기적으로 점검해 enforce 후보를 올립니다.
    • 정책 예외는 문서화하고 만료 시점을 정합니다.

    이런 방식으로 가면 Kubernetes 보안이 특정 담당자 감에 의존하지 않고 팀 표준으로 자리 잡습니다. 이전에 정리한 RBAC 글이 있다면 같이 연결해두는 것도 좋습니다. 내부 링크 흐름이 생기면 독자 입장에서도 이해가 더 빨라지고, SEO 측면에서도 분명 도움이 됩니다.

    정리: PSP에서 PSS로 갈아탈 때 기억할 것

    오늘 내용을 짧게 정리하면 이렇습니다. Pod Security Standards 마이그레이션은 단순한 기능 교체가 아니라, 보안 운영 방식을 표준화하는 작업입니다. PSP보다 세밀한 제어는 줄었지만, 네임스페이스 단위로 기준을 맞추기 쉬워졌고, Pod Security Admission으로 warn, audit, enforce를 단계적으로 운영할 수 있게 됐습니다.

    저도 처음엔 이 구조가 너무 단순한 것 아닌가 싶었습니다. 그런데 실제로는 팀 단위 운영에 더 잘 맞더라고요. 다만 무작정 enforce부터 걸면 안 됩니다. 꼭 warn, audit으로 현재 상태를 먼저 파악하고, Restricted는 목표로 두되 시스템 워크로드 예외를 현실적으로 분리해 가져가면 훨씬 수월합니다.

    지금 클러스터 업그레이드를 앞두고 있다면 이번 주에라도 테스트 네임스페이스 하나 만들어 Baseline warn부터 붙여보세요. 생각보다 빨리 문제가 보입니다. 그리고 이전에 다뤘던 RBAC 정리 글도 함께 보면 흐름이 더 잘 잡힐 겁니다. 다음 글에서는 Kyverno나 Gatekeeper로 PSS의 빈틈을 어떻게 보완하는지도 이어서 정리해보겠습니다.

    PSP 대체와 Pod Security Standards 보안 레벨 비교를 정리한 인포그래픽 이미지

    PSP와 PSS의 차이, 적용 순서, 운영 체크포인트를 한 장으로 정리한 요약 인포그래픽입니다.

    자주 묻는 질문

    PSS만으로 PSP를 완전히 대체할 수 있나요?

    기본적인 표준화 목적에는 충분한 경우가 많습니다. 다만 세밀한 조건 제어나 예외 검증이 많다면 Kyverno나 Gatekeeper 같은 정책 엔진을 함께 검토하는 편이 좋습니다.

    처음부터 Restricted로 가도 되나요?

    신규 서비스만 있고 이미지와 매니페스트를 처음부터 통제할 수 있는 환경이라면 가능합니다. 하지만 기존 워크로드가 있다면 Baseline warn, audit부터 시작하는 편이 훨씬 안전합니다.

    Pod Security Admission은 어디에 적용되나요?

    네임스페이스 라벨 기준으로 해당 네임스페이스의 Pod 생성에 영향을 줍니다. 또 warn과 audit는 Deployment 같은 워크로드 리소스에도 힌트를 주기 때문에, 네임스페이스 전략과 배포 검증 루틴을 함께 가져가는 게 중요합니다.