GKE Gateway にポリシーを追加する

このページは ApigeeApigee ハイブリッドに適用されます。

Apigee Edge のドキュメントを表示する。

このページでは、Apigee Operator for Kubernetes を使用して、Apigee ランタイム ポリシーと Google トークン挿入ポリシーを Google Kubernetes Engine(GKE)Gateway に追加する方法について説明します。使用可能なポリシーセットを Gateway に追加すると、API プロダクトの適用を超えて Gateway の機能を拡張し、追加のセキュリティ ルールとビジネスルールを含めることができます。

Apigee Operator for Kubernetes を使用して、Gateway に次のポリシーを追加できます。

概要

以降のセクションでは、次の方法について説明します。

始める前に

このガイドの例として使用されているすべてのポリシーを使用して GKE Gateway を変更するには、Apigee 内でトークンを作成し、プロキシと拡張機能をデプロイするために必要なロールが付与されているサービス アカウントが必要です。 Google トークンを作成しない場合は、サービス アカウントに追加のロールを追加する必要はありません。次のセクションに進みます。

必要な権限を持ったサービス アカウントを作成するには:

  1. Apigee 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 Gateway を変更する

1 つ以上のポリシーを使用して GKE Gateway を変更し、機能を拡張できます。このチュートリアルの例では、2 つの Apigee ポリシーと Google トークン挿入ポリシーの仕様を含む yaml ファイルを Gateway に適用します。

次の yaml ファイルを使用して Gateway に適用される各ポリシーは、Gateway に送信されたリクエストを評価するときにそれぞれ異なるロールを実行します。

  • SpikeArrest ポリシーは、一定の時間内に許可されるリクエストの最大レートを定義することで、ピーク メッセージ レートを制御します。この例では、最大レートは 1 分あたり 5 に設定されています。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
      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 ファイルを Gateway に適用します。
    kubectl -n apim apply -f apigee-policies.yaml

SharedFlow テンプレートとして TemplateRule を作成する

このステップでは、Gateway に追加したポリシーを適用するために 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: []

    この例では、テンプレート ルールにより、デベロッパーは 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 ポリシーをデプロイする

この手順では、ApigeeGatewayPolicy の仕様を含む新しいファイルを Gateway に適用します。このポリシーは、Apigee テンプレートを Gateway にデプロイするために使用されます。

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: APIMEXTENSION_POLICY_NAME
        namespace: apim

    PROJECT_ID は、実際の Google Cloud プロジェクト ID に置き換えます。

    APIMEXTENSION_POLICY_NAME は、Apigee Gateway ポリシーの適用に使用する APIMExtensionPolicy の名前に置き換えます。トラフィック拡張機能を作成するために APIMExtensionPolicy を作成した場合は、作成したポリシーの名前を使用します。ApigeeBackendService を使用してトラフィック拡張機能を作成した場合は、ApigeeBackendService の名前を使用します。ApigeeBackendService を作成すると、Apigee Operator for Kubernetes により、BackendService と同じ名前と名前空間の APIMExtensionPolicy が作成されます。

  3. ポリシーを適用します。
    kubectl apply -f apigee-gateway-policy-withSA.yaml
  4. 新しい Gateway ポリシーのデプロイ ステータスを確認します。
    kubectl -n apim get ApigeeGatewayPolicy

    デプロイすると、ポリシー STATUSCREATED と表示されます。

新しい Gateway ポリシーがデプロイされたら、2 分待ってから Gateway にリクエストを送信し、ポリシーがクラスタに伝播されるようにします。

ポリシーの適用を確認する

Apigee Gateway ポリシーが想定どおりに機能していることを確認するには、次のセクションで説明するように Gateway にリクエストを送信します。

AssignMessage ポリシーの適用

AssignMessage ポリシーを使用して {company_name} トークンがリクエストに挿入されていることを確認するには、次のコマンドを使用して Gateway にリクエストを送信します。

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

ここで

  • GATEWAY_IP_ADDRESS は Gateway の 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 ポリシーの適用をテストするには、1 分以内に Gateway に 10 回リクエストを送信します。

次のスクリプトを実行してリクエストを生成できます。

#!/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 は Gateway の 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 は Gateway の 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 の 3 つのリクエスト ヘッダーを設定します。

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 は Gateway の 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 は Gateway の 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 ポリシーの適用

ServiceCallout ポリシーの適用を確認するには、デバッグ セッションを開き、プロキシに有効なリクエストをいくつか送信します。

デバッグ セッションを開く手順は次のとおりです。

  1. Google Cloud コンソールで、[API プロキシ] ページに移動します。

    [API プロキシ] に移動

  2. Apigee Operator for Kubernetes 用に作成された環境にデプロイした global-ext-lb1-apim-policy プロキシを選択します。
  3. [Debug] タブをクリックします。
  4. [Debug session] ウィンドウで、[Start Debug Session] をクリックします。
  5. [Debug session] ペインで、次の項目を選択します。
    • 環境: 使用可能な環境のリストから、Apigee Operator for Kubernetes 用に作成した環境を選択します。
    • フィルタ: [None (All transaction)] を選択します。
  6. [開始] をクリックします。

セッションが開始されたら、有効なリクエストをプロキシに送信できます。

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

ここで

  • GATEWAY_IP_ADDRESS は Gateway の IP アドレスです。Gateway の IP アドレスは、次のコマンドを使用して取得できます。ここで、GATEWAY_NAME は Gateway の名前です。
    kubectl get gateway GATEWAY_NAME
  • HOST_NAME は、Gateway の HTTPRoute で定義されたホスト名です。
  • API_KEY は、テストの設定で取得した API キー値です。

リクエスト トランザクションとレスポンス トランザクションが [トランザクション] ペインに表示されます。リストから成功したトランザクションを選択して、フローを表示します。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 は Gateway の 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"
      }
    }

    mykvm ヘッダーの値がリクエスト ヘッダー mykvm の値に更新されているため、KVM ポリシーが正常に実行されたことがわかります。

  4. さらに 1 つリクエストを送信します。
    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 にポリシーを追加するときに問題が発生した場合は、Apigee Operator for Kubernetes のトラブルシューティングで一般的なエラーの解決策をご覧ください。

次のステップ