← 목록으로 돌아가기

프로덕션 시크릿 관리 실전: Vault·단기 자격증명·자동 회전·CI/CD 유출 방지

DevOps

Production Secret Management Rotation Vault

시크릿은 환경변수에 넣는 순간 끝난 것이 아니다

데이터베이스 비밀번호, API token, OAuth client secret, webhook signing key, cloud access key는 모두 서비스의 혈관입니다. 그런데 많은 팀에서 시크릿 관리는 배포 설정의 부속품처럼 다뤄집니다. .env 파일을 만들고, CI 변수에 넣고, Kubernetes Secret으로 배포하면 끝이라고 생각합니다. 문제는 시크릿의 진짜 운영이 그 다음부터 시작된다는 점입니다.

시크릿은 언젠가 유출됩니다. 로그에 찍힐 수 있고, Slack에 복사될 수 있고, CI job artifact에 남을 수 있고, 퇴사자의 로컬 노트북에 남을 수 있습니다. 중요한 것은 유출 가능성을 0으로 만드는 것이 아니라, 유출됐을 때 피해 범위와 시간을 줄이는 것입니다. 이를 위해서는 단기 자격증명, 자동 회전, 접근 감사, least privilege, 배포 파이프라인 마스킹이 필요합니다.

이 글에서는 프로덕션 시크릿 관리를 플랫폼 운영 관점에서 정리합니다. Vault나 cloud secret manager 같은 중앙 저장소를 어떻게 써야 하는지, Kubernetes Secret의 한계는 무엇인지, CI/CD에서 시크릿이 새는 경로는 어디인지, rotation을 실제로 자동화하려면 어떤 계약이 필요한지 다룹니다.


1. 시크릿 저장소와 설정 저장소를 분리한다

모든 설정이 시크릿은 아닙니다. Feature flag, timeout, endpoint URL, batch size는 노출되어도 큰 문제가 없을 수 있습니다. 반면 DB password, private key, signing secret은 접근 통제와 감사가 필요합니다. 둘을 같은 config map이나 같은 env 파일에 섞으면 권한 모델이 흐려집니다. 시크릿은 별도 저장소와 별도 접근 정책을 가져야 합니다.

중앙 시크릿 저장소의 장점은 정책을 한곳에서 관리할 수 있다는 것입니다. 누가 어떤 시크릿을 읽었는지 감사 로그를 남기고, 서비스별 권한을 나누고, rotation을 자동화할 수 있습니다. HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault 같은 도구가 여기에 해당합니다. 중요한 것은 도구 이름이 아니라 중앙화된 발급, 접근 통제, 감사, 회전 기능입니다.

시크릿을 애플리케이션에 전달하는 방식도 선택해야 합니다. 시작 시점에 환경변수로 주입할 수도 있고, sidecar나 agent가 파일로 동기화할 수도 있고, 애플리케이션이 런타임에 secret manager API를 호출할 수도 있습니다. 환경변수는 단순하지만 프로세스 시작 후 갱신이 어렵고, crash dump나 진단 도구에 노출될 수 있습니다. 런타임 조회는 회전에 유리하지만 secret manager 장애와 latency를 고려해야 합니다.


2. 장기 고정 키를 줄이고 단기 자격증명을 쓴다

가장 안전한 시크릿은 오래 살지 않는 시크릿입니다. 데이터베이스 계정을 서비스마다 고정 비밀번호로 발급하고 1년 동안 쓰면, 한 번 유출된 비밀번호가 오래 살아 있습니다. 반대로 Vault dynamic secret처럼 짧은 TTL의 DB credential을 발급하면 유출돼도 사용 가능한 시간이 제한됩니다.

Cloud 권한도 마찬가지입니다. CI/CD에 장기 access key를 저장하는 대신 OIDC federation을 사용해 job 실행 시점에만 단기 token을 발급받는 방식이 안전합니다. GitHub Actions, GitLab CI, major cloud provider는 이런 흐름을 지원합니다. 장기 키를 없애면 rotation 부담도 줄고, 유출 사고의 blast radius도 작아집니다.

