為 GKE 閘道新增政策

本頁面適用於 Apigee,但不適用於 Apigee Hybrid

查看 Apigee Edge 說明文件。

本頁面說明如何使用 Kubernetes 適用的 Apigee APIM Operator,在 Google Kubernetes Engine (GKE) Gateway 中新增 Apigee 執行階段政策和 Google 符記插入政策。將可用的政策組新增至 Gateway,即可擴充 Gateway 的功能,除了執行 API 產品外,還可納入其他安全性和業務規則。

您可以使用 Kubernetes 適用的 Apigee APIM Operator,將下列政策新增至 Gateway:

總覽

以下各節將說明如何:

事前準備

如要使用本指南中用於示例的完整政策集修改 GKE Gateway,您必須擁有服務帳戶,並具備在 Apigee 中建立符記及部署 Proxy 和擴充功能所需的角色。如果您選擇「不」建立 Google 權杖,就不需要在服務帳戶中新增其他角色,可以直接跳到下一節。

如何建立具備必要權限的服務帳戶:

  1. 如果您在 Kubernetes 適用的 Apigee APIM Operator 安裝指南中建立了名為 apigee-apim-gsa 的服務帳戶,可以略過這個步驟,直接進行下一個步驟。否則,請建立服務帳戶:
    gcloud iam service-accounts create apigee-apim-gsa --project=$PROJECT_ID
  2. 授予服務帳戶建立權杖所需的角色:
    gcloud projects add-iam-policy-binding $PROJECT_ID \
      --member "serviceAccount:apigee-apim-gsa@$PROJECT_ID.iam.gserviceaccount.com" \
      --role "roles/iam.serviceAccountTokenCreator"
  3. 授予 apigee-apim-gsa 服務帳戶必要的角色,以便部署 Proxy 和擴充功能:
    gcloud projects add-iam-policy-binding $PROJECT_ID \
      --member "serviceAccount:apigee-apim-gsa@$PROJECT_ID.iam.gserviceaccount.com" \
      --role "roles/iam.serviceAccountUser"

使用政策修改 GKE 閘道

您可以選擇使用一或多項政策修改 GKE Gateway,藉此擴充功能。這個範例逐步操作說明會將 yaml 檔案套用至 Gateway,其中包含兩個 Apigee 政策和一個 Google 符記插入政策的規格。

使用下列 yaml 檔案套用至 Gateway 的每項政策,在評估傳送至 Gateway 的要求時,會執行不同的角色:

  • SpikeArrest 政策會定義一段時間內允許的最大要求頻率,藉此控制訊息傳送頻率的尖峰值。在這個範例中,每分鐘的最大速率設為五次。如要進一步瞭解如何使用 SpikeArrest 政策來平滑流量中的突然尖峰,請參閱「SpikeArrest 政策」。
  • 您可以透過 JavaScript 政策,在 Gateway 要求中加入自訂 JavaScript 程式碼。在本例中,政策用於在要求中加入自訂標頭。如要進一步瞭解如何使用 JavaScript 政策新增自訂程式碼,請參閱「JavaScript 政策」。
  • Google 權杖插入政策可用於使用AssignMessage 政策,將 Google 驗證存取權權杖插入 Gateway 要求。Apigee 支援使用 Google OAuth 權杖或 OpenID Connect 權杖,透過 Google 服務進行驗證。如要進一步瞭解驗證權杖,請參閱「使用 Google 驗證」。

