Worker 구성 및 시크릿 관리

CloudflareBeginner
지금 연습하기

소개

지원 서비스에서 구성 변경 사항을 안전하게 미리 확인할 공간이 필요합니다. 동일한 코드를 preview 및 live 환경에서 실행하고, 두 환경의 공개 레이블과 시크릿을 분리하며, 상태 확인 엔드포인트는 공개로 유지한 채 테스트용 유지 관리 엔드포인트를 보호합니다.

Cloudflare 학습 계정과 이전 실습에서 익힌 디바이스 인증, 배포 및 로깅 지식을 사용합니다. 이 실습은 Node.js 22.22.0, 프로젝트 로컬 Wrangler 4.131.1 및 간단한 상태 확인 경로 fixture 가 준비된 /home/labex/project/worker-config에서 독립적으로 시작합니다. 이전 VM 이나 클라우드 리소스를 재사용하지 않습니다. 두 배포는 모두 삭제 가능한 학습용 리소스이며 유지 관리 작업은 dry run 입니다. 생성한 테스트용 synthetic token 만 사용합니다. Workers Free 와 workers.dev 로 이 간단한 실습을 수행할 수 있으며, 요청은 계정 사용량에 포함됩니다. 구매한 도메인, 데이터베이스 또는 유료 업그레이드는 필요하지 않습니다.

두 클라우드 배포와 로컬 토큰 파일을 모두 삭제한 다음 로그아웃하고 VM 을 종료합니다. 실습이 끝날 때까지 같은 터미널을 계속 사용합니다.

Preview 및 Live 구성 분리

이 단계에서는 제공된 동일한 상태 확인 핸들러를 이름이 지정된 두 환경에서 사용합니다. 여기서 live도 삭제 가능한 학습용 배포이며, 어느 환경도 실제 프로덕션 데이터를 처리하지 않습니다. preview라는 이름은 Wrangler 환경 이름이지 버전 preview URL 이 아닙니다.

준비된 프로젝트로 이동하고 상태 확인 경로 fixture 를 검사합니다. Node 와 프로젝트 로컬 Wrangler 는 이미 설치되어 있습니다.

cd /home/labex/project/worker-config
node --version
npx wrangler --version
cat src/index.js

Node 는 v22.22.0, Wrangler 는 4.131.1 로 표시되어야 합니다. 핸들러는 시크릿이 아닌 표시용 값을 env에서 읽습니다. 자신의 컴퓨터에서 수행한다면 Node 를 설치하고 wrangler@4.131.1을 프로젝트 개발 의존성으로 추가합니다. 기존 의존성은 npm ci로 설치합니다.

삭제 가능한 기본 이름을 생성합니다. 명령 치환을 사용하면 임의의 16 진수 출력이 셸 변수에 삽입됩니다. 이후 명령을 실행할 수 있도록 이 터미널을 계속 열어 둡니다.

WORKER_NAME="labex-config-$(openssl rand -hex 6)"

heredoc 을 사용해 구성을 작성합니다. 따옴표가 없는 종료 표시는 $WORKER_NAME 치환을 허용합니다. main은 공유 코드를 선택하고, compatibility_date는 런타임 동작을 선택합니다. env 객체는 --env preview--env live에 사용할 구성을 재정의합니다. 이러한 바인딩은 상속되지 않으므로 각 환경에 모든 vars 값을 정의해야 합니다. 데이터베이스나 큐 리소스는 없습니다. QUEUE_LABEL은 공개 표시용 레이블일 뿐입니다.

cat > wrangler.jsonc <<CONFIG
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-09-14",
  "workers_dev": true,
  "preview_urls": false,
  "env": {
    "preview": {"vars": {"ENVIRONMENT": "preview", "QUEUE_LABEL": "sandbox"}},
    "live": {"vars": {"ENVIRONMENT": "live", "QUEUE_LABEL": "primary"}}
  }
}
CONFIG

두 로컬 런타임을 시작합니다. >는 출력을 리디렉션하고, 2>&1은 오류를 포함하며, &는 프로세스를 백그라운드에서 실행합니다. 서로 다른 HTTP 포트와 inspector 포트를 사용해 충돌을 방지합니다.

npx wrangler dev --env preview --port 8080 > preview.log 2>&1 &
npx wrangler dev --env live --port 8081 --inspector-port 9230 > live.log 2>&1 &
cat preview.log
cat live.log