단기 자격증명은 애플리케이션 갱신 전략이 필요합니다. TTL이 1시간인 credential을 쓰면서 connection pool이 영원히 같은 password를 들고 있으면 만료 후 장애가 납니다. Credential refresh, connection recycle, grace period를 함께 설계해야 합니다. Secret manager가 새 credential을 발급했을 때 애플리케이션이 자연스럽게 새 연결을 만들 수 있어야 합니다.


3. Rotation은 이벤트가 아니라 루틴이어야 한다

시크릿 rotation을 사고 후 수동 절차로만 해두면 실제 사고 때 느립니다. 어떤 서비스를 재시작해야 하는지, 어떤 외부 시스템에 새 키를 등록해야 하는지, 이전 키를 언제 폐기해야 하는지 알기 어렵습니다. Rotation은 평소에도 주기적으로 실행되는 루틴이어야 합니다. 그래야 절차가 검증됩니다.

좋은 rotation은 overlap 기간을 둡니다. Signing key나 webhook secret처럼 producer와 consumer가 동시에 바뀌기 어려운 경우, 새 키와 이전 키를 일정 기간 함께 허용합니다. Producer는 새 키로 서명하고, consumer는 새 키와 이전 키를 모두 검증합니다. 충분한 배포 시간이 지난 뒤 이전 키를 제거합니다. 이중 검증 기간 없이 즉시 교체하면 일부 인스턴스가 실패합니다.

DB password rotation은 더 복잡합니다. 새 계정을 만들고 권한을 부여한 뒤 애플리케이션이 새 credential을 사용하도록 전환하고, 기존 connection이 빠질 시간을 준 뒤 옛 계정을 폐기합니다. 하나의 계정 비밀번호를 제자리에서 바꾸는 방식은 기존 connection과 재연결 타이밍에 민감합니다. 가능하다면 blue/green credential 전략이 더 안전합니다.

Rotation 성공 여부도 지표로 봐야 합니다. 마지막 회전 시각, 회전 실패 횟수, 만료 예정 시크릿 수, 이전 키 사용 요청 수를 대시보드에 올립니다. 이전 키 사용량이 계속 남아 있다면 아직 전환되지 않은 서비스가 있다는 뜻입니다. 이 지표 없이 날짜만 믿고 이전 키를 삭제하면 장애가 납니다.


4. Kubernetes Secret의 한계를 이해한다

Kubernetes Secret은 편리하지만 그 자체로 완전한 secret manager는 아닙니다. 기본적으로 etcd에 저장되며, 클러스터 설정에 따라 암호화 at rest가 필요합니다. RBAC 권한이 넓으면 많은 사람이 secret을 읽을 수 있습니다. Pod에 환경변수로 들어간 시크릿은 런타임 회전이 어렵습니다.

GitOps 환경에서는 sealed secret이나 external secret operator를 많이 씁니다. Sealed Secret은 암호화된 형태로 Git에 저장하고 클러스터 안에서만 복호화합니다. External Secrets Operator는 cloud secret manager나 Vault에서 값을 가져와 Kubernetes Secret으로 동기화합니다. 둘 다 장단점이 있습니다. Sealed Secret은 Git workflow에 잘 맞지만 rotation 자동화가 별도이고, External Secret은 중앙 secret manager와 잘 연결되지만 operator와 권한 구성이 중요합니다.

중요한 것은 secret이 Git에 평문으로 들어가지 않게 하는 것입니다. 실수로 커밋된 secret은 삭제 커밋을 해도 history에 남습니다. Secret scanning, pre-commit hook, repository push protection을 켜야 합니다. 유출된 키는 "삭제"가 아니라 "폐기 및 재발급"이 원칙입니다.


5. CI/CD는 시크릿 유출의 주요 경로다

CI/CD는 많은 권한을 가집니다. 배포 credential, package registry token, cloud role, signing key가 모입니다. 동시에 로그와 artifact가 많이 남는 환경입니다. 스크립트에서 set -x를 켜거나, 실패 디버깅을 위해 환경변수를 출력하거나, test report에 request header가 남으면 secret이 유출됩니다.