將政策新增至 Gateway:

  1. apim 命名空間中建立名為 apigee-policies.yaml 的新檔案。
  2. 將下列檔案的內容複製到您建立的新檔案中:
    # apigee-policies.yaml
    apiVersion: apim.googleapis.com/v1
    kind: SpikeArrest
    metadata:
      name: spike-arrest
      namespace: apim
    spec:
      identifier:
        ref: request.header.name
      useEffectiveCount: true
      peakMessageRate:
        value: "5pm"
    ---
    apiVersion: apim.googleapis.com/v1
    kind: Javascript
    metadata:
      name: js-add-headers
      namespace: apim
    spec:
      timeLimit: 2000
      source: |
        var sum = 1+1;
        context.setVariable("request.header.first", 1);
        context.setVariable("request.header.second", 1);
        context.setVariable("request.header.sum", sum);
    ---
    apiVersion: apim.googleapis.com/v1
    kind: AssignMessage
    metadata:
      name: google-token-policy
      namespace: apim
    spec:
      setActions:
        - authentication:
            googleAccessToken:
              scopes:
                - 'https://www.googleapis.com/auth/cloud-platform'
      AssignTo:
        createNew: false
        type: request
    ---
    apiVersion: apim.googleapis.com/v1
    kind: KVM
    metadata:
      name: kvm-1
      namespace: apim
    spec:
      delete:
      - keys:
        - value: mykey
      description: kvm1
      displayName: kvm1
      exclusiveCache: true
      expiryTimeInSecs: 3600
      get:
      - assignTo: response.header.mykvm
        index: 0
        keys:
        - value: mykey
      initialEntries:
      - keys:s
        - key1
        values:s
        - val1
      - keys:s
        - mykey
        values:
        - initvalue
      isEncrypted: false
      mapIdentifier: mapIdentifier
      mapName:s
        ref: kvm.mapname
        value: kvmname
      put:
      - keys:
        - value: mykey
        values:
        - value: request.header.mykvm
      scope: environment
    ---
    apiVersion: apim.googleapis.com/v1
    kind: OASValidation
    metadata:
      name: oas-validation-1
    spec:
      openApiSpec: |
        openapi: 3.0.4
        info:
          title: Sample API
          description: Optional multi/single line description.
          version: 0.1.9
        servers:
          - url: http://apigee-apim-operator-test.apigee.net
            description: Optional server description, our main host in httproute
        paths:
          /get:
            get:
              summary: just for test
              description: Optional extended description in CommonMark or HTML.
              parameters:
                - name: X-Request-Type
                  in: header
                  description: Must be 'internal' or 'external'.
                  required: true
                  schema:
                    type: string
                    enum:
                      - internal
                      - external
              responses:
                '200': # status code
                  description: A JSON object
                  content:
                    application/json:
                      schema:
                        type: object
                        properties:
                          headers:
                            type: object
      source: request
    ---
    apiVersion: apim.googleapis.com/v1
    kind: ServiceCallout
    metadata:
      name: service-callout-1
      namespace: apim
    spec:
      request:
        clearPayload: true
        variable: myRequest
        ignoreUnresolvedVariables: true
        removeActions:
          - payload: true
          - queryParams:
            - name: rq-param1
            - name: rq-param2
        copyActions:
          - version: true
          - verb: true
        addActions:
          - headers:
            - name: X-header1
              value: value1
            - name: X-header2
              value: value2
          - queryParams:
            - name: q-param1
              value: value1
            - name: q-param2
              value: value2
        setActions:
          - verb: PUT
          - formParams:
            - name: f-param1
              value: value1
            - name: f-param2
              value: value2
      response: calloutResponse
      timeout: 30000
      httpTargetConnection:
        URL: https://httpbin.org/put
        properties:
          - name: success.codes
            value: 1xx,2xx,3xx,400
          - name: supports.http11
            value: "true"
  3. 使用下列指令將 yaml 檔案套用至 Gateway:
    kubectl -n apim apply -f apigee-policies.yaml

建立 TemplateRule 做為 SharedFlow 範本

在這個步驟中,您將建立 TemplateRule,以便強制執行已新增至閘道的政策。範本規則是組織管理員建立的 SharedFlow 規則,可確保服務開發人員只會將已核准的政策套用至 Gateway 流量。範本規則可確保開發人員瞭解可用的政策、特定用途所需的政策,以及服務開發人員無法使用的政策。

