[CKS] Demo Encrypting Secret Data at Rest

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

개요

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

Kubernetes Secret 저장하기

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

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

# 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을 저장하는 방식을 정리했습니다.

따라서 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 접근 권한과 적절한 인증서만 있다면 누구나 검색하고 해독 가능합니다.

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

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

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

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으로 암호화되지 않은 데이터 읽기용

Kube API Server manifest 업데이트

mkdir /etc/kubernetes/enc
mv enc.yaml /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 -