向 GKE 网关添加政策

本页面适用于 Apigee,但不适用于 Apigee Hybrid

查看 Apigee Edge 文档。

本页面介绍了如何使用 Apigee APIM Operator for Kubernetes 将 Apigee 运行时政策和 Google 令牌注入政策添加到 Google Kubernetes Engine (GKE) 网关。 通过将一组可用的政策添加到网关,您可以将网关的功能扩展到 API 产品实施范围之外,以包含其他安全和业务规则。

Apigee APIM Operator for Kubernetes 可用于向网关添加以下政策:

概览

以下各部分介绍如何执行以下操作:

准备工作

如需使用本指南中用作示例的完整的政策集修改 GKE 网关,您必须拥有一个服务账号,并具有在 Apigee 中创建令牌以及部署代理和扩展程序所需的角色。如果您选择不创建 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. 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 网关,以扩展其功能。本示例演示将 yaml 文件应用于网关,该文件包含两项 Apigee 政策和一项 Google 令牌注入政策的规范。

使用以下 yaml 文件向网关应用的每项政策在评估发送到网关的请求时都会发挥不同的作用:

  • SpikeArrest 政策通过定义单位时间内允许的请求数上限来控制峰值消息速率。在此示例中,速率上限设置为每分钟 5 个。如需详细了解如何使用 SpikeArrest 政策来平滑流量的突然激增,请参阅 SpikeArrest 政策
  • 借助 JavaScript 政策,您可以将自定义 JavaScript 代码添加到网关请求。在此示例中,该政策用于将自定义标头添加到请求。如需详细了解如何使用 JavaScript 政策添加自定义代码,请参阅 JavaScript 政策
  • Google 令牌注入政策用于使用 AssignMessage 政策将 Google 身份验证访问令牌注入到网关请求中。 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

创建 TemplateRule 作为 SharedFlow 模板

在此步骤中,您将创建一个 TemplateRule 以实施您已添加到网关的政策。 模板规则是组织管理员为 SharedFlow 创建的规则,以确保服务开发者仅将已获批准的政策应用于网关流量。模板规则可确保开发者了解哪些政策可供他们使用、哪些政策是特定应用场景所必需的,以及服务开发者无法使用哪些政策。

创建模板规则

创建一个模板规则,以强制使用 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 网关政策

在此步骤中,您将向网关应用一个包含 ApigeeGatewayPolicy 规范的新文件。 此政策用于将 Apigee 模板部署到网关。

部署 Apigee 网关政策:

  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

部署新的网关政策后,请等待两分钟,然后再向网关发送请求,以便政策传播到集群。

验证政策实施情况

如需确认 Apigee 网关政策按预期正常生效,请按照以下部分中的说明向网关发送请求。

AssignMessage 政策强制执行

如需确认 {company_name} 令牌已使用 AssignMessage 政策注入到请求中,请使用以下命令向网关发送请求:

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 政策强制执行

您可以在 1 分钟内向网关发送 10 次请求,以测试 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 是网关的 HTTPRoute 中定义的主机名。
  • API_KEY 是在测试设置中获取的 API 密钥值。

响应将类似如下所示:

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

JavaScript 政策强制执行

如需确认 JavaScript 政策按预期正常生效,请使用以下命令向网关发送请求:

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 是网关的 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 是网关的 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 是网关的 HTTPRoute 中定义的主机名。
  • API_KEY 是在测试设置中获取的 API 密钥值。

ServiceCallout 政策强制执行

您可以打开调试会话并向代理发送一些有效请求,以验证 ServiceCallout 政策的强制执行情况。

如需打开调试会话,请按照以下步骤操作:

  1. 在 Google Cloud 控制台中,前往 API 代理页面。

    前往 API 代理

  2. 选择您部署到为 Apigee APIM Operator for Kubernetes 创建的环境中的 global-ext-lb1-apim-policy 代理。
  3. 点击调试标签页。
  4. 调试会话窗口中,点击启动调试会话
  5. 调试会话窗格中,进行以下选择:
    • 环境:从可用环境列表中选择您为 APIM Operator 创建的环境。
    • 过滤条件:选择无(所有事务)
  6. 点击开始

会话开始后,您可以向代理发送有效请求:

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 是网关的 HTTPRoute 中定义的主机名。
  • API_KEY 是在测试设置中获取的 API 密钥值。

请求和响应事务会显示在事务窗格中。从列表中选择一笔成功交易,以显示相应流程。您应该能够看到 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 是网关的 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"
      }
    }

    您可以看到,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 网关添加政策时遇到问题,请参阅排查 APIM Operator 问题,以了解常见错误的解决方案。

后续步骤