為 GKE 閘道新增政策

本頁內容適用於 Apigee,但不適用於 Apigee Hybrid

查看 Apigee Edge 說明文件。

本頁面說明如何使用適用於 Kubernetes 的 Apigee APIM 運算子,將 Apigee 執行階段政策和 Google 權杖插入政策 新增至 Google Kubernetes Engine (GKE) Gateway。在 Gateway 中新增一組可用的政策,即可將 Gateway 的功能擴展至 API 產品強制執行以外的範圍,納入額外的安全性和業務規則。

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

總覽

以下各節將說明如何:

事前準備

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

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

  1. 如果您已在 Apigee APIM Operator for Kubernetes 安裝指南中建立名為 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. 將部署 Proxy 和擴充功能所需的角色授予 apigee-apim-gsa 服務帳戶:
    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 政策,在閘道要求中加入自訂 JavaScript 程式碼。在本例中,這項政策用於在要求中新增自訂標頭。如要進一步瞭解如何使用 JavaScript 政策新增自訂程式碼,請參閱「JavaScript 政策」。
  • Google 權杖插入政策會使用 AssignMessage 政策,將 Google 驗證存取權杖插入 Gateway 要求。Apigee 支援使用 Google OAuth 權杖或 OpenID Connect 權杖向 Google 服務進行驗證。如要進一步瞭解驗證權杖,請參閱「使用 Google 驗證」。

將政策新增至閘道:

  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
      exclusiveCache: true
      expiryTimeInSecs: 3600
      get:
      - assignTo: response.header.mykvm
        keys:
        - value: mykey
      initialEntries:
      - keys:
        - key1
        values:
        - val1
      - keys:
        - mykey
        values:
        - initvalue
      isEncrypted: false
      put:
      - keys:
        - value: mykey
        values:
        - value: request.header.mykvm
      scope: environment
    ---
    apiVersion: apim.googleapis.com/v1
    kind: OASValidation
    metadata:
      name: oas-validation-1
      namespace: apim
    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 檔案套用至閘道:
    kubectl -n apim apply -f apigee-policies.yaml

以 SharedFlow 範本的形式建立 TemplateRule

在本步驟中,您將建立 TemplateRule,強制執行您新增至閘道的政策。 範本規則是機構管理員為 SharedFlows 建立的規則,可確保服務開發人員只會將核准的政策套用至閘道流量。範本規則可確保開發人員瞭解可用的政策、特定用途的必要政策,以及服務開發人員無法使用的政策。

建立範本規則

建立範本規則,強制執行 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: []

    在本範例中,範本規則會告知開發人員,說明 Google 權杖插入政策的 AssignMessage 政策為必要項目。此外,也告知開發人員可在 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. 確認新閘道政策的部署狀態:
    kubectl -n apim get ApigeeGatewayPolicy

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

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

驗證政策強制執行

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

AssignMessage 政策執行

如要確認 {company_name} 權杖是否已透過 AssignMessage 政策注入要求,請使用下列指令將要求傳送至 Gateway:

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

其中:

  • GATEWAY_IP_ADDRESS 是閘道的 IP 位址。您可以使用下列指令擷取閘道 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 政策的強制執行情況,請在一分鐘內向閘道傳送十次要求。

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

#!/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 位址。您可以使用下列指令擷取閘道 IP 位址,其中 GATEWAY_NAME 是閘道的名稱:
    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 位址。您可以使用下列指令擷取閘道 IP 位址,其中 GATEWAY_NAME 是閘道的名稱:
    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 政策是否正常運作,請使用下列指令將要求傳送至閘道:

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

強制執行 ServiceCallout 政策

如要驗證 ServiceCallout 政策的強制執行情況,請開啟偵錯工作階段,並傳送幾個有效要求至 Proxy。

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

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

    前往「API Proxies」

  2. 選取您部署至 Apigee APIM Operator for Kubernetes 所建立環境的 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 位址。您可以使用下列指令擷取閘道 IP 位址,其中 GATEWAY_NAME 是閘道的名稱:
    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. 將要求傳送至閘道:
    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 位址。您可以使用下列指令擷取閘道 IP 位址,其中 GATEWAY_NAME 是閘道的名稱:
      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. 向閘道傳送另一項要求:
    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"
      }
    }

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

  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 運算子問題」,瞭解如何解決常見錯誤。

後續步驟