https://www.skills.google/games/7399/labs/45437
📝 核心目標:
在建立 API Gateway 之前,我們必須先有一個能接收請求的真實後端服務(這裡使用 Cloud Functions)。
# 1. 設定預設地區 (Region)
gcloud config set compute/region us-east1
# 2. 將專案 ID 與 Number 存入變數,方便後續腳本呼叫
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
# 3. 啟用此架構所需的所有核心 API
# 包含:API Gateway 服務、Cloud Functions 服務、API 金鑰管理服務
gcloud services enable \
apigateway.googleapis.com \
cloudfunctions.googleapis.com \
apikeys.googleapis.com
# 4. 下載官方範例程式碼並進入目錄
git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
cd nodejs-docs-samples/functions/helloworld/helloworldGet
# 5. 部署 Cloud Function (名稱: helloGET)
# 設定為允許未經驗證的呼叫 (--allow-unauthenticated),因為驗證將交由前方的 API Gateway 處理
gcloud functions deploy helloGET \
--runtime nodejs22 \
--trigger-http \
--allow-unauthenticated \
--region us-east1
# 6. 測試後端服務是否部署成功
export FUNCTION_URL=$(gcloud functions describe helloGET --region us-east1 --format="value(httpsTrigger.url)")
curl -sL $FUNCTION_URL
# 預期輸出: Hello World!
API Gateway 的架構分為三個層級:API (邏輯群組) -> API Config (路由與安全規則,不可變動) -> Gateway (實際對外服務的節點)。
# 1. 產生一個隨機的 API ID (避免命名衝突)
cd ~
export API_ID="hello-world-$(cat /dev/urandom | tr -dc 'a-z' | fold -w 8 | head -n 1)"
# 2. 建立 OpenAPI 規範檔 (openapi2-functions.yaml)
# 這裡定義了 /hello 路徑,並使用 x-google-backend 擴展語法將流量導向剛才部署的 Function
cat <<EOF > openapi2-functions.yaml
swagger: '2.0'
info:
title: ${API_ID} description
description: Sample API on API Gateway with a Google Cloud Functions backend
version: 1.0.0
schemes:
- https
produces:
- application/json
paths:
/hello:
get:
summary: Greet a user
operationId: hello
x-google-backend:
address: https://us-east1-${PROJECT_ID}.cloudfunctions.net/helloGET
responses:
'200':
description: A successful response
schema:
type: string
EOF
# 3. 建立 API 邏輯資源
gcloud api-gateway apis create $API_ID \
--display-name="Hello World API" \
--project=$PROJECT_ID
# 4. 建立 API Config (綁定剛剛寫好的 OpenAPI yaml 檔)
# 注意:API Config 建立後即為 Read-Only,若要改規則只能建立新的 Config
gcloud api-gateway api-configs create hello-world-config \
--api=$API_ID \
--openapi-spec=openapi2-functions.yaml \
--project=$PROJECT_ID \
--display-name="Hello World Config" \
--backend-auth-service-account=${PROJECT_NUMBER}-compute@developer.gserviceaccount.com
# 5. 建立 Gateway 實體並掛載 Config (此步驟需等待幾分鐘進行佈建)
gcloud api-gateway gateways create hello-gateway \
--api=$API_ID \
--api-config=hello-world-config \
--location=us-east1 \
--project=$PROJECT_ID \
--display-name="Hello Gateway"
# 6. 取得 Gateway 的專屬網址並測試路由
export GATEWAY_URL=$(gcloud api-gateway gateways describe hello-gateway --location us-east1 --format json | jq -r .defaultHostname)
curl -sL https://$GATEWAY_URL/hello
# 預期輸出: Hello World!
為了防止 API 被濫用,我們在 Gateway 層加上金鑰驗證。只有帶有合法 ?key=xxx 參數的請求才能通過。
# 1. 取得這組 API 專屬的 Managed Service 名稱,並允許該服務使用 API Key
export MANAGED_SERVICE=$(gcloud api-gateway apis list --format json | jq -r .[0].managedService | cut -d'/' -f6)
gcloud services enable $MANAGED_SERVICE
# 2. 建立一把專用的 API Key,並限制這把鑰匙只能存取我們的 Managed Service
gcloud services api-keys create \
--display-name="Hello API Key" \
--api-target=service=$MANAGED_SERVICE
# 3. 抓取這把金鑰的明碼字串並存入變數
export API_KEY=$(gcloud services api-keys get-key-string \
$(gcloud services api-keys list --filter="displayName='Hello API Key'" --format="value(name)") \
--format="value(keyString)")
# 4. 建立第二版 OpenAPI 規範檔 (openapi2-functions2.yaml)
# 新增了 security 與 securityDefinitions 區塊來宣告 API Key 驗證機制
cat <<EOF > openapi2-functions2.yaml
swagger: '2.0'
info:
title: ${API_ID} description
description: Sample API on API Gateway with a Google Cloud Functions backend
version: 1.0.0
schemes:
- https
produces:
- application/json
paths:
/hello:
get:
summary: Greet a user
operationId: hello
x-google-backend:
address: https://us-east1-${PROJECT_ID}.cloudfunctions.net/helloGET
security:
- api_key: []
responses:
'200':
description: A successful response
schema:
type: string
securityDefinitions:
api_key:
type: "apiKey"
name: "key"
in: "query"
EOF
# 5. 建立新的 API Config (使用包含了 Security 設定的第二版 yaml 檔)
gcloud api-gateway api-configs create hello-config-secure \
--api=$API_ID \
--openapi-spec=openapi2-functions2.yaml \
--project=$PROJECT_ID \
--display-name="Hello Config Secure" \
--backend-auth-service-account=${PROJECT_NUMBER}-compute@developer.gserviceaccount.com
# 6. 更新 Gateway,將流量切換到具有防護能力的新 Config (此步驟需等待幾分鐘)
gcloud api-gateway gateways update hello-gateway \
--api=$API_ID \
--api-config=hello-config-secure \
--location=us-east1 \
--project=$PROJECT_ID
Gateway 更新完畢後,進行最終的安全測試:
# 測試 1:不帶任何身分驗證呼叫 API
curl -sL https://$GATEWAY_URL/hello
# 預期輸出:拒絕存取錯誤 (UNAUTHENTICATED: Method doesn't allow unregistered callers)
# 測試 2:在 URL 參數中帶上我們建立的 API Key
curl -sL -w "\n" "https://${GATEWAY_URL}/hello?key=${API_KEY}"
# 預期輸出:Hello World! (成功放行)