建立範本規則

建立範本規則,強制使用「AssignMessage」政策:

  1. apim 命名空間中建立名為 template-rule.yaml 的新 yaml 檔案。
  2. 將下列檔案的內容複製到您建立的新檔案中:
    # template-rule.yaml
    apiVersion: apim.googleapis.com/v1
    kind: ApimTemplateRule
    metadata:
      name: template-rule
      namespace: apim
    spec:
      allowList: [SpikeArrest, Javascript, GenerateJWT, KVM, OASValidation, OAuthv2, ServiceCallout]
      requiredList: [AssignMessage]
      denyList: []

    在這個範例中,範本規則會告知開發人員,必須使用 AssignMessage 政策,才能說明 Google 權杖插入政策。這項政策也會告知開發人員,他們可以在 API 管理中使用 SpikeArrest、JavaScript、GenerateJWT、KVM、OASValidation、OAuthv2 和 ServiceCallout 政策。拒絕清單中沒有指定任何政策。

套用範本規則

使用下列指令套用範本規則:

kubectl apply -f template-rule.yaml

建立 Apigee 範本以使用範本規則

建立 Apigee 範本,納入您在上一個部分建立的範本規則:

  1. apim 命名空間中建立名為 new-admin-template.yaml 的新 yaml 檔案。
  2. 將下列檔案的內容複製到您建立的新檔案中:
    # new-admin-template.yaml
    apiVersion: apim.googleapis.com/v1
    kind: ApimTemplate
    metadata:
      name: new-admin-template
      namespace: apim
    spec:
      apimTemplateRule:
        group: apim.googleapis.com
        kind: ApimTemplateRule
        name: template-rule
        namespace: apim
      templates:
      - mode: REQUEST
        flows:
        - name: preflow
          policies:
          - group: apim.googleapis.com
            kind: OASValidation
            name: oas-validation-1
            namespace: apim
          - group: apim.googleapis.com
            kind: SpikeArrest
            name: spike-arrest
            namespace: apim
        - name: ConditionalGetFlow
          policies:
          - group: apim.googleapis.com
            kind: Javascript
            name: js-add-headers
            namespace: apim
          condition: request.verb="GET"
        - name: postflow
          policies:
          - group: apim.googleapis.com
            kind: AssignMessage
            name: google-token-policy
            namespace: apim
          - group: apim.googleapis.com
            kind: ServiceCallout
            name: service-callout-1
            namespace: apim
      - mode: RESPONSE
        flows:
        - name: postflow
          policies:
          - group: apim.googleapis.com
            kind: KVM
            name: kvm-1
            namespace: apim
  3. 使用下列指令套用新範本:
    kubectl apply -f new-admin-template.yaml

部署 Apigee Gateway 政策

在這個步驟中,您會將新檔案套用至 Gateway,其中包含 ApigeeGatewayPolicy 的規格。這項政策用於將 Apigee 範本部署至閘道。

部署 Apigee Gateway 政策:

  1. apim 命名空間中建立名為 apigee-gateway-policy-withSA.yaml 的新 yaml 檔案。
  2. 將下列檔案的內容複製到您建立的新檔案中:
    # apigee-gateway-policy-withSA.yaml
    apiVersion: apim.googleapis.com/v1
    kind: ApigeeGatewayPolicy
    metadata:
      name: apim-template-injection
      namespace: apim
    spec:
      serviceAccount: apigee-apim-gsa@PROJECT_ID.iam.gserviceaccount.com
      ref:
        group: apim.googleapis.com
        kind: ApimTemplate
        name: new-admin-template
        namespace: apim
      targetRef:
        group: apim.googleapis.com
        kind: APIMExtensionPolicy
        name: global-ext-lb1-apim-policy
        namespace: apim
  3. 套用政策:
    kubectl apply -f apigee-gateway-policy-withSA.yaml
  4. 驗證新 Gateway 政策的部署狀態:
    kubectl -n apim get ApigeeGatewayPolicy

    部署完成後,政策 STATUS 應會顯示 CREATED

