Files
runbooks/cloudflare-vault-integration.md
kappa e0b2a22575 docs(cloudflare-vault): 문서 전면 개선 (68→540줄)
- 아키텍처 다이어그램 추가
- Vault 초기 설정 (KV 시크릿 엔진, 정책, AppRole)
- Cloudflare API Token 생성 가이드
- CLI 사용법 및 자동화 스크립트 (Fish, Bash)
- Terraform 통합 예제
- CI/CD 통합 (GitHub Actions, GitLab CI)
- 문제 해결 가이드
- 보안 체크리스트

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 00:51:47 +09:00

14 KiB

Cloudflare + HashiCorp Vault 통합 가이드

Cloudflare API 크레덴셜을 Vault에서 안전하게 관리하는 완벽 가이드

목차

  1. 개요
  2. 아키텍처
  3. Vault 초기 설정
  4. Cloudflare API Token 생성
  5. Vault에 크레덴셜 저장
  6. CLI 사용법
  7. 자동화 스크립트
  8. Terraform 통합
  9. CI/CD 통합
  10. 문제 해결

개요

왜 Vault를 사용하는가?

문제 Vault 해결책
크레덴셜 하드코딩 중앙 집중식 시크릿 관리
평문 저장 암호화된 저장소
무제한 유효기간 동적 시크릿, TTL 설정
감사 불가 모든 접근 로깅
권한 관리 어려움 세분화된 ACL 정책

지원하는 Cloudflare 크레덴셜

유형 용도 권장
API Token 특정 권한만 부여 권장
Global API Key 전체 권한 ⚠️ 레거시
Tunnel Credentials cloudflared 터널 필수
Origin CA Key 오리진 인증서 필요시

아키텍처

┌─────────────────────────────────────────────────────────────┐
│                    HashiCorp Vault                          │
│                 (https://vault.anvil.it.com)                │
├─────────────────────────────────────────────────────────────┤
│  secret/cloudflare/                                         │
│  ├── tokens/                                                │
│  │   ├── dns-edit          # DNS 편집용 토큰               │
│  │   ├── zone-read         # Zone 읽기 전용               │
│  │   └── workers-deploy    # Workers 배포용               │
│  ├── tunnels/                                               │
│  │   ├── production        # 프로덕션 터널                 │
│  │   └── staging           # 스테이징 터널                 │
│  └── global/               # Global API Key (레거시)       │
└─────────────────────────────────────────────────────────────┘
                              │
          ┌───────────────────┼───────────────────┐
          ▼                   ▼                   ▼
    ┌───────────┐      ┌───────────┐      ┌───────────┐
    │ Terraform │      │   n8n     │      │  CI/CD    │
    │           │      │ Workflows │      │ Pipeline  │
    └───────────┘      └───────────┘      └───────────┘

Vault 초기 설정

1. Vault 로그인

# 환경변수 설정
export VAULT_ADDR="https://vault.anvil.it.com"

# 토큰 로그인
vault login

# 또는 토큰 직접 지정
vault login hvs.xxxxxxxxxxxxx

2. KV Secrets Engine 활성화

# KV v2 시크릿 엔진 활성화 (이미 있으면 스킵)
vault secrets enable -path=secret kv-v2

# 확인
vault secrets list

3. Cloudflare 정책 생성

# 정책 파일 생성
cat > cloudflare-policy.hcl << 'EOF'
# Cloudflare 토큰 읽기 권한
path "secret/data/cloudflare/*" {
  capabilities = ["read", "list"]
}

# 토큰 메타데이터 읽기
path "secret/metadata/cloudflare/*" {
  capabilities = ["read", "list"]
}
EOF

# 정책 적용
vault policy write cloudflare-read cloudflare-policy.hcl

# 정책 확인
vault policy read cloudflare-read

4. AppRole 설정 (자동화용)

# AppRole 활성화
vault auth enable approle

# Role 생성
vault write auth/approle/role/cloudflare-automation \
  token_policies="cloudflare-read" \
  token_ttl=1h \
  token_max_ttl=4h \
  secret_id_ttl=24h

# Role ID 확인
vault read auth/approle/role/cloudflare-automation/role-id

# Secret ID 생성
vault write -f auth/approle/role/cloudflare-automation/secret-id

Cloudflare API Token 생성

Cloudflare 대시보드에서 생성

  1. https://dash.cloudflare.com/profile/api-tokens 접속
  2. Create Token 클릭
  3. 템플릿 선택 또는 Custom token 생성

권장 토큰 템플릿

DNS 편집용 토큰

권한 리소스
Zone - DNS - Edit 특정 Zone 또는 All zones
Zone - Zone - Read 특정 Zone 또는 All zones

Workers 배포용 토큰

권한 리소스
Account - Workers Scripts - Edit 계정
Account - Workers KV Storage - Edit 계정
Account - Workers Routes - Edit 계정

Zone 읽기 전용 토큰

권한 리소스
Zone - Zone - Read All zones
Zone - DNS - Read All zones
Zone - Analytics - Read All zones

API 토큰 테스트

# 토큰 유효성 검증
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# 성공 응답
{
  "result": { "status": "active" },
  "success": true
}

Vault에 크레덴셜 저장

1. API Token 저장 (권장)

# DNS 편집용 토큰 저장
vault kv put secret/cloudflare/tokens/dns-edit \
  api_token="your-dns-edit-token-here" \
  account_id="your-account-id" \
  description="DNS record management"

# Workers 배포용 토큰 저장
vault kv put secret/cloudflare/tokens/workers-deploy \
  api_token="your-workers-token-here" \
  account_id="your-account-id" \
  description="Workers deployment"

# 확인
vault kv get secret/cloudflare/tokens/dns-edit

2. Global API Key 저장 (레거시)

# Global API Key 저장 (권장하지 않음)
vault kv put secret/cloudflare/global \
  email="your-email@example.com" \
  api_key="your-global-api-key" \
  account_id="your-account-id"

3. Tunnel 크레덴셜 저장

# cloudflared tunnel 생성 시 credentials.json 내용 저장
vault kv put secret/cloudflare/tunnels/production \
  tunnel_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
  account_tag="your-account-tag" \
  tunnel_secret="base64-encoded-secret"

# 또는 JSON 파일 전체 저장
vault kv put secret/cloudflare/tunnels/production \
  credentials="$(cat ~/.cloudflared/xxxxxxxx.json | base64)"

4. 시크릿 버전 관리

# 시크릿 버전 목록
vault kv metadata get secret/cloudflare/tokens/dns-edit

# 특정 버전 읽기
vault kv get -version=2 secret/cloudflare/tokens/dns-edit

# 시크릿 삭제 (소프트 삭제)
vault kv delete secret/cloudflare/tokens/old-token

# 영구 삭제
vault kv destroy -versions=1 secret/cloudflare/tokens/old-token

CLI 사용법

환경변수로 로드

# API Token 방식 (권장)
export CLOUDFLARE_API_TOKEN=$(vault kv get -field=api_token secret/cloudflare/tokens/dns-edit)

# Global API Key 방식 (레거시)
export CF_API_EMAIL=$(vault kv get -field=email secret/cloudflare/global)
export CF_API_KEY=$(vault kv get -field=api_key secret/cloudflare/global)

# Account ID
export CLOUDFLARE_ACCOUNT_ID=$(vault kv get -field=account_id secret/cloudflare/tokens/dns-edit)

Tunnel credentials.json 복원

# JSON 파일로 추출
vault kv get -format=json secret/cloudflare/tunnels/production | \
  jq -r '.data.data | {
    AccountTag: .account_tag,
    TunnelID: .tunnel_id,
    TunnelSecret: .tunnel_secret
  }' > ~/.cloudflared/production.json

