게이트웨이를 통한 경로 추론

CloudflareBeginner
지금 연습하기

소개

Workers AI 과정에서는 애플리케이션이 Cloudflare 에서 호스팅하는 모델로 프롬프트를 직접 보냈습니다. 이 방식도 작동하지만, 규모가 커지는 애플리케이션에는 모델 트래픽을 한곳에서 일관되게 관찰하고 제어할 수 있는 지점이 필요합니다. Cloudflare AI Gateway가 바로 그 역할을 합니다. 호출자는 이름이 지정된 게이트웨이로 요청을 보내고, 게이트웨이는 요청을 Workers AI 와 같은 업스트림 모델 제공업체로 전달합니다.

이 실습에서는 다음 세 가지 역할을 명확하게 구분합니다.

  • 호출자는 LabEx VM 의 curl입니다.
  • 게이트웨이는 호출자가 진입할 수 있는지 확인하고 요청을 기록합니다.
  • 업스트림 제공업체는 Workers AI 이며, 요청이 모델을 실행할 수 있는지 확인합니다.

마지막 두 확인에는 서로 다른 자격 증명을 사용합니다. cf-aig-authorization은 호출자를 AI Gateway 에 인증합니다. 일반적인 Authorization 헤더는 게이트웨이의 Workers AI 요청을 인증합니다. 유효한 게이트웨이 토큰이 Workers AI 자격 증명으로 자동 사용되는 것은 아니며, Workers AI 자격 증명이 인증된 게이트웨이를 우회하게 해 주는 것도 아닙니다.

이 실습에서는 Cloudflare Dashboard 에서 임시 인증 게이트웨이 하나를 만들고, 범위를 제한한 AI Gateway 토큰을 생성합니다. 그런 다음 Cloudflare 에서 호스팅하는 Llama 3.3 모델에 짧은 요청을 보내고 생성된 로그를 확인합니다. 이후 게이트웨이 자격 증명만 잘못된 값으로 바꾸어 어떤 경계에서 요청을 거부하는지 확인합니다. 마지막으로 게이트웨이를 삭제하고, 더 이상 요청을 인증할 수 없도록 토큰을 삭제한 다음 Wrangler 에서 로그아웃합니다.

이 과정에 직접 들어왔다면 먼저 LabEx 를 Cloudflare 계정에 연결을 완료합니다. 이 과정에서는 LabEx VM 터미널, Wrangler 디바이스 인증, 계정 확인 및 명시적인 계정 ID 사용 방법을 설명합니다. Workers AI 추론 실습도 유용한 사전 학습 과정입니다.

AI Gateway 는 Free 플랜에서 사용할 수 있으며, 핵심 로깅은 계정 한도 내에서 무료입니다. 선택한 @cf/meta/llama-3.3-70b-instruct-fp8-fast 모델은 Standard 결제 방식으로 공유 Workers AI 무료 할당량을 사용할 수 있습니다. Workers Paid 와 Unified Billing 은 필요하지 않습니다. 계정의 일일 Workers AI 할당량을 사용할 수 없다면 계속 재시도하지 말고 중지합니다.

설정 과정에서는 Node.js 22.22.0 과 프로젝트 전용 Wrangler 4.132.0 을 /home/labex/project/ai-gateway-route에 설치합니다. 읽기 전용 평가 기능을 제공하지만 Wrangler 인증, 토큰 또는 게이트웨이 생성, 추론 요청 전송, Cloudflare 계정 수정은 수행하지 않습니다. LabEx 는 실습이 끝난 뒤 이 임시 VM 을 저장하지 않습니다. 그래도 VM 이 삭제되기 전에 클라우드 토큰을 삭제하고 VM 에 남은 복사본을 명시적으로 지워야 정리가 완료됩니다.

VM 인증 및 소유 리소스 이름 기록

이 단계에서는 새 VM 을 학습용 계정에 연결하고, 이 실습의 리소스를 명확하게 식별할 수 있는 이름을 저장합니다.

Wrangler 의 디바이스 로그인은 Workers AI 를 인증하지만, 이후 사용할 별도의 AI Gateway 호출자 자격 증명을 생성하지는 않습니다. 두 자격 증명을 분리하면 신뢰 경계를 더 쉽게 확인할 수 있습니다.

준비된 프로젝트 디렉터리로 이동하고 고정된 CLI 버전을 확인합니다.

cd /home/labex/project/ai-gateway-route
npx wrangler --version

4.132.0이 출력되어야 합니다. 계정 식별 정보와 Workers AI 액세스 권한을 사용해 디바이스 인증을 시작합니다.

npx wrangler login --device --browser=false --scopes account:read user:read ai:write