두 로그에 준비 완료가 표시될 때까지 기다립니다. 필요하면 해당 cat 명령을 다시 실행합니다. 그런 다음 응답을 비교합니다.

curl -i http://127.0.0.1:8080/health
curl -i http://127.0.0.1:8081/health

두 요청 모두 200 을 반환합니다. Preview 는 {"status":"ok","environment":"preview","queue":"sandbox"}를 반환하고, live 는 {"status":"ok","environment":"live","queue":"primary"}를 반환합니다. curl -i는 상태 코드와 헤더를 함께 표시합니다. 두 서버를 실행한 상태에서 검증 버튼을 사용합니다.

환경 문서에서 환경 상속과 기본 <name>-<environment> 배포 이름을 확인할 수 있습니다.

로컬 시크릿으로 유지 관리 경로 보호

이 단계에서는 각 환경에서 서로 다른 토큰을 사용해 테스트용 유지 관리 작업을 보호합니다. 시크릿은 env를 통해 사용할 수 있는 비공개 구성으로, 공개 vars, 반환되는 JSON 또는 애플리케이션 로그에 나타나면 안 됩니다. 이 간단한 bearer token 예제의 목적은 완전한 사용자 인증 시스템이 아니라 서버 측 경계를 익히는 것입니다.

시크릿 파일을 추가하기 전에 두 로컬 작업을 중지합니다. 실제 작업 번호를 확인합니다. 아래 예제에서는 preview 가 1 번이고 live 가 2 번이라고 가정합니다.

jobs
kill %1 %2

표시하지 않고 테스트 전용 임의 토큰 두 개를 생성합니다. umask 077을 사용하면 새 파일을 VM 사용자만 읽을 수 있습니다. printf는 각 환경별 파일에 dotenv 할당 한 줄을 작성합니다. 여기서는 실제 계정 API 토큰을 절대 사용하지 않습니다.

umask 077
PREVIEW_TOKEN=$(openssl rand -hex 24)
LIVE_TOKEN=$(openssl rand -hex 24)
printf 'MAINTENANCE_TOKEN=%s\n' "$PREVIEW_TOKEN" > .dev.vars.preview
printf 'MAINTENANCE_TOKEN=%s\n' "$LIVE_TOKEN" > .dev.vars.live
cat .gitignore

.dev.vars*.env*가 제외되어 있는지 확인합니다. 시크릿 파일을 출력하거나 커밋하지 마세요. Wrangler 는 --env preview.dev.vars.preview를 로드하고, --env live에는 별도의 live 파일을 로드합니다. 환경별 .dev.vars 파일이 있으면 일반 파일을 대체합니다. 이 파일들은 시크릿을 Cloudflare 에 자동으로 업로드하지 않습니다. 자세한 내용은 로컬 시크릿과 배포된 시크릿을 참고합니다.

핸들러를 교체합니다. 따옴표로 묶은 heredoc 은 JavaScript 를 있는 그대로 보존합니다. 구성된 시크릿이 없으면 503 을 반환하고, 요청 자격 증명이 없거나 잘못되면 401 을 반환합니다. 성공 응답을 반환하기 전에 서버에서 Authorization 헤더를 비교합니다. 로그에는 고정된 이벤트 이름, 공개 환경 이름 및 숫자 상태 코드만 기록합니다. 허용된 작업은 저장된 부작용이 없는 dry run 입니다.

cat > src/index.js <<'JS'
export default {
  async fetch(request, env) {
    const path = new URL(request.url).pathname;
    if (path === '/health' && request.method === 'GET') {
      return Response.json({status: 'ok', environment: env.ENVIRONMENT, queue: env.QUEUE_LABEL});
    }
    if (path !== '/maintenance') return Response.json({error: 'not_found'}, {status: 404});
    if (request.method !== 'POST') {
      return Response.json({error: 'method_not_allowed'}, {status: 405, headers: {Allow: 'POST'}});
    }
    // Fail closed if this environment has no configured secret.
    if (!env.MAINTENANCE_TOKEN) {
      return Response.json({error: 'maintenance_unconfigured'}, {status: 503});
    }
    const authorized = request.headers.get('Authorization') === `Bearer ${env.MAINTENANCE_TOKEN}`;
    const status = authorized ? 200 : 401;
    console.log(JSON.stringify({event: 'maintenance', environment: env.ENVIRONMENT, status}));
    if (!authorized) return Response.json({error: 'unauthorized'}, {status});
    return Response.json({operation: 'dry-run', environment: env.ENVIRONMENT});
  }
};
JS
npx wrangler dev --env preview --port 8080 > preview.log 2>&1 &
npx wrangler dev --env live --port 8081 --inspector-port 9230 > live.log 2>&1 &
cat preview.log
cat live.log

