Theme:

Kubernetes Secret이 base64로 인코딩된다는 건 알겠는데, 그게 정말 "안전한" 건가요?

결론부터 말하면, base64는 암호화가 아닙니다. echo 'cEBzc3cwcmQ=' | base64 -d를 실행하면 즉시 원문이 보입니다. Kubernetes Secret의 기본 보안은 RBAC로 접근을 제한하는 것뿐이며, 실제 암호화를 위해서는 추가적인 설정이 필요합니다.

Secret의 기본 보안 수준

Kubernetes Secret의 기본 상태를 정리하면 다음과 같습니다.

항목상태위험도
저장 형태 (etcd)base64 인코딩 (평문)높음
네트워크 전송TLS 암호화 (API Server ↔ etcd)낮음
API 접근RBAC로 제어설정에 따라
Git 저장평문 노출 위험매우 높음
SHELL
# Secret 값 쉽게 확인 가능
kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d
# p@ssw0rd

etcd Encryption at Rest

etcd에 저장되는 Secret을 실제로 암호화하는 설정입니다.

EncryptionConfiguration 설정

YAML
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      # 암호화 프로바이더 (우선순위 순)
      - aescbc:
          keys:
            - name: key1
              secret: <base64로 인코딩된 32바이트 키>
      # identity는 암호화 안 함 — 기존 데이터 읽기용
      - identity: {}
SHELL
# 암호화 키 생성
head -c 32 /dev/urandom | base64

# API Server 설정에 추가
# kube-apiserver 실행 옵션:
# --encryption-provider-config=/etc/kubernetes/encryption-config.yaml

암호화 알고리즘 비교

알고리즘특징권장
aescbcAES-CBC, 안정적일반적 사용
aesgcmAES-GCM, 인증된 암호화키 순환 필수
secretboxXSalsa20+Poly1305, 빠름권장
kms외부 KMS 연동 (AWS KMS 등)프로덕션 권장

KMS 연동 (AWS KMS 예제)

YAML
providers:
  - kms:
      apiVersion: v2
      name: aws-kms
      endpoint: unix:///var/run/kmsplugin/socket.sock

AWS KMS를 사용하면 암호화 키를 Kubernetes 외부에서 관리할 수 있어 보안이 한 단계 더 강화됩니다.

기존 Secret 재암호화

EncryptionConfiguration을 적용해도 기존에 저장된 Secret은 업데이트하기 전까지 평문입니다.

SHELL
# 모든 Secret 재암호화
kubectl get secrets --all-namespaces -o json | kubectl replace -f -

External Secrets Operator (ESO)

외부 시크릿 관리 서비스의 값을 Kubernetes Secret으로 자동 동기화합니다.

SHELL
# ESO 설치
helm install external-secrets external-secrets/external-secrets \
  --namespace external-secrets \
  --create-namespace

AWS Secrets Manager 연동

YAML
# SecretStore — 외부 소스 연결 설정
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: aws-secrets
  namespace: production
spec:
  provider:
    aws:
      service: SecretsManager
      region: ap-northeast-2
      auth:
        jwt:
          serviceAccountRef:
            name: eso-sa
---
# ExternalSecret — 동기화 규칙
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h          # 1시간마다 동기화
  secretStoreRef:
    name: aws-secrets
    kind: SecretStore
  target:
    name: db-credentials       # 생성될 Kubernetes Secret 이름
    creationPolicy: Owner
  data:
    - secretKey: username      # Kubernetes Secret의 키
      remoteRef:
        key: production/db     # AWS Secrets Manager의 시크릿 이름
        property: username     # JSON 속성
    - secretKey: password
      remoteRef:
        key: production/db
        property: password

ESO가 AWS Secrets Manager에서 값을 가져와 Kubernetes Secret을 자동으로 생성하고, refreshInterval마다 동기화합니다.

HashiCorp Vault 연동

YAML
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault
spec:
  provider:
    vault:
      server: "https://vault.example.com"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "app-role"
          serviceAccountRef:
            name: vault-sa

Sealed Secrets — GitOps 친화적

Sealed Secrets는 Git에 안전하게 저장할 수 있는 암호화된 Secret을 제공합니다.

SHELL
# 컨트롤러 설치
helm install sealed-secrets sealed-secrets/sealed-secrets \
  --namespace kube-system

# kubeseal CLI로 Secret 암호화
kubectl create secret generic db-secret \
  --from-literal=password=p@ssw0rd \
  --dry-run=client -o yaml | \
  kubeseal --format yaml > sealed-secret.yaml
YAML
# sealed-secret.yaml — Git에 커밋해도 안전
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: db-secret
  namespace: production
spec:
  encryptedData:
    password: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq...

클러스터의 Sealed Secrets 컨트롤러만이 이를 복호화하여 일반 Secret으로 변환합니다.

시크릿 관리 전략 비교

방식복잡도보안 수준GitOps키 관리
기본 Secret + RBAC낮음기본불가수동
etcd 암호화중간중간불가수동/KMS
Sealed Secrets중간높음가능자동
ESO + Vault/AWS SM높음매우 높음가능외부 관리

시크릿 관리 모범 사례

  1. 최소한: etcd 암호화 + RBAC 제한
  2. GitOps: Sealed Secrets 사용
  3. 엔터프라이즈: ESO + Vault/AWS Secrets Manager

추가 보안 조치

YAML
# Secret 접근 감사 로그 활성화
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: Metadata
    resources:
      - group: ""
        resources: ["secrets"]
SHELL
# Secret을 사용하는 Pod 확인
kubectl get pods --all-namespaces -o json | \
  jq '.items[] | select(.spec.volumes[]?.secret) | .metadata.name'

# 불필요한 Secret 정리
kubectl get secrets --all-namespaces --no-headers | wc -l

실무에서 주의할 점

  • Secret을 Git에 절대 커밋하지 마세요: .gitignore에 추가하거나 Sealed Secrets를 사용
  • 환경변수보다 볼륨 마운트를 권장합니다: 환경변수는 프로세스 목록이나 로그에 노출될 수 있습니다
  • 시크릿 교체(rotation) 자동화: ESO의 refreshInterval이나 Vault의 동적 시크릿 활용
  • 감사 로그를 활성화하세요: 누가 언제 Secret에 접근했는지 추적

정리

Kubernetes Secret의 base64는 암호화가 아닙니다. 최소한 etcd 암호화와 RBAC 제한을 적용하고, GitOps 환경에서는 Sealed Secrets, 엔터프라이즈 환경에서는 External Secrets Operator와 Vault/AWS Secrets Manager를 조합하여 시크릿을 안전하게 관리해야 합니다.

댓글 로딩 중...