표시된 링크를 열고 코드를 입력한 뒤, 사용할 학습용 계정을 인증합니다. 그런 다음 구조화된 계정 정보를 확인합니다.

npx wrangler whoami --json

loggedIn: true인지 확인합니다. 고유한 게이트웨이 ID 와 관련 토큰 이름을 생성합니다. YOUR_ACCOUNT_ID를 사용할 계정에 표시된 실제 32 자 ID 로 바꿉니다.

GATEWAY_ID="labex-c09-g01-$(openssl rand -hex 6)"
TOKEN_NAME="$GATEWAY_ID-token"
cat > .labex/state.json <<JSON
{
  "accountId": "YOUR_ACCOUNT_ID",
  "gatewayId": "$GATEWAY_ID",
  "tokenName": "$TOKEN_NAME"
}
JSON
cat .labex/state.json

무작위 접미사는 이름이 겹치는 것을 방지합니다. 상태 파일에는 리소스 식별자가 들어 있으며 자격 증명은 포함되지 않습니다. 이후 명령은 이 파일을 사용해 이 실습에서 생성한 정확한 리소스를 대상으로 합니다.

인증된 게이트웨이와 호출자 토큰 생성

이 단계에서는 요청을 검사하는 게이트웨이와, 게이트웨이를 호출하고 조회할 수 있는 자격 증명을 생성합니다.

Cloudflare Dashboard 를 열고 AI → AI Gateway → Create gateway → Custom gateway를 선택합니다. 게이트웨이 이름에는 .labex/state.jsongatewayId를 사용합니다. 다음 설정을 유지합니다.

  • 요청 로깅: 켬
  • 게이트웨이 인증: 켬
  • 캐시, 속도 제한, 지출 제한 및 재시도: 끔
  • Workers AI 결제: Standard

Standard 결제는 Workers AI 사용량을 일반 할당량에서 처리합니다. Unified Billing 은 별도의 결제 방식이며 이 초급 실습의 범위에 포함되지 않습니다.

Cloudflare 에서 새 리소스를 열면 이동 경로와 선택된 Overview 탭을 사용해 계정 전체의 게이트웨이 목록이 아니라 정확히 임시로 생성한 게이트웨이 내부에 있는지 확인합니다.

고유 ID 와 비어 있는 첫 요청 지표가 표시된 새 게이트웨이 Overview

생성한 뒤 Settings를 엽니다. 표시된 게이트웨이 ID 가 저장한 ID 와 정확히 일치하는지, 로깅과 인증이 활성화되어 있는지 확인합니다.

이제 Create an AI Gateway authentication token을 선택합니다. 저장한 tokenName으로 이름을 지정하고, 사용할 학습용 계정만 선택한 다음 다음 권한을 추가합니다.

  • AI Gateway — Run은 호출자가 인증된 게이트웨이에 진입하도록 허용합니다.
  • AI Gateway — Edit는 실습에서 관리 API 를 통해 AI Gateway 리소스를 읽고 삭제하도록 허용합니다.

이 토큰에는 Workers AI 권한을 추가하지 않습니다. Workers AI 는 Wrangler 의 별도 단기 자격 증명으로 인증합니다.

AI Gateway Run 및 Edit 로 범위를 제한한 토큰 권한 양식

계정과 권한을 검토한 뒤에만 토큰을 생성합니다. Cloudflare 는 토큰 값을 한 번만 표시합니다. 토큰을 화면에 출력하지 않고 안전하게 저장합니다.

bash -c '
while :; do
  read -rsp "Paste the AI Gateway token: " GATEWAY_TOKEN
  printf "\n"
  [ -n "$GATEWAY_TOKEN" ] && break
  printf "Token cannot be empty; paste it again.\n" >&2
done
umask 077
printf "%s" "$GATEWAY_TOKEN" > .labex/gateway-token
unset GATEWAY_TOKEN
chmod 600 .labex/gateway-token
'

준비된 터미널은 대화형으로 zsh 를 사용하므로, 이 블록은 Bash 의 숨겨진 read 프롬프트를 사용하기 위해 짧은 Bash 하위 프로세스를 시작합니다. 붙여넣은 값이 비어 있으면 명령이 셸로 돌아가기 전에 거부됩니다. 토큰은 하위 프로세스와 권한이 제한된 파일에만 남습니다.

토큰은 구성과 명령 출력에 노출되지 않도록 별도로 보관합니다. 인증된 관리 API 를 통해 실제 게이트웨이를 확인합니다.

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s),g=b.result||{};console.log(JSON.stringify({success:b.success,id:g.id,collect_logs:g.collect_logs,authentication:g.authentication},null,2))})'
unset GATEWAY_TOKEN

소유한 ID 가 출력되고 collect_logsauthentication이 모두 true로 설정되어 있어야 합니다. 비밀 값은 출력되지 않습니다.

