Kubernetes Secret을 안전하게 관리하는 방법: etcd 암호화부터 외부 Secret 관리 도구까지

2026. 6. 8. 09:58Kubernetes

반응형

Kubernetes Secret은 민감 데이터를 저장하는 기본 메커니즘이지만, 기본 설정만으로는 안전하지 않습니다. Base64 인코딩은 암호화가 아니며, etcd에 평문으로 저장될 수 있습니다. 운영 환경에서는 암호화, 접근 제어, 외부 Secret 관리 도구를 조합하여 보안을 강화해야 합니다.

핵심 요약

  • Kubernetes Secret은 Base64 인코딩만 적용됩니다. 이는 난독화일 뿐 암호화가 아닙니다.
  • 기본 설정에서 Secret은 etcd에 평문으로 저장됩니다. EncryptionConfiguration을 통해 저장 시 암호화(Encryption at Rest)를 활성화해야 합니다.
  • RBAC로 Secret 접근을 최소화하고, 감사 로그로 접근 이력을 추적합니다.
  • 운영 환경에서는 외부 Secret 관리 도구(External Secrets Operator, Sealed Secrets, HashiCorp Vault)를 사용하여 Git 저장소에 Secret이 노출되지 않도록 합니다.
  • 매니지드 Kubernetes(EKS, AKS, GKE)는 기본적으로 etcd 암호화를 제공하지만, 클러스터 내부 접근 제어는 별도로 설계해야 합니다.

1. Kubernetes Secret의 보안 한계

팀에서 데이터베이스 비밀번호를 Kubernetes Secret으로 관리합니다. YAML 파일을 Git에 커밋하고, 새 팀원이 합류할 때마다 kubectl로 Secret을 확인합니다. 어느 날 보안 감사에서 이런 질문을 받습니다: "이 Secret은 누가 언제 조회했는지 추적할 수 있나요? etcd에 암호화되어 저장되나요?"

대부분의 경우 대답은 "아니오"입니다. Kubernetes Secret의 기본 보안 수준이 낮은 이유를 먼저 이해해야 합니다.

1.1 Base64 ≠ 암호화

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: production
type: Opaque
data:
  username: YWRtaW4=        # echo -n "admin" | base64
  password: cEBzc3cwcmQ=    # echo -n "p@ssw0rd" | base64

base64 --decode로 누구나 원본 값을 복원할 수 있습니다. Git에 이 YAML이 커밋되면 사실상 평문과 동일합니다.

1.2 etcd 평문 저장

기본 설정에서 Kubernetes API Server는 Secret을 etcd에 그대로 저장합니다. etcd 백업 파일에 접근하거나, etcd를 직접 조회할 수 있는 사람은 모든 Secret을 평문으로 읽을 수 있습니다.

1.3 과도한 접근 권한

view ClusterRole을 가진 사용자는 Secret을 읽을 수 없지만, edit이나 admin ClusterRole은 Secret 읽기/쓰기가 가능합니다. 네임스페이스에 edit 권한을 부여하면 의도치 않게 Secret 접근이 허용됩니다.

위험 원인 영향
Git에 Secret YAML 노출 Base64가 암호화라고 착각 리포지토리 접근자 전원이 Secret 열람 가능
etcd 평문 저장 EncryptionConfiguration 미설정 etcd 백업/접근으로 전체 Secret 유출
과도한 RBAC 권한 네임스페이스 단위 edit/admin 부여 불필요한 서비스까지 Secret 조회 가능
감사 추적 불가 Audit Log 미설정 누가 언제 Secret을 읽었는지 확인 불가
Pod에서 환경 변수 노출 env로 Secret 주입 kubectl describe pod로 값 노출

2. 보안 강화 전략 개요

Kubernetes Secret 보안 계층 구조
Kubernetes Secret 보안 계층 구조

Secret 보안은 단일 도구로 해결되지 않습니다. 여러 계층을 조합하여 방어 깊이(Defense in Depth)를 확보해야 합니다.

계층 목적 도구/설정
저장 시 암호화 etcd에 암호화된 상태로 저장 EncryptionConfiguration, 클라우드 KMS
접근 제어 Secret 읽기/쓰기 권한 최소화 RBAC, 전용 ServiceAccount
전송 시 암호화 API Server ↔ etcd 통신 암호화 TLS (기본 활성화)
외부 Secret 관리 Git에 Secret을 저장하지 않음 External Secrets Operator, Sealed Secrets, Vault
감사 접근 이력 추적 Kubernetes Audit Log
런타임 보호 Pod 내부에서 Secret 노출 최소화 Volume mount 방식, automountServiceAccountToken: false

