Dev 비밀값과 설정 관리 - 100-hours-a-week/KTB4-2nd-Cloud GitHub Wiki

비밀값과 설정 관리

운영 설정과 비밀값은 Parameter Store 한 곳에 두고, 배포할 때마다 각 EC2가 자기 값을 읽어 환경 파일을 새로 만듭니다. Git, Terraform State, GitHub Actions에는 실제 값이 남지 않습니다.


처음에는 서버의 env 파일이 원본이었음

중간 배포 때는 App과 Worker의 /etc/yeodam/*.env 파일을 SSM으로 들어가 직접 고쳤습니다. 이미지 태그를 바꿀 때도, API 키를 추가할 때도 서버에서 sed나 nano로 수정했습니다.

이렇게 운영해보니 불편한 점이 분명했습니다.

  • 어떤 값이 들어가 있는지 서버에 들어가야만 확인 가능
  • 값을 바꾼 기록이 어디에도 남지 않음
  • 배포 워크플로가 이 파일을 쓰려면 비밀값을 CI로 넘겨야 함

그래서 값의 원본을 Parameter Store로 옮기고, 서버의 파일은 배포할 때마다 만들어지는 결과물로 바꿨습니다.


경로 구성

경로 내용 개수 읽을 수 있는 주체
/yeodam/v1/app/* DB, OAuth, JWT, S3, AI 호출, 외부 API 설정 18 App EC2
/yeodam/v1/worker/* API 키, S3 버킷, 실행 모드 등 AI 설정 4 Worker EC2
/yeodam/v1/deploy/* GHCR pull 계정과 PAT 2 App, Worker EC2
/yeodam/v1/observability/discord-webhook-url 알림 Webhook 1 알림 Lambda

DB 비밀번호, OAuth, JWT, API 키, GHCR PAT는 SecureString으로, URL이나 버킷 이름, Timeout 같은 일반 설정은 String으로 넣었습니다.

경로를 서버 단위로 나눠서 App은 Worker 설정을, Worker는 App 설정을 읽을 수 없습니다. GitHub 배포 Role은 어느 경로도 읽지 못합니다.

값 자체는 Terraform 리소스로 만들지 않았습니다. Terraform은 경로에 대한 읽기 권한만 관리하고, 값은 콘솔이나 CLI로 넣습니다. 그래서 State 파일에도 비밀값이 들어가지 않습니다.

키 이름과 용도는 Cloud 저장소의 deploy/parameter-store.md에서 관리합니다.


배포 때 환경 파일을 만드는 흐름

flowchart LR
  PS[("Parameter Store<br/>/yeodam/v1/app")] --> R["render-runtime-env.sh<br/>Instance Role로 조회"]
  R --> F["/run/yeodam/app.env<br/>root:root 600"]
  M["deploy/image-versions.env<br/>이미지 태그, digest"] --> C
  F --> C["docker compose<br/>--env-file"]
  C --> CT["컨테이너<br/>environment:에 적힌 값만"]
Loading

render-runtime-env.sh가 자기 경로의 값을 모두 읽어 /run/yeodam/*.env를 만듭니다. 권한은 root:root 600이고, 배포할 때마다 새로 씁니다.

이미지 태그와 digest는 여기 섞지 않고 Cloud 릴리스의 deploy/image-versions.env에서 따로 가져옵니다. 설정 값은 Parameter Store에서, 어떤 이미지를 띄울지는 Git에서 관리하는 셈입니다.

GHCR PAT는 환경 파일에 쓰지 않습니다. 배포 중에만 임시 Docker 설정에 docker login --password-stdin으로 넣고, pull이 끝나면 로그아웃하고 디렉터리를 지웁니다.


옮기는 과정

  1. 기존 서버 파일의 값을 Parameter Store로 이전 (App 18개, Worker 4개, Deploy 2개)
  2. 이전하는 동안만 EC2 Role에 임시 쓰기 권한 부여
  3. 이전이 끝나자마자 쓰기 권한 제거
  4. 두 EC2에서 환경 파일을 새로 만들고 Compose 설정 검사 통과 확인

권한을 줬는데 조회가 거부됨

처음 정책에는 하위 경로인 /yeodam/v1/app/*만 허용했습니다. 그런데 EC2에서 경로 단위 조회를 하자 AccessDeniedException이 났습니다.

GetParametersByPath는 하위 경로뿐 아니라 조회 기준 경로 자체에도 권한이 필요했습니다. 정책에 기준 경로 ARN과 하위 경로 ARN을 같이 넣어서 해결했습니다.

resources = [
  "arn:aws:ssm:ap-northeast-2:<account>:parameter/yeodam/v1/app",
  "arn:aws:ssm:ap-northeast-2:<account>:parameter/yeodam/v1/app/*",
]

값을 바꾸거나 추가할 때

값을 바꾸면 Parameter Store를 수정하고 다시 배포합니다. 실행 중인 컨테이너에는 자동으로 반영되지 않습니다.

새 환경변수를 추가할 때는 네 곳을 같이 확인합니다.

  • Parameter Store에 값 등록
  • render-runtime-env.sh가 해당 값을 파일에 쓰는지
  • Compose의 environment:에 이름이 있는지
  • 애플리케이션 설정에서 그 이름을 쓰는지

Compose 선언을 빠뜨려서 장소 검색이 실패했던 일 이후로 이 순서대로 확인합니다. 환경 파일에 있는 값이 컨테이너에 없음

⚠️ **GitHub.com Fallback** ⚠️