본문 바로가기
클라우드/쿠버네티스

🔑 우리 회사 쿠버네티스, 아무 파드나 시크릿을 다 볼 수 있다구요?

by gasbugs 2025. 9. 18.

안녕하세요! 쿠버네티스 환경을 운영하고 있는 개발자/엔지니어 여러분. 어느 날 문득 이런 생각을 해보신 적 없나요?

"내가 만든 파드는 그냥 배포 권한만 있으면, 같은 네임스페이스에 있는 DB 접속 정보 시크릿, 외부 API 키 시크릿을 전부 마음대로 마운트해서 쓸 수 있는 건가? 😱"

 

만약 이 질문에 "네, 그렇죠!"라고 바로 대답하셨다면, 당신은 쿠버네티스의 권한 모델을 정확히 이해하고 계신 겁니다. 그리고 동시에, 우리가 해결해야 할 중요한 보안 과제를 마주하고 있다는 의미이기도 합니다.

이번 포스트에서는 쿠버네티스의 기본 동작 방식이 왜 이렇게 설계되었는지 알아보고, 이러한 보안 우려를 해결하여 우리 클러스터를 더욱 견고하게 만들 수 있는 3가지 핵심 전략을 아주 상세하게 파헤쳐 보겠습니다! 🚀

 

 

 

🤔 왜 이런 일이 발생할까? 쿠버네티스의 기본 권한 모델 이해하기

쿠버네티스의 보안을 책임지는 핵심 요소는 RBAC (Role-Based Access Control) 입니다. RBAC의 작동 방식을 간단히 요약하면 다음과 같습니다.

"누가(Subject) 어떤 리소스(Resource)에 어떤 행동(Verb)을 할 수 있는가?"

여기서 '누가'는 사용자, 그룹, 또는 서비스 어카운트(ServiceAccount)가 될 수 있습니다. '어떤 리소스'는 파드, 시크릿, 디플로이먼트 등이 해당되고, '어떤 행동'은 create, get, list, delete 등이 있습니다.

자, 사용자가 파드를 생성하는 흐름을 따라가 볼까요?

  1. 👨‍💻 사용자: my-pod.yaml 파일을 작성하고 kubectl apply 명령을 실행합니다. 이 YAML 파일 안에는 "db-secret"이라는 시크릿을 마운트하라는 설정이 포함되어 있습니다.
  2. 👮 API 서버: 요청을 받고 RBAC 정책을 확인합니다. "이 사용자가 production 네임스페이스에 pod를 create 할 권한이 있는가?"
  3. 권한 통과: 권한이 있다면, API 서버는 이 요청을 받아들여 파드 정보를 etcd에 저장합니다.
  4. 👷 Kubelet: 노드에 할당된 파드를 명세(spec)대로 실행합니다. 명세에 "db-secret"을 마운트하라고 되어 있으니, Kubelet은 충실하게 해당 시크릿을 가져와 파드에 마운트합니다.

가장 중요한 포인트는 2번과 4번 사이에 추가적인 권한 검사가 없다는 것입니다!

API 서버는 "파드를 생성할 권한"만 확인할 뿐, "생성될 파드가 참조하는 시크릿을 읽을 권한"까지는 확인하지 않습니다. 마치 건물 출입증(RBAC)으로 건물에 들어온 뒤, 안에 있는 어떤 사무실(시크릿)이든 자유롭게 들어가는 것과 같습니다.

이것이 바로 "파드 생성 권한이 동일 네임스페이스 내 모든 시크릿 접근 권한으로 이어질 수 있다" 는 보안 우려가 나오는 배경입니다.


🛡️ 보안 강화 전략: 우리 클러스터를 안전하게 지키는 방법

그렇다면 이 문제를 어떻게 해결해야 할까요? 다행히도 우리에게는 여러 강력한 도구들이 있습니다.

방법 1: 네임스페이스로 격리하기 (가장 기본적이고 중요한 첫걸음!) 🧱

가장 먼저 적용해야 할 기본 중의 기본입니다. 시크릿은 네임스페이스에 종속된 리소스입니다. 즉, app-a 네임스페이스의 파드는 app-b 네임스페이스의 시크릿에 절대 접근할 수 없습니다.

  • 팀별/애플리케이션별 네임스페이스 분리: 여러 팀이 하나의 클러스터를 공유한다면, 팀별로 네임스페이스를 분리하여 서로의 리소스에 접근할 수 없도록 격리해야 합니다.
  • 환경별 네임스페이스 분리: dev, staging, production 환경을 네임스페이스로 나누는 것도 좋은 격리 전략입니다.

네임스페이스 분리만 잘해도 의도치 않은 시크릿 노출 사고의 90%는 막을 수 있습니다.

방법 2: 어드미션 컨트롤러로 정책 강제하기 (진정한 해결사!) 👮‍♀️

"같은 네임스페이스 안에서도 A 파드는 A 시크릿만, B 파드는 B 시크릿만 쓰게 하고 싶어요!" 라는 요구사항을 만족시켜 줄 수 있는 기술이 바로 어드미션 컨트롤러(Admission Controller) 입니다.

 