CI 변수 마스킹은 필요하지만 충분하지 않습니다. 마스킹은 정확히 같은 문자열에만 동작하는 경우가 많고, base64 인코딩이나 일부 substring에는 실패할 수 있습니다. Secret을 command line argument로 넘기면 process list나 shell history에 남을 수 있습니다. 가능하면 stdin, 파일 descriptor, 전용 credential helper를 사용하고, 로그에는 절대 출력하지 않습니다.

권한도 job 단위로 최소화해야 합니다. 모든 workflow가 production deploy 권한을 갖는 구조는 위험합니다. Pull request 검증 job에는 읽기 권한만 주고, main branch 배포 job에만 제한된 배포 권한을 줍니다. OIDC 기반 cloud role assume을 쓰면 repository, branch, environment 조건으로 권한을 제한할 수 있습니다.

Artifact 보존 정책도 봐야 합니다. 빌드 결과물, coverage report, test snapshot, container layer에 secret이 들어갈 수 있습니다. 이미지 빌드 중 private token을 ARG로 넘기면 layer history에 남을 수 있습니다. BuildKit secret mount처럼 layer에 남지 않는 방식을 사용해야 합니다.


6. 감사와 대응: 누가 읽었는지 알아야 한다

시크릿 접근은 감사 가능해야 합니다. 어떤 workload가 어떤 시크릿을 언제 읽었는지, 어떤 사용자가 수동으로 조회했는지, 실패한 접근 시도가 있었는지 기록해야 합니다. 감사 로그가 없으면 유출 의심 상황에서 폐기 범위를 판단할 수 없습니다. 모든 키를 한꺼번에 바꾸는 것은 느리고 위험합니다.

접근 주체도 사람보다 workload identity 중심으로 가야 합니다. 서버에 공용 credential 파일을 두고 여러 서비스가 공유하면 누가 사용했는지 알 수 없습니다. 서비스 계정, Kubernetes service account, cloud workload identity를 사용해 workload별 권한을 나눕니다. 사람이 production secret을 직접 읽는 경우는 break-glass 절차로 제한하고, 사유와 만료 시간을 남깁니다.

유출 대응 절차는 미리 있어야 합니다. 키 식별, 영향 범위 파악, 새 키 발급, dual validation 전환, 옛 키 폐기, 로그와 artifact 정리, 사후 보고 순서가 문서화되어 있어야 합니다. 사고 중에 처음 rotation 방법을 찾으면 늦습니다. 정기 rotation 훈련은 보안뿐 아니라 운영 안정성에도 도움이 됩니다.


실무 체크리스트

  • 시크릿과 일반 설정이 저장소와 권한 모델에서 분리되어 있는가
  • 장기 cloud access key 대신 OIDC 기반 단기 자격증명을 사용하는가
  • DB credential이나 외부 API key rotation 절차가 자동화되어 있는가
  • 새 키와 이전 키가 공존하는 overlap 기간을 지원하는가
  • Kubernetes Secret이 etcd 암호화와 RBAC 최소 권한 아래 관리되는가
  • Git 저장소에 평문 secret이 들어가지 않도록 scanning과 push protection이 켜져 있는가
  • CI 로그, artifact, container layer에 secret이 남지 않도록 검증하는가
  • Secret 접근 감사 로그를 남기고 이상 접근을 알림으로 연결했는가
  • Break-glass 접근 절차와 사고 시 폐기/재발급 runbook이 있는가

결론: 시크릿 관리는 회전 가능한 신뢰를 만드는 일이다

시크릿 보안의 목표는 아무도 키를 보지 못하게 하는 데서 끝나지 않습니다. 누가 어떤 권한으로 접근했는지 알고, 오래 사는 키를 줄이고, 유출됐을 때 빠르게 바꾸고, 바꾸는 과정이 서비스 장애로 이어지지 않게 만드는 것입니다. 즉 시크릿 관리는 저장이 아니라 생명주기 관리입니다.

환경변수와 Kubernetes Secret은 출발점일 뿐입니다. 프로덕션에서는 중앙 secret manager, 단기 자격증명, 자동 rotation, CI/CD 유출 방지, 감사 로그가 함께 필요합니다. 키는 언젠가 새어나갈 수 있습니다. 잘 설계된 시스템은 그 사실을 전제로 피해 시간을 짧게 만들고, 회전 절차를 평소에도 반복해 둡니다.