[CKS] Demo Encrypting Secret Data at Rest

Kubernetes etcd에 저장된 Secret 데이터를 AES-CBC 암호화로 보호하는 방법입니다. 암호화 설정을 활성화하여 기밀 정보 노출을 방지할 수 있습니다.

[CKS] Demo Encrypting Secret Data at Rest
Photo by Gabriela / Unsplash

개요

CKS 자격증을 위해 아래 내용을 정리했습니다.

Kubernetes Secret 저장하기

k8s etcd에 저장된 비밀 데이터를 암호화하여 안전하게 보호하는 방법을 설명합니다.

Secret 객체 생성, base64 인코딩 저장, 암호화 설정 활성화까지 etcd에 안전하게 보호하는 방법을 확인합니다.

  • 시크릿 객체 생성 (예시입니다)
    • --allow-missing-template-keys=true
    • --append-hash=false
    • --dry-run='none'
# Create a new secret named my-secret by loading files from a directory
kubectl create secret generic my-secret --from-file=path/to/bar


# Create a secret with specified keys taken from disk files
kubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa --from-file=ssh-publickey=path/to/id_rsa.pub


# Create a secret with literal values for keys
kubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret


# Create a secret using a combination of a file and a literal value
kubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa --from-literal=passphrase=topsecret


# Create a secret from environment files
kubectl create secret generic my-secret --from-env-file=path/to/foo.env --from-env-file=path/to/bar.env

기본적인 secert 생성 방법과 확인 방법은 아래 가이드를 참고하세요

Secret이 base64를 통해 인코딩되어 저장된다는 것을 명심하세요.

저장 시 암호화가 되어있지않다면 누구나 접근하여 기밀 데이터를 노출하거나 열람할 수 있습니다.

Inspecting Secrets in etcd

etcd에 Secret을 저장하는 방식을 정리했습니다.

  • /registry/secrets/default/secret1 Secret은 다음과 같은 정보에 저장됩니다.

따라서 etcdctl 명령어를 통해 원시 데이터를 볼 수 있습니다.

apt-get install etcd-client
ETCDCTL_API=3 etcdctl \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  get /registry/secrets/default/secret1 | hexdump -C
2f 72 65 67 69 73 74 72 79 2f 73 65 63 72 65 74  |/registry/secret|
31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |1..............|
31 2e 6b 38 73 73 73 73 73 73 73 73 73 73 73 73  |1.k8sssssssssss...|
06 2f 76 31                                     |./v1|

암호화되지 않은 상태로출력됩니다. 따라서 etcd 접근 권한과 적절한 인증서만 있다면 누구나 검색하고 해독 가능합니다.

  • 암호화 되었다면 k8s:enc:aescbc:v1:key1 로 구성됩니다.

저장 데이터 암호화 활성화 여부 확인

  • --encryption-provider-config 파라미터 혹은 API Server Manifest 파일을 확인합니다.
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep encryption-provider-config
apiVersion: v1
kind: Pod
metadata:
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver

    - --encryption-provider-config=/etc/kubernetes/enc/encryption-config.yaml  # 이 라인이 있어야 함

    - --advertise-address=192.168.1.10
    - --allow-privileged=true
    # ... 기타 파라미터들
    volumeMounts:
    - mountPath: /etc/kubernetes/enc
      name: enc
      readOnly: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/enc
      type: DirectoryOrCreate
    name: enc

암호화 구성 파일을 확인할 수 있습니다.

  • enc.yaml (encryption-config.yaml****)
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64로 인코딩된 32바이트 키> # head -c 32 /dev/urandom | base64
      - identity: {}  # fallback으로 암호화되지 않은 데이터 읽기용
  • AES-CBC 알고리즘 사용
  • identity: {} 는 fallback용. → 상단에 위치하면 암호화가 적용되지 않습니다.

Kube API Server manifest 업데이트

  • 암호화 파일을 저장할 로컬 디렉터리를 생성합니다(예: /etc/kubernetes/enc)
mkdir /etc/kubernetes/enc
mv enc.yaml /etc/kubernetes/enc/
  • Kube API Server 매니페스트( /etc/kubernetes/manifests/kube-apiserver.yaml)를 수정
    • --encryption-provider-config 플래그를 추가
    • 새로운 볼륨 마운트(암호화 파일 디렉토리 → /etc/kubernetes/enc)
spec:
  containers:
  - command:
    - kube-apiserver
    ...
    - --encryption-provider-config=/etc/kubernetes/enc/enc.yaml
  volumeMounts:
    ...
    - name: enc
      mountPath: /etc/kubernetes/enc
      readOnly: true
  volumes:
    ...
    - name: enc
      hostPath:
        path: /etc/kubernetes/enc
        type: DirectoryOrCreate

변경사항을 저장하면 API Server가 다시 시작된 뒤 새로운 구성이 로드됩니다

ps aux | grep kube-api

암호화 검증

kubectl create secret generic my-secret-2 --from-literal=key2=topsecret

kubectl get secret

NAME          TYPE     DATA   AGE
my-secret     Opaque   1      16m
my-secret-2   Opaque   1      3s

ETCDCTL_API=3 etcdctl \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  get /registry/secrets/default/my-secret-2 | hexdump -C
# 평문 값이 더 이상 보이지 않는지 확인합니다.

기존 secret을 업데이트하렴녀 아래 명령어를 실행합니다.

kubectl get secrets --all-namespaces -o json | kubectl replace -f -