CKS — 쿠버네티스 보안 전문가 · 마이크로서비스 취약점 최소화 · 실습
Secret 다루기와 저장 시 암호화
목표
Secret 을 타입별로 만들고, 주입 방식에 따라 노출 경로가 어떻게 달라지는지 확인하고,
RBAC 으로 읽기 범위를 좁힌 뒤 저장 시 암호화 설정 파일을 직접 작성합니다.
왜 중요한가
Secret 매니페스트의 값이 base64 로 되어 있어 암호화된 것처럼 보이지만, base64 는 인코딩이지
암호화가 아닙니다. 키가 없고 되돌리는 데 명령 하나면 됩니다. 기본 설정에서 Secret 은 etcd 에
평문으로 저장되므로 etcd 백업 파일을 얻은 사람은 모든 Secret 을 읽습니다.
EncryptionConfiguration 을 켜야 비로소 저장된 값이 암호화되고, 이때 identity 프로바이더는
반드시 목록의 마지막이어야 합니다. 앞에 오면 평문 저장으로 되돌아갑니다.
주입 방식도 중요합니다. 환경변수는 /proc/PID/environ 으로 읽히고 자식 프로세스에 상속되며,
크래시 리포트나 디버그 페이지에 통째로 실려 나갑니다. 볼륨 마운트가 더 안전하고,defaultMode 로 파일 권한을 좁히는 것이 관례입니다.
마지막은 RBAC 입니다. 어떤 네임스페이스에 get secrets 권한이 있는 사람은 그 네임스페이스의
모든 Secret 을 읽습니다. resourceNames 로 특정 Secret 만 허용할 수 있다는 사실이 의외로
잘 알려져 있지 않습니다.
단계
1. 네임스페이스 cks-secrets 를 만들고 그 안에 Opaque Secret db-cred 를 만든다.
키는 username(값 app)과 password(값 pr0d-Db-Pass) 두 개다.
2. cks-secrets 에 kubernetes.io/dockerconfigjson 타입 Secret registry-cred 를 만든다.
서버는 registry.cks.local, 사용자는 ci, 비밀번호는 ci-token 이다.
3. cks-secrets 에 kubernetes.io/tls 타입 Secret shop-tls 를 만든다. tls.crt 와tls.key 가 모두 비어 있지 않아야 한다.
4. cks-secrets 에 파드 env-app(컨테이너 이름 app, 이미지 nginx:1.27-alpine)을 만든다.
컨테이너의 envFrom[0].secretRef.name 은 db-cred 다.
5. cks-secrets 에 파드 vol-app(컨테이너 이름 app)을 만든다. 볼륨 이름은 db,secret.secretName 은 db-cred, secret.defaultMode 는 0400(10진수 256)이고,
컨테이너는 그 볼륨을 /etc/db 에 readOnly: true 로 마운트한다.
6. cks-secrets 에 Opaque Secret app-config 를 만든다. 키는 mode(값 strict) 하나이고immutable 은 true 다.
7. cks-secrets 에 ServiceAccount app 을 만들고, Role db-cred-reader 를 만든다.
apiGroups 는 코어 그룹, resources 는 secrets, resourceNames 는 db-cred 하나,
verbs 는 get 하나다. RoleBinding app-db-cred 로 SA app 에 바인딩한다.
그다음 두 질문의 답(yes/no)을 순서대로/root/cks-secrets/can-i.txt 에 두 줄로 저장한다. 첫 줄은 app SA 가secret/db-cred 를 get 할 수 있는지, 두 줄은 secret/app-config 를 get 할 수 있는지다.
8. /root/cks-secrets/encryption-config.yaml 에 저장 시 암호화 설정을 쓴다.apiVersion: apiserver.config.k8s.io/v1, kind: EncryptionConfiguration,resources[0].resources 는 secrets 하나, providers 는 두 개로 첫 번째가 aescbc
(키 이름 key1, secret 은 32 바이트를 base64 인코딩한 값), 마지막이 identity 다.
참고
kubectl create secret generic db-cred --from-literal=username=app --from-literal=password=pr0d-Db-Pass -n cks-secrets- 32 바이트 키 생성:
head -c 32 /dev/urandom | base64 kubectl auth can-i get secret/db-cred -n cks-secrets --as=system:serviceaccount:cks-secrets:app- 흔한 실수 1:
defaultMode: 0400을 따옴표로 감싸면 문자열이 되어 거부됩니다. 숫자로 쓰세요. - 흔한 실수 2: EncryptionConfiguration 에서
identity를 첫 번째에 두면 새로 쓰는 Secret 이 평문으로 저장됩니다. - 흔한 실수 3: 설정을 켜도 기존 Secret 은 다시 쓰기 전까지 평문입니다.
kubectl get secrets -A -o json | kubectl replace -f -로 전체를 갱신해야 합니다.
단계 8개
- Opaque Secret 만들기
- 레지스트리 자격증명 Secret
- TLS Secret
- 환경변수로 주입하기
- 볼륨으로 마운트하고 권한 좁히기
- 변경 불가 Secret
- 특정 Secret 만 읽게 제한
- 저장 시 암호화 설정 파일