部署新 Gateway 政策後,請等待兩分鐘,再向 Gateway 傳送要求,讓政策傳播至叢集。

驗證政策違規處置

如要確認 Apigee Gateway 政策運作正常,請按照下列各節所述,向 Gateway 傳送要求。

指派訊息政策違規處置

如要確認系統會使用「AssignMessage」政策將 {company_name} 權杖插入要求中,請使用下列指令向 Gateway 傳送要求:

curl http://GATEWAY_IP_ADDRESS/get -H "Host: HOST_NAME" -H "x-api-key: API_KEY"

其中:

  • GATEWAY_IP_ADDRESS 是閘道的 IP 位址。您可以使用下列指令擷取 Gateway IP 位址:
    kubectl get gateway GATEWAY_NAME
  • HOST_NAME 是主機名稱。
  • API_KEY 是 API 金鑰值。

成功的回應應包含 Authorization 標頭,並附上產生的權杖權杖,類似於以下內容:

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Authorization": "Bearer ya29.c.c0ASRK0Gbw03y9cfvxL11DxaRYBQUU18SmUP4Vu63OckHI5cX7wJ4DmGMG2vbDDS69HXJHqMj-lak4tcqOsJGmE65crn2gNuJLanXidwM8",
    "First": "1.0",
    "Host": "apigee-apim-operator-test.apigee.net",
    "Second": "1.0",
    "Sum": "2",
    "User-Agent": "curl/8.7.1",
    "X-Api-Key": "McYcHGR3PTSGLXExvKADwQ1JJeCjgPDUvAakCl0rJKCFaX0Y",
    "X-Cloud-Trace-Context": "0fd3dadc2a3c328fa968d5f5f1434c29/18300783092696918345"
  },
  "origin": "34.54.108.129",
  "url": "apigee-apim-operator-test.apigee.net/get"
}

SpikeArrest 政策強制執行

您可以測試 SpikeArrest 政策的執行情況,方法是在一分鐘內向 Gateway 傳送十次要求。

您可以執行下列指令碼來產生要求:

#!/bin/sh
for i in $(seq 1 11); do
    curl http://GATEWAY_IP_ADDRESS/get -H "Host: HOST_NAME" -H "x-api-key: API_KEY"
    sleep 1
done

其中:

  • GATEWAY_IP_ADDRESS 是閘道的 IP 位址。您可以使用下列指令擷取 Gateway IP 位址,其中 GATEWAY_NAME 是 Gateway 的名稱:
    kubectl get gateways.gateway.networking.k8s.io GATEWAY_NAME -o=jsonpath="{.status.addresses[0].value}"
  • HOST_NAME 是 Gateway 的 HTTPRoute 中定義的主機名稱。
  • API_KEY 是「測試設定」中取得的 API 金鑰值。

回應會顯示類似以下的內容:

"fault":{"faultstring":"Spike arrest violation. Allowed rate : MessageRate{capacity=5, period=Minutes}","detail":{"errorcode":"policies.ratelimit.SpikeArrestViolation"}}}

JavaScript 政策強制執行

如要確認 JavaScript 政策是否正常運作,請使用下列指令向 Gateway 傳送要求:

curl http://GATEWAY_IP_ADDRESS/get \
  -H "Host: HOST_NAME" \
  -H "x-api-key: API_KEY" \
  -H "X-Request-Type: external" -i

其中:

  • GATEWAY_IP_ADDRESS 是閘道的 IP 位址。您可以使用下列指令擷取 Gateway IP 位址,其中 GATEWAY_NAME 是 Gateway 的名稱:
    kubectl get gateways.gateway.networking.k8s.io GATEWAY_NAME -o=jsonpath="{.status.addresses[0].value}"
  • HOST_NAME 是 Gateway 的 HTTPRoute 中定義的主機名稱。
  • API_KEY 是「測試設定」中取得的 API 金鑰值。