어드미션 컨트롤러는 API 서버의 문지기 역할을 합니다. 모든 생성/수정 요청이 처리되기 직전에 이 문지기를 통과해야만 합니다. 여기서 우리는 커스텀 정책을 만들어 문지기에게 검사하도록 시킬 수 있습니다.

이 분야의 대표적인 오픈소스로는 KyvernoOPA Gatekeeper가 있습니다.

 

✨ Kyverno 예시

Kyverno는 쿠버네티스 리소스(YAML) 형태로 정책을 정의하기 때문에 배우기 쉽고 직관적입니다. 예를 들어, "파드는 app 레이블이 자신과 동일한 시크릿만 마운트할 수 있다"는 정책을 만들어 보겠습니다.

# policies.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: restrict-secret-mount-by-label
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-secret-labels
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "Pods can only mount secrets with a matching 'app' label."
      foreach:
      - list: "request.object.spec.volumes"
        pattern:
          secret:
            secretName: "?*" # 시크릿 볼륨이 있다면
            # 이 아래 정책을 검사
            preconditions:
              all:
              - key: "{{ request.object.metadata.labels.app }}"
                operator: NotEquals
                value: "" # 파드에 app 레이블이 있는지 확인
            deny:
              conditions:
                any:
                - key: "{{ secrets[request.namespace][element.secret.secretName].metadata.labels.app }}"
                  operator: NotEquals
                  value: "{{ request.object.metadata.labels.app }}" # 시크릿의 app 레이블과 파드의 app 레이블이 다른 경우 거부

 

이 정책을 클러스터에 적용하면, app: my-app 레이블을 가진 파드가 app: other-app 레이블을 가진 시크릿을 마운트하려고 시도할 때, API 서버는 요청을 **거부(Deny)**합니다. 이제 더 이상 아무 시크릿이나 마운트할 수 없게 된 거죠!

방법 3: 외부에서 시크릿 관리하기 (궁극의 분리!) 🏦

애초에 민감한 정보를 쿠버네티스 Secret 오브젝트에 직접 저장하지 않는, 가장 강력한 보안 모델입니다.

  • 전문 솔루션 사용: HashiCorp Vault, AWS Secrets Manager, Google Secret Manager, Azure Key Vault 등 외부의 전문 시크릿 관리 도구를 사용합니다.
  • 연동 컨트롤러: External Secrets Operator (ESO) 같은 컨트롤러를 클러스터에 설치합니다.

작동 방식은 다음과 같습니다.

  1. 개발자는 ExternalSecret이라는 커스텀 리소스(CRD)를 생성합니다. 이 리소스에는 "Vault의 kv/myapp/db-password 경로에 있는 값을 가져와줘" 라는 위치 정보만 담겨 있습니다. (실제 비밀번호는 없음)
  2. External Secrets Operator는 이 ExternalSecret을 감지하고, 자신이 가진 권한으로 Vault에 접속하여 실제 비밀번호를 가져옵니다.
  3. 가져온 비밀번호 값으로 쿠버네티스 네이티브 Secret 오브젝트(myapp-db-secret)를 자동으로 생성해 줍니다.
  4. 애플리케이션 파드는 이 자동으로 생성된 Secret을 안전하게 마운트하여 사용합니다.

이 방식의 장점은 명확합니다.

  • 중앙 관리: 모든 시크릿을 한 곳(Vault 등)에서 중앙 관리하고 감사(Audit)할 수 있습니다.
  • 권한 분리: 개발자는 시크릿의 실제 값에 접근할 필요 없이 위치만 알면 됩니다. 시크릿 접근 권한은 쿠버네티스 RBAC이 아닌 Vault의 정책으로 제어됩니다.
  • 자동 로테이션: Vault에서 비밀번호가 변경되면, ESO가 이를 감지하여 쿠버네티스 시크릿을 자동으로 업데이트해 줍니다.

✍️ 정리하며

오늘 우리는 쿠버네티스의 기본 동작만으로는 파드의 시크릿 접근을 세밀하게 제어하기 어렵다는 점과, 이를 해결하기 위한 3가지 핵심 전략에 대해 알아보았습니다.

  • 1단계 (기본): 네임스페이스를 이용해 애플리케이션과 환경을 철저히 격리하세요.
  • 2단계 (강화): Kyverno, OPA 같은 어드미션 컨트롤러를 도입하여 네임스페이스 내에서 세분화된 접근 제어 정책을 강제하세요.
  • 3단계 (고급): 외부 시크릿 관리 솔루션과 연동하여 시크릿 관리의 책임을 쿠버네티스 외부로 이전하고, 더욱 강력한 보안과 중앙 관리 체계를 구축하세요.

이러한 다층적 보안(Defense in Depth) 전략을 통해, 우리는 더욱 안전하고 신뢰할 수 있는 쿠버네티스 환경을 만들어 나갈 수 있습니다. 여러분의 클러스터는 오늘부터 한 단계 더 안전해졌기를 바랍니다!


태그: 쿠버네티스, Kubernetes, 보안, Security, 시크릿, Secret, RBAC, Admission Controller, Kyverno, OPA, Gatekeeper, External Secrets