Secret in Runtime Config Files

일부 서비스는 애플리케이션 구조상 config.yaml, application.yml, settings.json 같은 설정 파일 자체를 유지해야 합니다. 이 경우에도 Secret 원문을 저장소에 커밋하면 안 되며, 실제 설정 파일은 런타임에 안전한 소스에서 생성하거나 마운트해야 합니다.

이런 경우에 참고

  • 환경 변수만으로 설정 구조를 바꾸기 어려운 경우
  • 애플리케이션이 특정 파일 경로의 설정 파일을 반드시 읽는 경우
  • config.yaml.example는 필요하지만 실제 config.yaml도 운영에 필요한 경우
  • Kubernetes, Vault Agent, CSI driver, 배포 시스템의 secure file delivery를 사용할 수 있는 경우

기본 권장 패턴

  • 저장소에는 config.yaml.example만 둡니다.
  • 실제 config.yaml은 Git에 커밋하지 않습니다.
  • 실제 파일은 Kubernetes Secret volume, CSI/Vault Agent, 배포 시스템의 secure file delivery를 통해 런타임에 생성하거나 마운트합니다.
  • 애플리케이션은 지정된 파일 경로에서 설정을 읽되, 파일이 없거나 필수 Secret이 비어 있으면 fail closed로 종료합니다.

언제 이 패턴을 선택하는가

  • 애플리케이션이 특정 파일 경로의 설정 파일을 반드시 읽어야 하는 경우
  • 환경 변수만으로 계층형 설정 구조를 표현하기 어려운 경우
  • 배포 플랫폼이 Secret file mount 또는 secure file delivery를 표준으로 제공하는 경우

금지 패턴

  • 운영용 config.yaml을 저장소에 커밋
  • Secret이 포함된 config.yaml을 ConfigMap에 저장
  • Docker image 안에 config.yaml을 bake-in
  • Dockerfile에서 운영용 config.yaml을 COPY
  • 수동 배포 파일을 기본 운영 패턴으로 문서화

권장 구조

text
config.yaml.example         # 샘플 설정만 포함, Git 커밋 가능
config.yaml                 # 실제 운영 설정, Git 커밋 금지
.gitignore                  # config.yaml 포함
/etc/app/config.yaml        # 런타임에 마운트되거나 생성되는 실제 설정 파일 예시

예시

변경 전

yaml
database:
  host: prod-db.internal
  user: app_user
  password: super-secret-password

jwt:
  secret: hardcoded-jwt-secret

위와 같은 파일이 저장소에 포함되어 있으면 Secret 유출로 간주해야 합니다.

변경 후

저장소에 두는 파일: config.yaml.example

yaml
database:
  host: prod-db.internal
  user: app_user
  password: "<runtime-provided>"

jwt:
  secret: "<runtime-provided>"

런타임 파일 경로 예시

text
/etc/app/config.yaml

이 파일은 Kubernetes Secret volume, Vault Agent/CSI, 또는 배포 시스템의 secure file delivery가 런타임에 생성하거나 마운트합니다.

파일 권한 가이드

  • 설정 파일은 애플리케이션 실행 사용자만 읽을 수 있도록 최소 권한으로 설정합니다.
  • world-readable 권한을 금지합니다.
  • owner와 group을 운영 표준에 맞게 제한합니다.

일반적인 쓰기 가능한 파일의 권한 설정 예시입니다. Kubernetes Secret volume처럼 읽기 전용인 마운트는 볼륨 설정에서 권한과 소유권을 구성하세요.

bash
chmod 600 /etc/app/config.yaml
chown appuser:appgroup /etc/app/config.yaml

Kubernetes 예시

  • Secret 또는 외부 Secret 연동 리소스에 설정 파일 내용을 저장합니다.
  • Pod에는 Secret volume으로 /etc/app/config.yaml을 마운트합니다.
  • ConfigMap으로 대체하지 않습니다.