두 서버에 준비 완료가 표시되면 인증 경계를 테스트합니다. -X POST는 메서드를 지정하고, -H는 bearer 헤더를 추가합니다. 실제 자격 증명을 사용할 때는 verbose curl 출력을 사용하지 마세요.

curl -i -X POST http://127.0.0.1:8080/maintenance
curl -i -X POST http://127.0.0.1:8080/maintenance -H "Authorization: Bearer incorrect-token"
curl -i -X POST http://127.0.0.1:8080/maintenance -H "Authorization: Bearer $LIVE_TOKEN"
curl -i -X POST http://127.0.0.1:8080/maintenance -H "Authorization: Bearer $PREVIEW_TOKEN"
curl -i -X POST http://127.0.0.1:8081/maintenance -H "Authorization: Bearer $LIVE_TOKEN"
curl -i http://127.0.0.1:8080/health
curl -i http://127.0.0.1:8081/health

처음 세 요청은 다른 환경에서 유효한 토큰을 포함하더라도 모두 401 unauthorized를 반환합니다. 다음 두 요청은 각 환경에 해당하는 operation: dry-run과 함께 200 을 반환합니다. 상태 확인 경로는 계속 공개됩니다. 검증을 사용해 토큰 격리, 메서드, 공개 구성 및 로컬 로그에 토큰 값이 없는지 양방향으로 확인합니다.

각 환경 배포 및 시크릿 업로드

이 단계에서는 새 VM 을 인증하고, 이름이 지정된 각 환경을 배포한 뒤 해당 환경의 시크릿을 명시적으로 업로드합니다. 먼저 로컬 작업을 중지합니다. jobs에서 실제 작업 번호를 사용합니다.

jobs
kill %1 %2
npx wrangler login --device --browser=false --scopes account:read user:read workers_scripts:write workers_tail:read

로그인된 브라우저에서 표시된 링크를 열고 현재 코드를 입력합니다. Wrangler 의 권한과 필요한 Background Access 를 검토하고, 연결 실습에서 배운 대로 학습 계정만 선택해 인증합니다. 터미널 작업이 완료될 때까지 기다립니다.

npx wrangler whoami --json

loggedIn: true, 계정 이름 및 ID 가 표시되는지 확인합니다. 아래의 YOUR_ACCOUNT_ID를 실제 ID 로 바꾸고, 원래 리소스 이름은 그대로 유지합니다.

cat > wrangler.jsonc <<CONFIG
{
  "name": "$WORKER_NAME",
  "main": "src/index.js",
  "compatibility_date": "2026-09-14",
  "account_id": "YOUR_ACCOUNT_ID",
  "workers_dev": true,
  "preview_urls": false,
  "env": {
    "preview": {"vars": {"ENVIRONMENT": "preview", "QUEUE_LABEL": "sandbox"}},
    "live": {"vars": {"ENVIRONMENT": "live", "QUEUE_LABEL": "primary"}}
  }
}
CONFIG

이 프로젝트에서는 항상 --env를 포함합니다. 그렇지 않으면 Wrangler 가 이름이 지정되지 않은 최상위 환경을 대상으로 하며, 이 실습의 배포 계획에는 포함되지 않습니다.

npx wrangler deploy --env preview
npx wrangler deploy --env live

각 배포 출력에서 정확한 workers.dev 주소를 복사합니다. 학습 계정의 기존 서브도메인을 재사용합니다. 처음 사용하는 경우 Wrangler 가 표시하는 사용 가능한 서브도메인 안내를 따르되, 기존 서브도메인은 변경하지 않습니다.

PREVIEW_URL="https://YOUR_BASE-preview.YOUR_SUBDOMAIN.workers.dev"
LIVE_URL="https://YOUR_BASE-live.YOUR_SUBDOMAIN.workers.dev"
curl -i -X POST "$PREVIEW_URL/maintenance"
curl -i -X POST "$LIVE_URL/maintenance"

두 요청 모두 maintenance_unconfigured 오류와 함께 503 을 반환합니다. 일반 배포에서는 로컬 시크릿 파일이 업로드되지 않기 때문입니다. 상태 확인 경로는 유지 관리 인증과 독립적으로 동작합니다.