인증, 로그 및 Standard 결제가 표시된 게이트웨이 Settings 화면

Workers AI 요청 하나를 게이트웨이로 라우팅

이 단계에서는 Workers AI 에 직접 요청하는 대신 게이트웨이를 통해 작은 요청 하나를 보냅니다.

제공업체 전용 게이트웨이 URL 에는 계정, 게이트웨이, 제공업체 및 모델 정보가 포함됩니다. 두 인증 헤더는 의도적으로 분리되어 있습니다.

caller → cf-aig-authorization → AI Gateway → Authorization → Workers AI model

Wrangler 의 현재 단기 Workers AI 토큰을 구조화된 데이터로 가져온 다음 요청을 보냅니다. 이 명령은 JSON 응답만 파일에 저장하며 두 자격 증명 모두 출력하지 않습니다.

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
MODEL='@cf/meta/llama-3.3-70b-instruct-fp8-fast'
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(npx wrangler auth token --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))')
curl --http1.1 -fsS \
  -H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"In one sentence, explain why an AI gateway is useful.","max_tokens":64}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL" \
  > .labex/valid-response.json
unset GATEWAY_TOKEN UPSTREAM_TOKEN
node -e 'const b=require("./.labex/valid-response.json"); console.log(b.result?.response ?? b.result)'

생성 결과는 비결정적이므로 문구가 달라질 수 있습니다. 평가는 소유한 게이트웨이를 통해 제공업체가 성공적인 비어 있지 않은 결과를 반환했는지만 확인합니다.

게이트웨이 인증 경계 분리

이 단계에서는 유효한 Workers AI 자격 증명은 그대로 두고 게이트웨이 자격 증명만 바꿉니다.

통제된 부정 테스트에서는 한 번에 하나의 조건만 변경해야 합니다. 두 자격 증명이 모두 유효하지 않으면 HTTP 오류만으로 어떤 시스템이 요청을 거부했는지 알 수 없습니다. 다음 요청은 Wrangler 의 유효한 업스트림 토큰을 유지하고 cf-aig-authorization에 명확히 잘못된 값을 보냅니다.

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
MODEL='@cf/meta/llama-3.3-70b-instruct-fp8-fast'
UPSTREAM_TOKEN=$(npx wrangler auth token --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))')
STATUS=$(curl --http1.1 -sS -o .labex/invalid-response.json -w '%{http_code}' \
  -H 'cf-aig-authorization: Bearer deliberately-invalid' \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"This request must not reach the model.","max_tokens":8}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset UPSTREAM_TOKEN
printf '%s\n' "$STATUS" | tee .labex/invalid-status.txt

401 또는 403이 출력되어야 합니다. 응답 본문은 표시하지 않습니다. 상태 코드만으로 충분한 증거가 되며, 오류 출력을 제한하면 요청 세부 정보가 노출될 가능성을 줄일 수 있습니다.

요청을 게이트웨이 로그와 연결

이 단계에서는 관찰 기능을 사용해 실행 결과를 게이트웨이에 표시된 기록과 연결합니다.

**관찰 가능성 (Observability)**은 호출자가 요청을 보낸 뒤 시스템이 무엇을 했는지 설명할 수 있을 만큼 충분한 증거를 수집하는 것입니다. 게이트웨이 로그에는 모델에 다시 요청하지 않아도 제공업체, 모델, 상태, 지연 시간 및 토큰 사용량이 표시될 수 있습니다. 로그가 나타나기까지 잠시 걸릴 수 있습니다.

인증된 관리 API 를 통해 기존 로그를 읽습니다. 이 작업은 읽기 전용 확인이며 모델 요청을 다시 보내지 않습니다.

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID/logs?per_page=50" \
  > .labex/logs.json
unset GATEWAY_TOKEN
node - <<'NODE'
const body = require('./.labex/logs.json')
const model = '@cf/meta/llama-3.3-70b-instruct-fp8-fast'
const matches = (body.result || []).filter(row =>
  row.provider === 'workers-ai' && row.model === model
)
console.log(matches.map(row => ({
  id: row.id,
  provider: row.provider,
  model: row.model,
  success: row.success,
  created_at: row.created_at
})))
if (!matches.some(row => row.success === true)) process.exit(2)
NODE

provider: "workers-ai", 의도한 모델 및 success: true가 포함된 항목이 하나 이상 표시되어야 합니다. 해당 항목 없이 명령이 종료되면 약 20 초 기다린 뒤 추론 요청을 더 보내지 말고 동일한 읽기 전용 블록을 다시 실행합니다.