JavaScript 政策會設定三個要求標頭:FirstSecondSum,如回應所示:

HTTP/1.1 200 OK
...
{
  "args": {},
  "headers": {
    ...
    "First": "1.0",
    ...
    "Second": "1.0",
    "Sum": "2",
    ...
  },
  ...
}

強制執行 OASValidation 政策

如要確認 OASValidation 政策是否正常運作,請使用下列指令向 Gateway 傳送要求:

curl "http://GATEWAY_IP_ADDRESS/get"  \
  -H "Host: HOST_NAME" \
  -H "x-api-key: API_KEY" \
  -H "X-Request-Type: badvalue"

其中:

  • GATEWAY_IP_ADDRESS 是閘道的 IP 位址。您可以使用下列指令擷取 Gateway IP 位址,其中 GATEWAY_NAME 是 Gateway 的名稱:
    kubectl get gateways.gateway.networking.k8s.io GATEWAY_NAME -o=jsonpath="{.status.addresses[0].value}"
  • HOST_NAME 是 Gateway 的 HTTPRoute 中定義的主機名稱。
  • API_KEY 是「測試設定」中取得的 API 金鑰值。

指令包含 X-Request-Type 標頭的無效值。要求會失敗,並傳回類似以下的回應:

{"fault":{"faultstring":"OASValidation oas-validation-1 with resource \"oas:\/\/oas-validation-1.yaml\": failed with reason: \"[ERROR - Instance value (\"badvalue\") not found in enum (possible values: [\"internal\",\"external\"]): []]\"","detail":{"errorcode":"steps.oasvalidation.Failed"}}}

傳送相同要求,並為 X-Request-Type 標頭提供有效值,即可成功。例如:

curl "http://GATEWAY_IP_ADDRESS/get"  \
  -H "Host: HOST_NAME" \
  -H "x-api-key: API_KEY" \
  -H "X-Request-Type: external" -i

其中:

  • GATEWAY_IP_ADDRESS 是閘道的 IP 位址。您可以使用下列指令擷取 Gateway IP 位址,其中 GATEWAY_NAME 是 Gateway 的名稱:
    kubectl get gateways.gateway.networking.k8s.io GATEWAY_NAME -o=jsonpath="{.status.addresses[0].value}"
  • HOST_NAME 是 Gateway 的 HTTPRoute 中定義的主機名稱。
  • API_KEY 是「測試設定」中取得的 API 金鑰值。

ServiceCallout 政策強制執行

您可以開啟偵錯工作階段,並向 Proxy 傳送一些有效要求,藉此驗證 ServiceCallout 政策的執行情況。

如要開啟偵錯工作階段,請按照下列步驟操作:

  1. 前往 Google Cloud 控制台的「API Proxies」頁面。

    前往「API Proxy」

  2. 選取已部署至為 Kubernetes 的 Apigee APIM Operator 建立的環境中的 global-ext-lb1-apim-policy Proxy。
  3. 按一下「Debug」分頁標籤。
  4. 在「Debug session」視窗中,按一下「Start Debug Session」
  5. 在「Debug session」窗格中,選取下列項目:
    • 環境:從可用環境清單中選取您為 APIM 操作員建立的環境。
    • 篩選條件:選取「無 (所有交易)」
  6. 按一下「啟動」

工作階段開始後,您就可以向 Proxy 傳送有效要求:

curl "GATEWAY_IP_ADDRESSget"  \
  -H "Host: HOST_NAME" \
  -H "x-api-key: API_KEY" \
  -H "X-Request-Type: external" -i

