LabHub

쿠버네티스 운영 실무 · Secret 보관 방법 · 실습

etcd 안의 평문을 직접 확인하고 막기

LabHub 에서 이어서 보기

목표

Secret 이 실제로 어떻게 저장되는지 etcd 를 직접 열어 확인하고, 저장 시 암호화·봉투 암호화·접근 통제·외부 저장소라는 네 겹의 대응을 각각 매니페스트로 작성합니다.

왜 중요한가

가장 많이 퍼진 오해가 "Secret 은 base64 라 안전하다"입니다. base64 는 키가 없는 표현 방식이라 되돌리는 데 명령 하나면 되고, 더 중요한 것은 기본 설정에서 apiserver 가 Secret 을 평문 그대로 etcd 에 쓴다는 사실입니다. 앞 모듈에서 배운 etcd 스냅샷은 그래서 클러스터에서 가장 민감한 파일이기도 합니다. 이 실습에서는 그 사실을 남의 말이 아니라 자기 손으로 확인합니다. 대응은 한 겹이 아닙니다. EncryptionConfiguration 은 디스크를 얻은 사람을 막고, KMS 봉투 암호화는 그 키마저 클러스터 밖으로 뺍니다. 그러나 저장을 암호화해도 API 로 읽을 수 있는 사람에게는 소용이 없으므로 RBAC 가 필요하고, resourceNames 로 이름 단위까지 좁힐 수 있지만 그것이 list/watch 에는 통하지 않는다는 한계도 알아야 합니다. 마지막으로 값을 아예 클러스터 밖에 두는 외부 시크릿 방식까지, 네 겹이 각각 무엇을 막고 무엇을 못 막는지 구분하는 것이 이 실습의 핵심입니다.

단계

1. 네임스페이스 secret-lab 을 만들고 그 안에 Secret db-password 를 만드세요. 타입은 Opaque 이고 키 password 의 값은 labhub-Pr0d-2026 입니다. 뒤에서 권한을 비교할 대조군으로 Secret other-secret 도 하나 만드세요.
2. db-passworddata.password 값을 그대로 /root/ops/secrets/out/encoded.txt 에, 그것을 디코딩한 평문을 /root/ops/secrets/out/decoded.txt 에 저장하세요(디코딩 결과는 labhub-Pr0d-2026 이어야 하고 두 파일은 서로 대응해야 합니다). 그리고 /root/ops/secrets/out/base64-note.txt 에 base64 가 인코딩일 뿐 암호화가 아니라는 결론을 한 줄로 적으세요.
3. /root/ops/secrets/encryption-config.yaml 을 쓰세요. apiVersionapiserver.config.k8s.io/v1, kindEncryptionConfiguration 이고 resources[0].resourcessecrets 가 들어가야 합니다. providers첫 번째는 실제 암호화 프로바이더(aescbc, secretbox, aesgcm 중 하나)이며 keys[0].name 이 있어야 하고, 마지막identity 여야 합니다.
4. /root/ops/secrets/kms-config.yaml 을 쓰세요. kindEncryptionConfiguration 이고 providers[0]kms 여야 합니다. kms.apiVersionv2, kms.endpointunix:// 로 시작하는 소켓 경로, kms.name 도 있어야 합니다. 그리고 /root/ops/secrets/out/envelope-note.txt 에 봉투 암호화의 두 층 구조(데이터 키와 마스터 키)를 설명해 적으세요.
5. /root/ops/secrets/external-secret.yaml 에 문서 두 개를 쓰세요. 하나는 kind: SecretStore, 다른 하나는 kind: ExternalSecret 입니다. ExternalSecret 에는 spec.refreshInterval, spec.secretStoreRef.name, spec.target.name, spec.target.creationPolicy, spec.data[0].remoteRef.key 가 모두 있어야 합니다. 이 파일에 실제 비밀번호 labhub-Pr0d-2026 이 들어가면 안 됩니다.
6. secret-lab 에 ServiceAccount db-client 를 만들고, Role db-secret-reader 를 만드세요. 규칙은 secrets 리소스에 대해 resourceNamesdb-password 하나, verbsget 하나뿐이어야 합니다. 이 역할을 db-client 에게 RoleBinding 으로 거세요. 결과적으로 db-clientdb-password 는 읽고, other-secret 은 읽지 못하며, 시크릿 목록 조회(list)도 못 해야 합니다. 그리고 /root/ops/secrets/out/resourcenames-note.txtresourceNameslist/watch 에는 통하지 않는다는 점을 적으세요.
7. secret-lab 에 Secret pinned-config 를 만드세요. immutable: true 이고 키 build 의 값은 2026-08-20 입니다. 그다음 이 값을 바꾸려고 시도하고 거부 메시지를 /root/ops/secrets/out/immutable-error.txt 에 저장하세요. 저장 후에도 build 값은 여전히 2026-08-20 이어야 합니다.
8. etcd 에서 /registry/secrets/secret-lab/db-password 키를 조회한 출력을 /root/ops/secrets/out/etcd-secret.txt 에 저장하세요. 이 파일 안에 평문 labhub-Pr0d-2026 이 보여야 합니다. 그리고 /root/ops/secrets/out/secrets-audit.json 을 만드세요. total_secretssecret-lab실제 Secret 개수와 일치해야 하고, encrypted_at_restfalse, plaintext_visible_in_etcdtrue 입니다. mitigations 배열에는 대응 방안을 3개 이상 적되 저장 시 암호화(EncryptionConfiguration 또는 "암호화")와 접근 권한 통제(RBAC 또는 "권한")가 반드시 포함돼야 합니다.

참고

단계 8개

  1. 실습용 Secret 두 개 만들기
  2. base64 를 직접 되돌려 보기
  3. 저장 시 암호화 설정 쓰기
  4. KMS v2 봉투 암호화 설정 쓰기
  5. 외부 시크릿 저장소 연동 매니페스트 쓰기
  6. 시크릿 하나만 여는 역할 만들기
  7. 불변 Secret 만들고 수정 거부 확인하기
  8. etcd 에서 평문을 꺼내 증거로 남기기