Dashboard 에서 게이트웨이의 Logs 화면을 엽니다. @cf/meta/llama-3.3-70b-instruct-fp8-fast에 대한 성공한 Workers AI 행을 찾습니다. 세부 정보 패널을 열기 전에 성공 여부, 제공업체 및 모델을 확인합니다.

성공한 Workers AI 요청이 강조 표시된 게이트웨이 Logs 표

정확한 처리 시간, 토큰 수 및 생성된 텍스트는 달라질 수 있습니다. 이 값들은 해당 요청의 결과이며, 정확히 재현해야 하는 목표가 아닙니다. 로그를 쉽게 찾기 위해 프롬프트에 자격 증명이나 개인 정보를 절대 입력하지 않습니다.

모델, 상태, 지연 시간 및 토큰 사용량이 표시된 로그 세부 정보 패널

임시 게이트웨이 삭제

이 단계에서는 관리 자격 증명을 아직 사용할 수 있을 때 클라우드 리소스를 삭제합니다.

정리 작업은 소유한 정확한 ID 를 대상으로 해야 하며, 인증된 목록 조회를 통해 삭제되었음을 확인해야 합니다. 로그아웃이나 네트워크 오류로 페이지가 표시되지 않는 것은 삭제 증거가 아닙니다.

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS -X DELETE \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s);if(!b.success)process.exit(1);console.log("gateway deletion accepted")})'
unset GATEWAY_TOKEN

GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways" \
  > .labex/gateways-after-delete.json
unset GATEWAY_TOKEN
node -e 'const b=require("./.labex/gateways-after-delete.json"),id=process.argv[1],found=(b.result||[]).some(g=>g.id===id);console.log("gateway absent:",!found);if(found)process.exit(1)' "$GATEWAY_ID"

gateway absent: true가 출력되어야 합니다. 두 번째 요청은 유효한 인증으로 게이트웨이 목록을 조회하며, 소유한 ID 가 남아 있으면 실패합니다. 계정의 다른 게이트웨이는 수정되지 않습니다.

토큰 삭제 및 로그아웃

이 단계에서는 사용한 순서의 역순으로 서로 독립적인 두 자격 증명을 삭제합니다.

Cloudflare Dashboard 에서 My Profile → API Tokens를 엽니다. .labex/state.json에 저장된 정확한 토큰 이름을 찾고, 해당 토큰의 Actions 메뉴를 연 다음 Delete를 선택합니다. 확인 내용을 검토한 뒤 해당 토큰만 삭제합니다. 토큰을 삭제하면 액세스 권한이 즉시 취소됩니다. 게이트웨이는 이미 삭제했으므로 이제 토큰을 제거해도 안전합니다.

로컬 복사본을 삭제한 다음 별도로 인증된 Wrangler VM 세션을 종료합니다.

shred -u .labex/gateway-token
npx wrangler logout
npx wrangler whoami --json || true

loggedIn: false가 포함된 구조화된 출력이 표시되어야 합니다. Dashboard 브라우저 세션은 별개이므로 로그인 상태가 유지됩니다. 마지막으로 로컬 파일을 확인합니다.

test ! -e .labex/gateway-token && echo "local gateway token removed"

메시지는 VM 에 토큰 복사본이 없음을 확인합니다. LabEx 의 Check 버튼은 로컬 파일과 Wrangler 로그아웃 상태를 독립적으로 다시 확인합니다. 평가 백엔드 스크립트는 학습자 프로젝트에 의도적으로 포함되어 있지 않습니다.

이제 게이트웨이를 삭제하고 호출자 및 관리 토큰을 제거했으며, 로컬 토큰 복사본을 지우고 새 VM 의 연결을 해제했습니다. 실습을 종료하면 LabEx 는 이 임시 VM 을 저장하지 않고 삭제합니다. 그래도 클라우드 정리는 중요합니다. VM 만 삭제해서는 Cloudflare 토큰을 취소하거나 게이트웨이를 제거할 수 없기 때문입니다.

요약

인증된 Cloudflare AI Gateway 를 만들고 실제 Workers AI 추론 요청을 게이트웨이를 통해 라우팅했습니다. 게이트웨이 인증과 업스트림 모델 인증을 분리하고, 한 가지 자격 증명만 변경해 요청을 거부한 경계를 확인했으며, 성공한 요청을 게이트웨이 로그와 연결했습니다. 마지막으로 인증된 리소스 삭제를 확인한 뒤 토큰을 삭제하고 VM 에서 로그아웃했습니다.

다음 실습에서는 이 관찰 가능한 요청 경로를 바탕으로 진행합니다. 기밀이 아닌 간단한 메타데이터를 추가하고, 의도적인 실패를 추적하며, 요청이 실패한 위치를 추측하지 않고 게이트웨이의 증거를 사용합니다.