표준 bulk 명령을 사용해 dotenv 파일을 해당 환경에 업로드합니다. 시크릿 하나만 있어도 이 파일 기반 작업을 사용할 수 있습니다. 출력에는 시크릿 값이 아니라 시크릿 이름이 표시됩니다. 시크릿을 업데이트하면 즉시 버전이 생성되고 배포됩니다.

npx wrangler secret bulk .dev.vars.preview --env preview
npx wrangler secret bulk .dev.vars.live --env live
npx wrangler secret list --env preview
npx wrangler secret list --env live

각 목록에 typesecret_textMAINTENANCE_TOKEN이 포함되어야 합니다. 공개 값과 인증 동작을 비교합니다.

curl -i "$PREVIEW_URL/health"
curl -i "$LIVE_URL/health"
curl -i -X POST "$PREVIEW_URL/maintenance"
curl -i -X POST "$PREVIEW_URL/maintenance" -H "Authorization: Bearer $LIVE_TOKEN"
curl -i -X POST "$PREVIEW_URL/maintenance" -H "Authorization: Bearer $PREVIEW_TOKEN"
curl -i -X POST "$LIVE_URL/maintenance" -H "Authorization: Bearer $LIVE_TOKEN"

상태 확인 응답에는 preview/sandbox와 live/primary가 계속 표시되어야 합니다. 시크릿이 없거나 다른 환경의 자격 증명을 사용하면 401 을 반환하고, 일치하는 토큰을 사용하면 200 을 반환합니다. 연결 오류가 발생하면 초기 호스트 이름 전파가 완료될 때까지 기다린 후 다시 시도합니다. 같은 Dashboard 계정에서 Compute → Workers & Pages를 엽니다. 이름이 -preview-live로 끝나는 두 Worker 를 찾고, 전체 이름과 URL 을 배포 출력과 비교합니다. 이 예제에서는 이름이 지정된 각 Wrangler 환경이 자체 배포 Worker 를 가집니다. Dashboard 에서 다른 애플리케이션을 만들지 마세요.

Workers and Pages 에 나열된 분리된 preview 및 live Worker

-preview Worker 를 열고 Settings를 선택합니다. Runtime variables and secretsVariables and secrets 섹션에서 Type, Name, Value 열을 비교합니다. ENVIRONMENTpreview, QUEUE_LABELsandbox여야 합니다. MAINTENANCE_TOKEN의 유형은 Secret이어야 하며, Value encrypted로 표시되고 읽을 수 있는 값은 표시되지 않아야 합니다.

sandbox 변수와 암호화된 유지 관리 시크릿을 표시하는 Preview 환경

Workers & Pages로 돌아가 -live Worker 를 열고 같은 섹션을 확인합니다. 공개 값은 liveprimary여야 하며, 독립적으로 업로드된 시크릿은 동일한 바인딩 이름을 사용합니다. 표를 비교하기 전에 상단 breadcrumb 에서 Worker 이름을 확인합니다.

primary 변수와 자체 암호화 유지 관리 시크릿을 표시하는 Live 환경

이미지에 표시된 임의 이름의 접미사와 서브도메인은 예시 값입니다. 암호화된 표시는 시크릿 바인딩의 존재와 유형을 확인할 뿐, 두 환경의 시크릿 값이 서로 다르다는 뜻은 아닙니다. 위의 일치 및 교차 환경 HTTP 확인을 통해 실제 동작을 검증합니다. 이 확인 단계에서는 읽기 전용으로 작업합니다. Dashboard 에서 변수를 편집하거나 자격 증명을 공개, 교체 또는 복사하지 마세요. 검증을 사용하면 두 환경의 실제 소유권, 배포된 바인딩 유형 및 공개 동작을 확인할 수 있습니다.

시크릿을 노출하지 않고 애플리케이션 로그 검사

이 단계에서는 배포된 preview 환경에서 거부된 요청 하나와 허용된 요청 하나를 검사합니다. 애플리케이션 로그에는 자격 증명이나 요청 헤더를 복사하지 않고 결과가 설명되어야 합니다.

앞서 배운 tail 명령으로 로그 스트림을 시작합니다. pretty 출력은 애플리케이션 메시지를 표시합니다. 스트림을 중지한 후 제한된 테스트 결과를 검사할 수 있도록 출력 내용을 저장합니다.

npx wrangler tail --env preview --format pretty > preview-tail.log 2>&1 &
cat preview-tail.log