chmod 600 ~/.cloudflared/production.json

한 번에 모든 크레덴셜 로드

# JSON에서 환경변수로 변환
eval $(vault kv get -format=json secret/cloudflare/tokens/dns-edit | \
  jq -r '.data.data | to_entries[] | "export CF_\(.key | ascii_upcase)=\(.value)"')

자동화 스크립트

Fish Shell 함수

# ~/.config/fish/functions/cf-auth.fish
function cf-auth
    set -l token_name $argv[1]
    if test -z "$token_name"
        set token_name "dns-edit"
    end

    set -gx CLOUDFLARE_API_TOKEN (vault kv get -field=api_token secret/cloudflare/tokens/$token_name)
    set -gx CLOUDFLARE_ACCOUNT_ID (vault kv get -field=account_id secret/cloudflare/tokens/$token_name)

    echo "✅ Cloudflare 인증 설정 완료 (토큰: $token_name)"
end

function cf-auth-clear
    set -e CLOUDFLARE_API_TOKEN
    set -e CLOUDFLARE_ACCOUNT_ID
    set -e CF_API_EMAIL
    set -e CF_API_KEY
    echo "🧹 Cloudflare 환경변수 정리 완료"
end

Bash 함수

# ~/.bashrc 또는 ~/.bash_aliases
cf-auth() {
    local token_name="${1:-dns-edit}"
    export CLOUDFLARE_API_TOKEN=$(vault kv get -field=api_token "secret/cloudflare/tokens/${token_name}")
    export CLOUDFLARE_ACCOUNT_ID=$(vault kv get -field=account_id "secret/cloudflare/tokens/${token_name}")
    echo "✅ Cloudflare 인증 설정 완료 (토큰: ${token_name})"
}