3. etcd 저장 시 암호화 (Encryption at Rest)

etcd 암호화 동작 흐름
etcd 암호화 동작 흐름

3.1 EncryptionConfiguration 설정

자체 관리 클러스터(kubeadm 등)에서는 API Server에 --encryption-provider-config 플래그로 암호화를 활성화합니다.

# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <BASE64_ENCODED_32_BYTE_KEY>
      - identity: {}   # 암호화되지 않은 기존 Secret 읽기용 fallback
# 32바이트 키 생성
head -c 32 /dev/urandom | base64

# API Server 설정에 추가
# /etc/kubernetes/manifests/kube-apiserver.yaml
# --encryption-provider-config=/etc/kubernetes/encryption-config.yaml

암호화 Provider 선택:

Provider 특징 권장 용도
aescbc AES-CBC 256비트 암호화. 키를 로컬에 저장 소규모 클러스터, 테스트 환경
aesgcm AES-GCM 인증 암호화. 키 로테이션 시 주의 필요 성능이 중요한 경우
kms v2 외부 KMS와 연동 (봉투 암호화) 운영 환경 권장
secretbox NaCl SecretBox 사용. 인증+암호화 동시 제공 단순한 환경에서 안전한 선택
주의
identity provider는 암호화를 적용하지 않습니다. providers 목록에서 첫 번째 항목이 쓰기에 사용됩니다. identity가 첫 번째이면 암호화가 적용되지 않으므로, 반드시 암호화 provider를 먼저 배치해야 합니다.

3.2 기존 Secret 재암호화

EncryptionConfiguration을 적용해도 기존 Secret은 자동으로 재암호화되지 않습니다. 명시적으로 업데이트해야 합니다.

# 모든 네임스페이스의 Secret을 재암호화
kubectl get secrets --all-namespaces -o json | \
  kubectl replace -f -

3.3 매니지드 Kubernetes에서의 etcd 암호화

플랫폼 기본 암호화 추가 옵션
EKS 기본 비활성화, 콘솔에서 활성화 가능 AWS KMS 키를 지정하여 봉투 암호화
AKS 기본 활성화 (Azure 관리 키) Customer-Managed Key (CMK) 지정 가능
GKE 기본 활성화 (Google 관리 키) CMEK(Customer-Managed Encryption Key) 지정 가능

EKS에서 Secret 암호화를 활성화하는 경우:

# EKS 클러스터에 KMS 기반 Secret 암호화 활성화
aws eks associate-encryption-config \
  --cluster-name my-cluster \
  --encryption-config '[{"resources":["secrets"],"provider":{"keyArn":"arn:aws:kms:ap-northeast-2:123456789012:key/key-id"}}]'

4. RBAC로 Secret 접근 제한

4.1 Secret 전용 Role 설계

네임스페이스 내에서도 Secret 접근은 별도 Role로 분리해야 합니다. 개발자에게 edit ClusterRole 대신 Secret을 제외한 커스텀 Role을 부여하는 패턴이 안전합니다.

# Secret 읽기를 제외한 개발자 Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: developer-no-secrets
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# Secret에 대한 규칙이 없으므로 접근 불가
# Secret 읽기만 허용하는 별도 Role (필요한 사람에게만 부여)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]
  resourceNames: ["db-credentials", "api-key"]  # 특정 Secret만 허용

4.2 감사 로그 설정

Secret 접근 이력을 추적하려면 Kubernetes Audit Policy에서 Secret 관련 이벤트를 기록해야 합니다.

# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # Secret 읽기/쓰기 모든 동작을 RequestResponse 수준으로 기록
  - level: Metadata
    resources:
      - group: ""
        resources: ["secrets"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
Tip
Secret 감사 로그에서 level: RequestResponse를 사용하면 Secret 값 자체가 로그에 기록될 수 있습니다. level: Metadata는 "누가, 언제, 어떤 Secret에 접근했는가"만 기록하므로 보안과 감사 모두를 만족합니다.

5. 외부 Secret 관리 도구 비교

외부 Secret 관리 도구 동작 비교
외부 Secret 관리 도구 동작 비교

Git 저장소에 Secret YAML을 직접 저장하지 않으려면 외부 Secret 관리 도구를 사용해야 합니다. 각 도구의 동작 방식과 trade-off가 다릅니다.

도구 방식 Git에 저장하는 것 Secret 원본 위치 복잡도
Sealed Secrets 비대칭 암호화로 암호화된 Secret을 Git에 저장 암호화된 SealedSecret YAML 클러스터 내부 (컨트롤러가 복호화) 낮음
External Secrets Operator 외부 저장소에서 Secret을 동기화 ExternalSecret 참조 YAML (값 미포함) AWS Secrets Manager, Vault, Azure Key Vault 등 중간
HashiCorp Vault + VSO Vault에서 직접 Secret을 주입 VaultStaticSecret/VaultDynamicSecret CRD HashiCorp Vault 높음
Secrets Store CSI Driver CSI 볼륨으로 Secret을 Pod에 마운트 SecretProviderClass YAML (값 미포함) 클라우드 KMS, Vault 중간

의사결정 기준

Q1. Secret 원본을 어디에 저장할 것인가?
├── 클라우드 Secret 서비스 (Secrets Manager, Key Vault 등) → External Secrets Operator
├── 자체 관리 Vault → HashiCorp Vault + VSO
└── 별도 인프라 없이 Git 기반으로 → Sealed Secrets

Q2. 동적 Secret(TTL 기반 자동 갱신)이 필요한가?
├── 예 → HashiCorp Vault (Dynamic Secrets)
└── 아니오 → External Secrets Operator 또는 Sealed Secrets

Q3. 팀 규모와 운영 복잡도를 감당할 수 있는가?
├── 소규모 팀, 단일 클러스터 → Sealed Secrets
├── 중규모, 멀티 클라우드 → External Secrets Operator
└── 대규모, 엄격한 보안 요구사항 → HashiCorp Vault

6. Sealed Secrets: Git 친화적 암호화

Sealed Secrets 동작 흐름
Sealed Secrets 동작 흐름

Sealed Secrets는 Bitnami에서 개발한 오픈소스 도구입니다. 비대칭 암호화를 사용하여 클러스터의 컨트롤러만 복호화할 수 있는 SealedSecret을 생성합니다. 암호화된 YAML은 Git에 안전하게 커밋할 수 있습니다.

6.1 동작 원리

  1. 클러스터에 Sealed Secrets 컨트롤러를 설치합니다. 컨트롤러가 RSA 키 쌍을 생성합니다.
  2. 개발자가 kubeseal CLI로 일반 Secret을 SealedSecret으로 암호화합니다.
  3. 암호화된 SealedSecret YAML을 Git에 커밋합니다.
  4. 클러스터에 SealedSecret이 적용되면, 컨트롤러가 복호화하여 일반 Kubernetes Secret을 생성합니다.

6.2 설치 및 사용

# 컨트롤러 설치 (Helm)
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets \
  --namespace kube-system

# kubeseal CLI 설치 (v0.27.x 기준)
# macOS
brew install kubeseal

# Linux
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.27.3/kubeseal-0.27.3-linux-amd64.tar.gz
tar -xvzf kubeseal-0.27.3-linux-amd64.tar.gz
sudo install -m 755 kubeseal /usr/local/bin/kubeseal
# 일반 Secret을 SealedSecret으로 암호화
kubectl create secret generic db-credentials \
  --namespace production \
  --from-literal=username=admin \
  --from-literal=password='p@ssw0rd' \
  --dry-run=client -o yaml | \
  kubeseal --format yaml > sealed-db-credentials.yaml
# sealed-db-credentials.yaml (Git에 안전하게 커밋 가능)
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  encryptedData:
    username: AgBy3i4OJSWK+P... (암호화된 값)
    password: AgCtr8sMGh2DJKL... (암호화된 값)
  template:
    metadata:
      name: db-credentials
      namespace: production
    type: Opaque

6.3 키 로테이션

Sealed Secrets 컨트롤러는 기본적으로 30일마다 새 키를 생성합니다. 이전 키는 삭제되지 않으므로 기존 SealedSecret은 계속 복호화됩니다.

# 현재 사용 중인 키 확인
kubectl get secrets -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key

# 키를 수동으로 로테이션한 후 기존 SealedSecret 재암호화
kubeseal --re-encrypt < sealed-db-credentials.yaml > sealed-db-credentials-new.yaml

6.4 trade-off

장점 단점
설치/운영이 단순 클러스터 간 키가 다르므로 멀티 클러스터에서 관리 복잡
Git에 안전하게 저장 가능 Secret 값 변경 시 re-seal 필요
외부 인프라 불필요 동적 Secret(자동 갱신) 미지원
GitOps와 자연스럽게 통합 컨트롤러 키 분실 시 모든 Secret 복구 불가
Security Note
Sealed Secrets 컨트롤러의 개인 키를 안전하게 백업해야 합니다. 이 키를 잃으면 기존 SealedSecret을 복호화할 수 없습니다. 키는 kube-system 네임스페이스의 Secret으로 저장되므로, 클러스터 재생성 시 이 키를 먼저 복원해야 합니다.

7. External Secrets Operator: 외부 저장소 연동

External Secrets Operator 동작 흐름
External Secrets Operator 동작 흐름

External Secrets Operator(ESO)는 AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, HashiCorp Vault 등 외부 Secret 저장소에서 값을 읽어와 Kubernetes Secret으로 동기화합니다.

7.1 동작 원리

  1. 외부 저장소(예: AWS Secrets Manager)에 Secret을 생성합니다.
  2. 클러스터에 SecretStore(또는 ClusterSecretStore)를 정의하여 외부 저장소 연결 정보를 설정합니다.
  3. ExternalSecret 리소스를 생성하여 "어떤 외부 Secret을 어떤 Kubernetes Secret으로 동기화할지" 정의합니다.
  4. ESO 컨트롤러가 주기적으로 외부 저장소에서 값을 가져와 Kubernetes Secret을 생성/갱신합니다.

7.2 설치 및 설정

# External Secrets Operator 설치 (Helm)
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
  --namespace external-secrets \
  --create-namespace

7.3 AWS Secrets Manager 연동 예시

# SecretStore 정의 — AWS Secrets Manager 연결
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: aws-secrets-manager
  namespace: production
spec:
  provider:
    aws:
      service: SecretsManager
      region: ap-northeast-2
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa  # IRSA로 인증
# ExternalSecret 정의 — 외부 Secret을 K8s Secret으로 동기화
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h              # 동기화 주기
  secretStoreRef:
    name: aws-secrets-manager
    kind: SecretStore
  target:
    name: db-credentials           # 생성될 K8s Secret 이름
    creationPolicy: Owner
  data:
    - secretKey: username          # K8s Secret의 key
      remoteRef:
        key: production/db-creds   # AWS Secrets Manager의 Secret 이름
        property: username         # JSON 내 특정 필드
    - secretKey: password
      remoteRef:
        key: production/db-creds
        property: password

7.4 Azure Key Vault 연동 예시

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: azure-key-vault
  namespace: production
spec:
  provider:
    azurekv:
      vaultUrl: "https://my-vault.vault.azure.net"
      authType: WorkloadIdentity
      serviceAccountRef:
        name: external-secrets-sa

7.5 trade-off

장점 단점
Secret 원본이 클러스터 외부에 있어 분리됨 외부 저장소 장애 시 Secret 갱신 불가
다양한 Provider 지원 (15+ 종류) 초기 설정(IRSA, Workload Identity) 필요
자동 동기화로 Secret 갱신 자동화 동기화 지연(refreshInterval)으로 즉시 반영 안 될 수 있음
Git에는 참조만 저장 (값 미포함) 외부 저장소 비용 발생

8. HashiCorp Vault 연동

HashiCorp Vault Kubernetes 연동 구조
HashiCorp Vault Kubernetes 연동 구조

HashiCorp Vault는 동적 Secret 생성, 자동 갱신, 세밀한 접근 정책을 제공하는 Secret 관리 플랫폼입니다. Kubernetes와의 연동 방식은 세 가지가 있습니다.

연동 방식 설명 특징
Vault Secrets Operator (VSO) CRD 기반으로 Vault Secret을 K8s Secret으로 동기화 권장 방식, Operator 패턴
Vault Agent Injector Init/Sidecar 컨테이너로 Secret을 Pod에 주입 애플리케이션 코드 변경 불필요
Secrets Store CSI Driver CSI 볼륨으로 Secret을 파일 시스템에 마운트 표준 CSI 인터페이스 사용

8.1 Vault Secrets Operator (VSO) 방식

# VaultAuth — Vault 인증 설정
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: vault-auth
  namespace: production
spec:
  method: kubernetes
  mount: kubernetes
  kubernetes:
    role: production-app
    serviceAccount: app-sa
# VaultStaticSecret — 정적 Secret 동기화
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  type: kv-v2
  mount: secret
  path: production/db-creds
  destination:
    name: db-credentials       # 생성될 K8s Secret 이름
    create: true
  refreshAfter: 30s            # 갱신 주기
  vaultAuthRef: vault-auth
# VaultDynamicSecret — 동적 Secret (TTL 기반 자동 갱신)
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
  name: db-dynamic-creds
  namespace: production
spec:
  mount: database
  path: creds/production-readonly
  destination:
    name: db-dynamic-credentials
    create: true
  renewalPercent: 67           # TTL의 67% 지점에서 갱신
  vaultAuthRef: vault-auth

8.2 Vault Agent Injector 방식

Pod에 annotation을 추가하면 Vault Agent가 sidecar로 주입되어 Secret을 파일로 제공합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: production
spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: "production-app"
        vault.hashicorp.com/agent-inject-secret-db-creds: "secret/data/production/db-creds"
        vault.hashicorp.com/agent-inject-template-db-creds: |
          {{- with secret "secret/data/production/db-creds" -}}
          export DB_USER="{{ .Data.data.username }}"
          export DB_PASS="{{ .Data.data.password }}"
          {{- end }}
    spec:
      serviceAccountName: app-sa
      containers:
        - name: app
          image: my-app:1.0
          # Secret은 /vault/secrets/db-creds 파일로 마운트됨

8.3 trade-off

장점 단점
동적 Secret으로 자동 로테이션 가능 Vault 자체의 운영 부담 (HA, unseal, 백업)
세밀한 접근 정책 (Policy, AppRole) 러닝 커브가 높음
감사 로그 내장 추가 인프라 비용 (Vault 클러스터)
다양한 Secret Engine (DB, PKI, AWS 등) 단일 장애점(SPOF) 위험 (HA 필수)
Tip
Vault를 자체 운영하기 어려운 경우, HCP Vault(HashiCorp Cloud Platform)나 클라우드 네이티브 Secret 관리 서비스(AWS Secrets Manager, Azure Key Vault)를 External Secrets Operator로 연동하는 방식이 운영 부담을 줄일 수 있습니다.

9. 실무 시나리오: 스타트업 프로덕션 환경 설계

시나리오

팀원 10명의 스타트업에서 EKS 클러스터를 운영합니다. 데이터베이스 비밀번호, 외부 API 키, TLS 인증서를 관리해야 합니다. GitOps(Argo CD)를 사용 중이며, Secret을 Git에 저장하면 안 됩니다.

요구사항

  • Secret이 Git 리포지토리에 노출되면 안 됨
  • Secret 변경 시 Pod 재시작 없이 반영되면 좋음
  • 운영 부담이 적어야 함 (Vault 자체 운영은 부담)
  • AWS 서비스를 이미 사용 중

설계 결정

결정 이유 대안
External Secrets Operator 채택 AWS Secrets Manager와 직접 연동, Vault 운영 불필요 Sealed Secrets (동기화/갱신 미지원)
IRSA로 인증 IAM Role을 ServiceAccount에 직접 연결, 키 관리 불필요 Access Key 사용 (보안 위험)
refreshInterval: 1h 설정 Secret 변경 시 1시간 내 자동 반영 수동 kubectl rollout restart
EKS Secret 암호화 활성화 KMS로 etcd 암호화, 추가 비용 최소 기본 설정 유지 (보안 위험)

구현

# 1. IRSA용 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-secrets-sa
  namespace: production
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/ExternalSecretsRole
# 2. ClusterSecretStore (모든 네임스페이스에서 재사용)
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: aws-secrets-manager
spec:
  provider:
    aws:
      service: SecretsManager
      region: ap-northeast-2
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa
            namespace: production
# 3. ExternalSecret (Git에 이것만 커밋)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: app-secrets
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: app-secrets
  data:
    - secretKey: DB_PASSWORD
      remoteRef:
        key: production/app/db
        property: password
    - secretKey: API_KEY
      remoteRef:
        key: production/app/external-api
        property: key

이 구성에서 Git에 저장되는 것은 ExternalSecret YAML뿐입니다. 실제 Secret 값은 AWS Secrets Manager에만 존재하고, ESO가 클러스터에 동기화합니다.

10. Pod에서 Secret을 안전하게 사용하기

Secret을 Pod에 주입하는 방법은 두 가지입니다: 환경 변수(env)와 볼륨 마운트(volume). 보안 관점에서 볼륨 마운트가 권장됩니다.

10.1 환경 변수 vs 볼륨 마운트

방식 장점 단점
환경 변수 (env) 코드에서 바로 접근 가능 kubectl describe pod로 노출, 프로세스 목록에서 보일 수 있음, Secret 변경 시 Pod 재시작 필요
볼륨 마운트 (volume) 파일 시스템 권한으로 보호, 자동 갱신 가능 파일 읽기 로직 필요
# 권장: 볼륨 마운트 방식
apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
    - name: app
      image: my-app:1.0
      volumeMounts:
        - name: secrets
          mountPath: /etc/secrets
          readOnly: true
  volumes:
    - name: secrets
      secret:
        secretName: db-credentials
        defaultMode: 0400    # 소유자만 읽기 가능

10.2 불필요한 Secret 마운트 방지

# API 접근이 불필요한 Pod에서 ServiceAccount 토큰 마운트 비활성화
apiVersion: v1
kind: Pod
metadata:
  name: simple-worker
spec:
  automountServiceAccountToken: false
  containers:
    - name: worker
      image: worker:1.0

11. 보안 체크리스트

운영 환경에서 Kubernetes Secret을 관리할 때 확인해야 하는 항목입니다.

# 항목 확인 방법
1 etcd 암호화가 활성화되어 있는가 kubectl get secrets -o json의 annotation 확인, 매니지드의 경우 콘솔 확인
2 Secret YAML이 Git에 커밋되어 있지 않은가 git log --all -p -- '*.yaml' | grep 'kind: Secret'
3 Secret 접근 RBAC가 최소 권한인가 kubectl auth can-i get secrets --as=<user> -n <ns>
4 감사 로그가 Secret 접근을 기록하는가 Audit Policy에 secrets 리소스 포함 여부 확인
5 환경 변수 대신 볼륨 마운트를 사용하는가 Deployment YAML의 envFrom vs volumeMounts 확인
6 불필요한 ServiceAccount 토큰이 마운트되지 않는가 automountServiceAccountToken: false 확인
7 Secret 로테이션 전략이 있는가 외부 Secret 관리 도구의 refreshInterval 또는 수동 절차 확인
8 컨트롤러 키(Sealed Secrets) 또는 Vault unseal 키를 백업했는가 백업 절차 및 복구 테스트 여부 확인

12. 비용/운영 고려사항

항목 비용 운영 부담
EKS Secret 암호화 (KMS) KMS API 호출당 $0.03/10,000건 거의 없음 (한 번 설정)
AWS Secrets Manager Secret당 $0.40/월 + API 호출 비용 Secret 생성/갱신 관리
Azure Key Vault 표준 티어 기준 $0.03/10,000 작업 Secret 생성/갱신 관리
HashiCorp Vault (자체 운영) 인프라 비용 (EC2/EKS) HA 구성, unseal, 백업, 업그레이드 관리
HCP Vault 월 $0.03/시간~ (인스턴스 기준) 관리형으로 운영 부담 낮음
Sealed Secrets 무료 (오픈소스) 키 백업, re-seal 관리
External Secrets Operator 무료 (오픈소스) + 외부 저장소 비용 Provider 인증 설정, 동기화 모니터링
Tip
소규모 팀에서 시작한다면 Sealed Secrets로 충분할 수 있습니다. Secret 수가 늘어나고 자동 갱신이 필요해지면 External Secrets Operator로 전환하는 단계적 접근이 실용적입니다. Vault는 동적 Secret, PKI 인증서, 데이터베이스 자격증명 자동 로테이션 등 고급 기능이 필요한 경우에 도입을 검토합니다.

13. 정리

  • Kubernetes Secret은 Base64 인코딩만 적용되며, 기본 설정에서는 etcd에 평문으로 저장됩니다. 단독으로는 보안 수준이 낮습니다.
  • 저장 시 암호화(EncryptionConfiguration 또는 클라우드 KMS)를 반드시 활성화하여 etcd 수준에서 보호해야 합니다.
  • RBAC로 Secret 접근을 최소화하고, 감사 로그로 접근 이력을 추적합니다.
  • Git에 Secret을 저장하지 않기 위해 외부 Secret 관리 도구를 사용합니다. 팀 규모와 요구사항에 따라 Sealed Secrets, External Secrets Operator, HashiCorp Vault 중 선택합니다.
  • Pod에서는 환경 변수보다 볼륨 마운트 방식이 보안상 안전합니다. 불필요한 토큰 마운트는 비활성화합니다.
  • Secret 보안은 단일 도구가 아닌 여러 계층(암호화, 접근 제어, 외부 관리, 감사)의 조합으로 달성됩니다.

참고 문서

반응형