스트림이 연결되었다는 메시지가 표시될 때까지 기다립니다. 연결 중에는 cat을 다시 실행합니다. 그런 다음 새 synthetic 요청을 보냅니다.

curl -i -X POST "$PREVIEW_URL/maintenance" -H "Authorization: Bearer incorrect-token"
curl -i -X POST "$PREVIEW_URL/maintenance" -H "Authorization: Bearer $PREVIEW_TOKEN"

grep을 사용해 고정된 애플리케이션 이벤트 이름이 포함된 줄만 표시합니다.

grep 'maintenance' preview-tail.log

상태 401 과 200 인 이벤트가 표시될 때까지 기다립니다. 두 이벤트의 공개 환경은 preview 여야 합니다. 어느 메시지에도 토큰 값이 포함되면 안 됩니다. 이벤트 전달은 HTTP 응답보다 늦을 수 있으므로 최대 1 분 동안 grep을 다시 실행합니다. 이벤트가 없으면 소스의 해당 console.log를 확인합니다.

jobs
kill %1

두 이벤트가 모두 표시되면 실제 tail 작업을 중지합니다. 위 예제에서는 작업 1 번이라고 가정합니다. 검증을 사용해 수집된 로그를 확인하고 원격 인증 계약을 독립적으로 다시 검사합니다. 이 과정은 synthetic 요청만 테스트하며, 향후 임의의 로깅 변경에 대한 안전성을 보장하지는 않습니다.

두 환경 배포 삭제

이 단계에서는 인증이 유지된 상태에서 삭제 가능한 두 환경 Worker 를 모두 삭제합니다. 구성에서 기본 이름과 학습 계정을 확인합니다.

cat wrangler.jsonc

이 실습의 preview 및 live 배포만 삭제합니다. 각 프롬프트에서 정확한 <base>-preview 또는 <base>-live 이름을 확인한 다음 단일 키 y를 누릅니다.

npx wrangler delete --env preview
npx wrangler delete --env live

이 Worker 를 삭제하면 연결된 시크릿 바인딩도 삭제됩니다. Wrangler 4.131.1 에서는 이후 이전에 문서화된 legacy Workers Sites KV 인증 오류가 표시될 수 있습니다. 권한을 확대하지 말고, 해당 오류를 삭제의 증거로 해석하지도 마세요. Workers & Pages 를 새로 고치고 검증을 사용합니다. 인증된 인벤토리에서 두 이름이 모두 없어야 삭제가 성공한 것입니다. 인증 또는 네트워크 오류는 결론을 내릴 수 없습니다. 관련 없는 Worker, 학습 계정 및 기존 서브도메인은 유지합니다.

로컬 시크릿 삭제 및 연결 해제

이 단계에서는 클라우드 정리가 확인된 후 이 실습의 로컬 시크릿 사본을 삭제하고 VM 연결을 해제합니다. rm은 아래에 지정한 두 파일만 삭제하며, unset은 두 임시 셸 변수를 제거합니다.

rm .dev.vars.preview .dev.vars.live
unset PREVIEW_TOKEN LIVE_TOKEN
npx wrangler logout
npx wrangler whoami --json

명시적인 "loggedIn": false가 표시되어야 합니다. 구조화된 결과에 이 값이 포함되어 있다면 인증되지 않은 명령의 nonzero 종료 상태는 정상입니다. 검증을 실행한 후 VM 을 종료합니다. 브라우저 로그인은 별도로 유지할 수 있으므로 다음 실습에서 사용할 수 있습니다. 로그아웃이나 VM 종료는 먼저 클라우드 리소스를 삭제하는 작업을 대신하지 않습니다.

요약

Wrangler 환경별로 공개 구성을 분리하고, 환경별 로컬 시크릿을 로드했으며, 암호화된 시크릿 바인딩을 업로드했습니다. 또한 일치하는 자격 증명, 누락된 자격 증명 및 다른 환경의 자격 증명을 확인했습니다. 공개 상태 확인 경로는 환경 식별 정보를 유지했고, 서버는 dry-run 유지 관리 경로를 보호했습니다. 토큰을 출력하지 않는 제한된 애플리케이션 로그를 검사한 다음, 로컬 자격 증명을 삭제하고 로그아웃하기 전에 배포 삭제를 확인했습니다.

이 과정에서 익힌 구성 관리 원칙은 이후 과정에서 preview 구성 드리프트를 진단할 때도 도움이 됩니다.