cf-auth-clear() {
    unset CLOUDFLARE_API_TOKEN CLOUDFLARE_ACCOUNT_ID CF_API_EMAIL CF_API_KEY
    echo "🧹 Cloudflare 환경변수 정리 완료"
}

# 자동 완성
_cf_auth_completions() {
    local tokens=$(vault kv list -format=json secret/cloudflare/tokens 2>/dev/null | jq -r '.[]')
    COMPREPLY=($(compgen -W "${tokens}" -- "${COMP_WORDS[COMP_CWORD]}"))
}
complete -F _cf_auth_completions cf-auth

Terraform 통합

Provider 설정

# providers.tf
terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 4.0"
    }
    vault = {
      source  = "hashicorp/vault"
      version = "~> 3.0"
    }
  }
}

provider "vault" {
  address = "https://vault.anvil.it.com"
  # 토큰은 VAULT_TOKEN 환경변수에서 자동 로드
}

# Vault에서 Cloudflare 토큰 읽기
data "vault_kv_secret_v2" "cloudflare" {
  mount = "secret"
  name  = "cloudflare/tokens/dns-edit"
}

provider "cloudflare" {
  api_token = data.vault_kv_secret_v2.cloudflare.data["api_token"]
}

DNS 레코드 관리 예시

# dns.tf
data "cloudflare_zone" "main" {
  name = "example.com"
}

resource "cloudflare_record" "api" {
  zone_id = data.cloudflare_zone.main.id
  name    = "api"
  value   = "192.168.1.100"
  type    = "A"
  proxied = true
}

Tunnel 설정 예시

# tunnel.tf
data "vault_kv_secret_v2" "tunnel" {
  mount = "secret"
  name  = "cloudflare/tunnels/production"
}

resource "cloudflare_tunnel" "production" {
  account_id = data.vault_kv_secret_v2.cloudflare.data["account_id"]
  name       = "production-tunnel"
  secret     = data.vault_kv_secret_v2.tunnel.data["tunnel_secret"]
}

CI/CD 통합

GitHub Actions

# .github/workflows/deploy.yml
name: Deploy to Cloudflare

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Import Secrets from Vault
        uses: hashicorp/vault-action@v2
        with:
          url: https://vault.anvil.it.com
          method: approle
          roleId: ${{ secrets.VAULT_ROLE_ID }}
          secretId: ${{ secrets.VAULT_SECRET_ID }}
          secrets: |
            secret/data/cloudflare/tokens/workers-deploy api_token | CLOUDFLARE_API_TOKEN ;
            secret/data/cloudflare/tokens/workers-deploy account_id | CLOUDFLARE_ACCOUNT_ID

      - name: Deploy Worker
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ env.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ env.CLOUDFLARE_ACCOUNT_ID }}

GitLab CI

# .gitlab-ci.yml
variables:
  VAULT_ADDR: "https://vault.anvil.it.com"

.vault-auth: &vault-auth
  before_script:
    - export VAULT_TOKEN=$(vault write -field=token auth/approle/login role_id=$VAULT_ROLE_ID secret_id=$VAULT_SECRET_ID)
    - export CLOUDFLARE_API_TOKEN=$(vault kv get -field=api_token secret/cloudflare/tokens/dns-edit)

deploy:
  <<: *vault-auth
  script:
    - wrangler deploy

문제 해결

일반적인 오류

오류 원인 해결
permission denied Vault 정책 부족 정책에 경로 추가
token expired Vault 토큰 만료 vault login 재실행
secret not found 잘못된 경로 vault kv list 로 확인
authentication error CF 토큰 만료/삭제 Cloudflare에서 토큰 재생성

Vault 연결 확인

# Vault 상태 확인
vault status

# 토큰 정보 확인
vault token lookup

# 시크릿 경로 목록
vault kv list secret/cloudflare/
vault kv list secret/cloudflare/tokens/

Cloudflare 토큰 검증

# 토큰 유효성 확인
curl -s -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
  -H "Authorization: Bearer $(vault kv get -field=api_token secret/cloudflare/tokens/dns-edit)" | jq

# 권한 확인
curl -s -X GET "https://api.cloudflare.com/client/v4/user" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.result.id'

디버그 모드

# Vault 상세 로그
VAULT_LOG_LEVEL=debug vault kv get secret/cloudflare/tokens/dns-edit

# curl 상세 출력
curl -v -X GET "https://api.cloudflare.com/client/v4/zones" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"

보안 체크리스트

  • Global API Key 대신 API Token 사용
  • 토큰별 최소 권한 원칙 적용
  • Vault 정책으로 접근 제한
  • 환경변수는 세션 종료 시 정리
  • CI/CD에서 AppRole 사용
  • 정기적인 토큰 로테이션
  • Vault 감사 로그 활성화

참고 자료


마지막 업데이트: 2026-01