개발자 해야 할 일

  • 저장소에 있는 실제 설정 파일에서 Secret 값을 제거합니다.
  • 애플리케이션이 런타임 파일 경로를 읽도록 유지하되, 파일 누락과 필수 값 누락 시 즉시 실패하게 수정합니다.
  • 설정 객체 전체를 로그, panic, debug dump로 출력하지 않도록 수정합니다.
  • Secret 회전 시 reload 또는 restart가 필요한지 애플리케이션 동작을 문서화합니다.

인프라/플랫폼 해야 할 일

  • 실제 설정 파일을 Kubernetes Secret volume, CSI/Vault Agent, 또는 secure file delivery로 공급합니다.
  • ConfigMap, Docker image bake-in, Dockerfile COPY를 사용하지 않도록 배포 표준을 정합니다.
  • 파일 owner, group, 권한을 최소화합니다.
  • Secret 회전 시 파일 갱신과 restart/reload 절차를 운영 문서에 포함합니다.

검증 방법

  • 저장소에 운영용 설정 파일이 없는지 확인합니다.
  • 컨테이너 또는 호스트에서 설정 파일 권한이 최소화되어 있는지 확인합니다.
  • 애플리케이션이 파일 누락 시 정상적으로 실패하는지 확인합니다.
  • 설정 값이 로그, actuator, 예외 메시지에 노출되지 않는지 확인합니다.

자주 하는 실수

  • 운영용 config.yaml을 Git에 커밋
  • Secret이 들어 있는 설정 파일을 ConfigMap에 저장
  • Docker image에 설정 파일 bake-in
  • 파일 권한을 넓게 열어 두고 world-readable 상태로 배포
  • Secret rotation은 했지만 reload/restart 절차를 정의하지 않음

담당자 조치 절차

노출된 자격 증명은 아래 파일 정리나 배포 변경을 기다리지 말고 먼저 폐기·비활성화하고 새 값으로 교체하세요.

  1. 저장소에 커밋된 실제 config.yaml에서 Secret 값을 제거합니다.
  2. 저장소에는 config.yaml.example만 남기고 실제 config.yaml은 .gitignore에 추가합니다.
  3. 실제 config.yaml은 Kubernetes Secret volume, CSI/Vault Agent, 또는 secure file delivery로 런타임에 공급합니다.
  4. 애플리케이션은 지정 파일 경로를 읽도록 유지하되, 파일 누락이나 필수 Secret 누락 시 즉시 종료하도록 수정합니다.
  5. 설정 파일 권한을 최소화하고 world-readable 상태를 제거합니다.
  6. 디버그 로그, panic, 설정 dump에 Secret 값이 노출되지 않도록 마스킹합니다.
  7. Secret 회전 시 파일 갱신 후 reload 또는 restart 절차를 운영 문서에 명시합니다.
  8. 기존 값이 저장소에 노출되었다면 폐기 및 재발급합니다.

담당자에게 안내할 문구 예시

  • "config.yaml 형식을 유지해야 하더라도 실제 운영 파일은 Git에 커밋하지 말고 런타임에 안전하게 마운트하세요."
  • "저장소에는 config.yaml.example만 남기고, 실제 config.yaml은 Kubernetes Secret volume 또는 배포 시스템의 secure file delivery로 공급하세요."
  • "설정 파일이 없거나 필수 Secret이 비어 있으면 애플리케이션이 즉시 실패하도록 구성하세요."
  • "Secret이 포함된 config.yaml을 Docker image나 ConfigMap에 포함시키지 마세요."

운영 체크리스트

  • .gitignore에 실제 설정 파일이 포함되어 있는가
  • config.yaml.example와 실제 config.yaml의 역할이 분리되어 있는가
  • 설정 파일 권한이 최소화되어 있는가
  • 로그, panic, debug dump에 전체 설정 객체를 출력하지 않는가
  • Secret rotation 시 reload 또는 restart 절차가 정의되어 있는가
  • 예외적으로 수동 배치를 하더라도 기본 권장 방식이 아닌 fallback으로만 관리하는가

관련 문서