其中:

  • GATEWAY_IP_ADDRESS 是閘道的 IP 位址。您可以使用下列指令擷取 Gateway IP 位址,其中 GATEWAY_NAME 是 Gateway 的名稱:
    kubectl get gateway GATEWAY_NAME
  • HOST_NAME 是 Gateway 的 HTTPRoute 中定義的主機名稱。
  • API_KEY 是「測試設定」中取得的 API 金鑰值。

要求和回應交易會顯示在「Transactions」窗格中。從清單中選取成功的交易,即可顯示流程。您應該會看到 ServiceCallout 政策已成功執行。

KVM 政策強制執行

KVM 政策執行成功後,系統會使用金鑰 mykey 的起始值初始化 KVM。當有回應交易時,KVM 政策會擷取 mykey 的值,並將其儲存在回應標頭 mykvm 中。當 KVM 政策再次執行時,系統會插入從要求標頭 mykvm 取得的 mykey 新值。

您可以檢查每筆交易的標頭,確認政策會在某筆交易中將值儲存在 KVM,並在下一個交易中擷取相同的值,如以下範例所示。

測試 KVM 政策:

  1. 傳送要求至 Gateway:
    curl -i "http://GATEWAY_IP_ADDRESS/get" \
      -H "Host: HOST_NAME" \
      -H "x-api-key: API_KEY" \
      -H "X-Request-Type: external" \
      -H "KVM_NAME: next-value1" -i

    其中:

    • GATEWAY_IP_ADDRESS 是閘道的 IP 位址。您可以使用下列指令擷取 Gateway IP 位址,其中 GATEWAY_NAME 是 Gateway 的名稱:
      kubectl get gateway GATEWAY_NAME
    • HOST_NAME 是 Gateway 的 HTTPRoute 中定義的主機名稱。
    • API_KEY 是「測試設定」中取得的 API 金鑰值。
    • KVM_NAME 是 KVM 的名稱。

  2. 請檢查回應標頭,確認 KVM 政策已成功執行,且已為 mykvm 儲存初始值。回應內容應如下所示:
    HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    Content-Length: 517
    content-type: application/json
    date: ...
    server: gunicorn/19.9.0
    mykvm: initvalue
    via: 1.1 google
    {
      "args": {
      ...
      "url": "http://apigee-apim-operator-test.apigee.net/get"
      }
    }
  3. 向 Gateway 傳送另一項要求:
    curl -i "http://GATEWAY_IP_ADDRESS/get" \
      -H "Host: HOST_NAME" \
      -H "x-api-key: API_KEY" \
      -H "mykvm: next"X-Request-Type: external" -H "mykvm: next-value2" -i

    回應應類似以下:

    HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    Content-Length: 517
    content-type: application/json
    date: ...
    server: gunicorn/19.9.0
    mykvm: next-value2
    via: 1.1 google
    {
      "args": {
      ...
      "url": "http://apigee-apim-operator-test.apigee.net/get?rq-param2=rq-val1&x-param1=xval1"
      }
    }

    您可以看到 KVM 政策已成功執行,因為 mykvm 標頭的值已更新為要求標頭 mykvm 的值。

  4. 再傳送一次要求:
    curl -i "http://GATEWAY_IP_ADDRESS/get" \
      -H "Host: HOST_NAME" \
      -H "x-api-key: API_KEY" \
      -H "X-Request-Type: external" -H "mykvm: next-value3" -i

    回應應類似以下:

    HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    Content-Length: 517
    content-type: application/json
    date: ...
    server: gunicorn/19.9.0
    mykvm: next-value2
    via: 1.1 google
    {
      "args": {
      ...
      "url": "http://apigee-apim-operator-test.apigee.net/get?rq-param2=rq-val1&x-param1=xval1"
      }
    }

    mykvm 標頭的值再次更新,顯示回應中顯示的值是先前交易中儲存的值。

疑難排解

如果在為 GKE Gateway 新增政策時遇到問題,請參閱「排解 APIM Operator 問題」,瞭解如何解決常見錯誤。

後續步驟