Cloudflare + AWS SSM 자동화 가이드

목적

  • Cloudflare 배포 필수값을 AWS SSM에 저장
  • GitHub Actions Secret을 AWS SSM에 최초 등록·회전
  • SSM 최신값을 GitHub Actions에 동기화
  • main push 시 블로그 자동 배포

필요한 값 (사용자가 제공)

  1. CLOUDFLARE_ACCOUNT_ID 또는 CF_ACCOUNT_ID
  2. CLOUDFLARE_API_TOKEN 또는 CF_API_TOKEN
  3. CLOUDFLARE_WEB_ANALYTICS_TOKEN 또는 CF_WEB_ANALYTICS_TOKEN
  4. CLOUDFLARE_PAGES_PROJECT 또는 CF_PROJECT_NAME (kjg-blog)

SSM 경로

SSM 경로 타입
Cloudflare Account ID /solodev/ci/blog/cloudflare/account-id String
Cloudflare API Token /solodev/ci/blog/cloudflare/api-token SecureString
Cloudflare Pages Project /solodev/ci/blog/cloudflare/project-name String
Cloudflare Web Analytics Token /solodev/ci/blog/cloudflare/web-analytics-token SecureString

GitHub Secret은 GitHub API로 값을 읽을 수 없습니다. 따라서 Secret → SSM 등록은 GitHub Actions가 Secret을 실행 환경에 주입한 뒤 수행합니다. 로컬에서는 동일한 등록 스크립트에 같은 이름의 환경변수를 직접 주입합니다.

GitHub Secret → SSM 등록

GitHub에서 Sync Blog Cloudflare Secrets to SSM workflow를 workflow_dispatch로 실행합니다. workflow는 다음 값을 로그에 출력하지 않고 SSM에 기록합니다.

  • CLOUDFLARE_ACCOUNT_IDString
  • CLOUDFLARE_API_TOKENSecureString
  • CLOUDFLARE_WEB_ANALYTICS_TOKENSecureString
  • CLOUDFLARE_PAGES_PROJECT=kjg-blogString

AWS 접근에는 기존 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY GitHub Secret을 사용합니다. 이 두 AWS bootstrap credential은 Cloudflare SSM 값으로 복사하지 않습니다.

로컬 실행

로컬은 Secret 값을 출력하지 않는 동일한 등록 경로를 사용합니다. --dry-run은 AWS에 쓰지 않고 대상 파라미터와 타입만 확인합니다.

CLOUDFLARE_ACCOUNT_ID=... \
CLOUDFLARE_API_TOKEN=... \
CLOUDFLARE_WEB_ANALYTICS_TOKEN=... \
CLOUDFLARE_PAGES_PROJECT=kjg-blog \
bash scripts/blog/sync-cloudflare-blog-secrets-to-ssm.sh --dry-run

실제 등록:

CLOUDFLARE_ACCOUNT_ID=... \
CLOUDFLARE_API_TOKEN=... \
CLOUDFLARE_WEB_ANALYTICS_TOKEN=... \
CLOUDFLARE_PAGES_PROJECT=kjg-blog \
bash scripts/blog/sync-cloudflare-blog-secrets-to-ssm.sh --overwrite

원클릭 실행

CF_ACCOUNT_ID=... \
CF_API_TOKEN=... \
CF_WEB_ANALYTICS_TOKEN=... \
CF_PROJECT_NAME=kjg-blog \
scripts/blog/bootstrap-cloudflare-pages-from-values.sh --overwrite --create-project --trigger-deploy

실행 내용:

  1. SSM 파라미터 등록
  2. GitHub Secret/Variable 동기화
  3. Cloudflare Pages 프로젝트 생성 시도
  4. 배포 워크플로우 실행
  5. 준비 상태 점검

수동 단계별 실행

1) SSM 등록

CF_ACCOUNT_ID=... \
CF_API_TOKEN=... \
CF_PROJECT_NAME=kjg-blog \
scripts/blog/register-cloudflare-blog-ssm.sh --overwrite

2) GitHub 동기화

scripts/blog/sync-cloudflare-blog-secrets-from-ssm.sh

3) 준비 상태 점검

scripts/blog/check-cloudflare-blog-ready.sh

4) 배포 실행

gh workflow run deploy-cloudflare-pages-blog.yml

값 회전(최신화)

Cloudflare 토큰 변경 시 아래 2개만 재실행:

CF_ACCOUNT_ID=... \
CF_API_TOKEN=... \
CF_PROJECT_NAME=kjg-blog \
scripts/blog/register-cloudflare-blog-ssm.sh --overwrite

scripts/blog/sync-cloudflare-blog-secrets-from-ssm.sh

실패 시 점검

  1. AWS 권한: aws sts get-caller-identity
  2. SSM 값 확인:
    • aws ssm get-parameter --name /solodev/ci/blog/cloudflare/account-id
    • aws ssm get-parameter --name /solodev/ci/blog/cloudflare/api-token --with-decryption
  3. GitHub 설정 확인:
    • gh secret list
    • gh variable list
  4. 워크플로우 로그:
    • gh run list --workflow deploy-cloudflare-pages-blog.yml

전체 GitHub Repository Secret의 SSM 이관

현재 Repository Secret 25개는 scripts/blog/github-repository-secrets.txt에 이름만 manifest로 관리합니다. Secret 값은 GitHub API로 읽을 수 없으므로, Sync GitHub Repository Secrets to SSM workflow가 Secret을 실행 환경에 주입해 등록합니다.

  • Secret 파라미터: /solodev/ci/github-secrets/<SECRET_NAME> (SecureString)
  • 배포 변수: /solodev/ci/github-variables/CLOUDFLARE_PAGES_PROJECT (String)
  • 등록 workflow: .github/workflows/sync-cloudflare-blog-secrets-to-ssm.yml
  • 로컬 등록: scripts/blog/sync-github-repository-secrets-to-ssm.sh
  • Consumer workflow: scripts/ci/load-github-secrets-from-ssm.sh로 필요한 값만 주입
  • 준비 상태 확인: scripts/blog/check-github-secrets-ssm-ready.sh

등록 workflow는 AWS_GITHUB_SECRETS_WRITE_ROLE_ARN GitHub Variable의 OIDC role을 사용합니다. Consumer workflow는 AWS_GITHUB_SECRETS_READ_ROLE_ARN을 사용합니다. 두 role은 main branch ref만 신뢰합니다.

GITHUB_TOKEN은 Repository Secret이 아니라 실행마다 생성되는 GitHub 내장 token이므로 SSM manifest에 포함하지 않습니다. workflow에서는 $을 사용합니다.

새 Repository Secret을 추가하면 manifest와 등록 workflow의 Secret env mapping을 함께 갱신해야 합니다. GitHub Secret 목록과 manifest가 일치하지 않으면 등록을 진행하지 않습니다.