ExternalCallout ポリシー

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

Apigee Edge のドキュメントはこちらをご覧ください。

ポリシー アイコン

概要

ExternalCallout ポリシーを使用すると、gRPC サーバーに gRPC リクエストを送信し、Apigee ポリシーでサポートされていないカスタム動作を実装できます。サーバーのコードでは、プロキシのフロー内でフロー変数に簡単にアクセスして変更できます。

Apigee は、API を介して ExternalCallout ポリシーを介して gRPC サーバーと通信します。 Apigee は、API を使用してフロー変数を gRPC サーバーに送信します。gRPC サーバー内では、フロー変数のリファレンス ページに記載されているフロー変数と、ポリシーの XML 内で指定した追加の変数の読み取りが可能です。また、変数によっては修正することもできます。

Apigee で gRPC サーバーを構成し、このポリシーをプロキシに含めると、Apigee は次のように API リクエストを処理します。

  1. Apigee では、フロー変数を含むメッセージが gRPC サーバーに送信されます。
  2. gRPC サーバーコードは、そのコードで定義されているように、変数へのアクセスと変更を実行します。次に、gRPC サーバーはすべてのフロー変数を含むレスポンスを Apigee に送り返します。
  3. Apigee は gRPC サーバーからレスポンスを読み取ります。変数が追加されたり、変更可能なフロー変数が変更されたりすると、Apigee でそれらが更新されます。

このポリシーは、標準ポリシーであり、任意の環境タイプにデプロイできます。すべてのユーザーがポリシーや環境のタイプを知る必要はありません。ポリシータイプと各環境タイプで使用可能かどうかは、ポリシータイプをご覧ください。

gRPC リクエストの送信について詳しくは、次のリンクをご覧ください。

<ExternalCallout>

ExternalCallout ポリシーを定義します。

<ExternalCallout async="true" continueOnError="true" enabled="true" name="EC">

この要素には、すべてのポリシーに共通する次の属性があります。

属性 デフォルト 必須かどうか 説明
name なし 必須

ポリシーの内部名。name 属性の値には、英字、数字、スペース、ハイフン、アンダースコア、ピリオドを使用できます。この値は 255 文字を超えることはできません。

管理 UI プロキシ エディタで <DisplayName> 要素を追加して、ポリシーのラベルに使用する別の自然言語名を指定することもできます。

continueOnError false 省略可 ポリシーが失敗したときにエラーを返す場合は、false に設定します。これは、ほとんどのポリシーで想定される動作です。ポリシーが失敗した後もフローの実行を続行する場合は、true に設定します。関連情報:
enabled true 省略可 ポリシーを適用するには、true に設定します。ポリシーを無効にするには、false に設定します。ポリシーがフローに接続されている場合でも適用されません。
async   false 非推奨 この属性は非推奨となりました。

次の表に、<ExternalCallout> の子要素を示します。

子要素 必須 説明
<TimeoutMs> 必須 gRPC リクエストのリクエスト タイムアウト(ミリ秒)。
<GrpcConnection> 必須 リクエストを送信する gRPC サーバーにする既存の TargetServer の名前を指定します。
<Configurations> 省略可 ExternalCallout ポリシーのさまざまな側面(<Property> 要素や <FlowVariable> 要素など)を構成できます。

例 1

ExternalCallout の実用的な例については、GitHub の ExternalCallout サンプルをご覧ください。

次の例は、ExternalCallout ポリシーの構成を示しています。

<ExternalCallout enabled="true" continueOnError="false" name="ExternalCallout-1">
  <DisplayName>External Callout 1</DisplayName>
  <TimeoutMs>5000</TimeoutMs>
  <GrpcConnection>
    <Server name="external-target-server"/>
  </GrpcConnection>
  <Configurations>
    <Property name="with.request.content">true</Property>
    <Property name="with.request.headers">false</Property>
    <Property name="with.response.content">true</Property>
    <Property name="with.response.headers">false</Property>
    <FlowVariable>example1.flow.variable</FlowVariable>
    <FlowVariable>example2.flow.variable</FlowVariable>
  </Configurations>
<ExternalCallout>

この例では、次の構成を使用して、external-target-server という名前の TargetServer で表される外部 gRPC サーバーにリクエストを送信します。

  • <Property>: gRPC サーバーに送信されるリクエストに、リクエストとレスポンスのヘッダーではなく、リクエストとレスポンスのコンテンツは含めます。
  • <FlowVariable>: FlowVariable 要素で指定された追加のフロー変数example1.flow.variableexample2.flow.variable)を、gRPC サーバーに送信されたリクエストに含めます。

例 2

次の例では、Audience 要素の useTargetUrl 属性が true に設定されています。useTargetUrltrue の場合、gRPC ターゲット サーバーのホスト名がオーディエンスとして使用されます。たとえば、サーバーのホストが my-grpc-server-java.a.run.app の場合、使用されるオーディエンスは https://my-grpc-server-java.a.run.app になります。

<ExternalCallout continueOnError="false" enabled="true" name="External-Callout-1">
  <DisplayName>External-Callout-1</DisplayName>
  <GrpcConnection>
    <Server name="cloud_run_server_name"/>
    <Authentication>
      <GoogleIDToken>
        <Audience useTargetUrl="true"/>
      </GoogleIDToken>
    </Authentication>
  </GrpcConnection>
  <TimeoutMs>5000</TimeoutMs>
  <Configurations>
    <Property name="with.request.content">true</Property>
    <Property name="with.request.headers">true</Property>
    <Property name="with.response.content">true</Property>
    <Property name="with.response.headers">true</Property>
    <FlowVariable>example.flow.variable</FlowVariable>
    <FlowVariable>another.flow.variable</FlowVariable>
  </Configurations>
</ExternalCallout>

子要素のリファレンス

以降のセクションでは、ExternalCallout の子要素について説明します。

<TimeoutMs>

gRPC リクエストのリクエスト タイムアウト(ミリ秒)。<TimeoutMs> は正の数にする必要があります。

<GrpcConnection>

<GrpcConnection> 要素により、gRPC サーバーが、name 属性で指定された既存の TargetServer に設定されます。TargetServer リソースのリファレンス ページをご覧ください。

注: TargetServerプロトコルGRPC にする必要があります。

たとえば、次のコードがあるとします。

<GrpcConnection>
  <Server name="external-target-server"/>
</GrpcConnection>

external-target-server という名前の既存の TargetServer となる gRPC サーバーを指定します。

<Authentication> 要素(このセクションで後述)を使用して、Google 発行の OpenID Connect トークンを生成し、Cloud Run でホストされるカスタム サービスなどの gRPC ベースのサービスに対する認証済み呼び出しを行います。

次の表に、<GrpcConnection> の子要素を示します。

子要素 必須かどうか 説明
<Server> 要素 必須 gRPC サーバーを指定します。
<Authentication> 要素 省略可 Google 発行の OpenID Connect トークンを生成し、Cloud Run などの gRPC ベースのサービスに対する認証された呼び出しを行います。

<Server> 要素

gRPC サーバーを指定します。

次の表に、<Server> 要素の属性を示します。

属性 説明 デフォルト 要否
name

リクエストの送信先の gRPC サーバーとなる既存の TargetServer の名前。

なし 必須 文字列

<Authentication> 要素

Google 発行の OpenID Connect トークンを生成し、Cloud Run でホストされているカスタム サービスなど、gRPC ベースのサービスに対する認証された呼び出しを行います。この要素を使用するには、Google 認証システムの使用で説明されている設定とデプロイの手順が必要です。適切に設定すると、ポリシーは認証トークンを作成し、それをサービス リクエストに追加します。

この要素には必須の子要素 GoogleIDToken が 1 つあります。

デフォルト なし
必須かどうか 省略可。
複合型
親要素 <GrpcConnection>
子要素 <GoogleIDToken>

Authentication 要素の構文は次のとおりです。

構文

<ExternalCallout>
...
  <GrpcConnection>
    <Server name="cloud_run_server_name"/>
    <Authentication>
      <HeaderName ref="FLOW_VARIABLE">STRING</HeaderName>
      <GoogleIDToken>
         <Audience ref="variable-1">STRING</Audience>
         <IncludeEmail ref="variable-2">BOOLEAN</IncludeEmail>
      </GoogleIDToken>
    </Authentication>
  </GrpcConnection>
</ExternalCallout>

次の例は、GoogleIDToken 要素を示しています。

<ExternalCallout continueOnError="false" enabled="true" name="External-Callout-1">
  <DisplayName>External-Callout-1</DisplayName>
  <GrpcConnection>
     <Server name="cloud_run_server_name"/>
     <Authentication>
        <HeaderName ref='my-variable'>X-Serverless-Authorization</HeaderName>
        <GoogleIDToken>
           <Audience>https://cloudrun-hostname.a.run.app</Audience>
        </GoogleIDToken>
     </Authentication>
  </GrpcConnection>
  <TimeoutMs>5000</TimeoutMs>
  <Configurations>
    <Property name="with.request.content">true</Property>
    <Property name="with.request.headers">true</Property>
    <Property name="with.response.content">true</Property>
    <Property name="with.response.headers">true</Property>
    <FlowVariable>example.flow.variable</FlowVariable>
    <FlowVariable>another.flow.variable</FlowVariable>
  </Configurations>
</ExternalCallout>

属性

なし。

<HeaderName> 子要素

デフォルトでは、認証構成が存在する場合、Apigee は署名なしトークンを生成し、ターゲット システムに送信されるメッセージの Authorization ヘッダーにそれを挿入します。HeaderName 要素を使用すると、別のヘッダーの名前を指定して、その署名なしトークンを保持できます。この機能は、ターゲットが X-Serverless-Authorization ヘッダーを使用する Cloud Run サービスである場合に特に役立ちます。Authorization ヘッダーが存在する場合は、そのヘッダーも変更されない状態でリクエストで送信されます。

デフォルト なし
必須かどうか いいえ
文字列
親要素 <Authentication>
子要素 なし

HeaderName 要素の構文は次のとおりです。

構文

<ExternalCallout>
...
  <Authentication>
    <HeaderName ref="FLOW_VARIABLE">STRING</HeaderName>
    <GoogleIDToken>
    ...
    </GoogleIDToken>
  </Authentication>
  ...
</ExternalCallout>

静的文字列を使用する場合

この例では、生成された署名なしトークンがデフォルトでは X-Serverless-Authorization という名前のヘッダーに追加され、ターゲット システムに送信されます。Authorization ヘッダーが存在する場合は、そのヘッダーも変更されない状態でリクエストで送信されます。

<Authentication>
  <HeaderName>X-Serverless-Authorization</HeaderName>
  <GoogleIDToken>
    <Audience>https://cloudrun-hostname.a.run.app</Audience>
  </GoogleIDToken>
</Authentication>

変数参照を使用する場合

この例では、生成された署名なしトークンがデフォルトでは X-Serverless-Authorization という名前のヘッダーに追加され、ターゲット システムに送信されます。my-variable に値がある場合は、デフォルトの文字列の代わりにその値が使用されます。Authorization ヘッダーが存在する場合は、そのヘッダーも変更されない状態でリクエストで送信されます。

<Authentication>
  <HeaderName ref='my-variable'>X-Serverless-Authorization</HeaderName>
  <GoogleIDToken>
    <Audience>https://cloudrun-hostname.a.run.app</Audience>
  </GoogleIDToken>
</Authentication>
<GoogleIDToken> 子要素

Google 発行の OpenID Connect トークンを生成し、Cloud Run でホストされているカスタム サービスなど、Google サービスに対して認証された呼び出しを行います。

デフォルト なし
必須かどうか 必須
文字列
親要素 <Authentication>
子要素 <Audience>
<IncludeEmail>

GoogleIDToken 要素の構文は次のとおりです。

構文

<ExternalCallout>
...
  <GrpcConnection>
    <Server name="cloud_run_server_name"/>
    <Authentication>
      <GoogleIDToken>
        <Audience ref="context-variable" useTargetUrl='BOOLEAN'>STRING</Audience>
        <IncludeEmail ref="context-variable">BOOLEAN</IncludeEmail>
      </GoogleIDToken>
    </Authentication>
  </GrpcConnection>
</ExternalCallout>

次の例は、GoogleIDToken 要素を示しています。

<Authentication>
  <GoogleIDToken>
      <Audience>https://httpserver0-bar.run.app</Audience>
      <IncludeEmail>true</IncludeEmail>
  </GoogleIDToken>
</Authentication>
<Audience> 子要素

生成された認証トークンのオーディエンス(トークンがアクセス権を付与する API やアカウントなど)。

Audience の値が空の場合、ref が空か、空の値に解決されます。useTargetUrltrue の場合は、「https://」+(gRPC ターゲット サーバーのホスト名)がオーディエンスとして使用されます。たとえば、サーバーのホストが my-grpc-server-java.a.run.app の場合、使用されるオーディエンスは https://my-grpc-server-java.a.run.app になります。

デフォルトでは、useTargetUrlfalse となっています。

<Audience>explicit-audience-value-here</Audience>

or:

<Audience ref='variable-name-here'/>

or:

<Audience ref='variable-name-here' useTargetUrl='true'/>

or:

<Audience useTargetUrl='true'/>
デフォルト なし
必須かどうか 必須
文字列
親要素 <GoogleIDToken>
子要素 なし。
<IncludeEmail> 子要素

true に設定すると、生成された認証トークンには、サービス アカウント emailemail_verified クレームが含まれます。

デフォルト false
必須かどうか 省略可
ブール値
親要素 <GoogleIDToken>
子要素 なし。

<Configurations>

<Configurations> 要素を使用すると、ExternalCallout ポリシーのさまざまな側面(<Property><FlowVariable> など)を構成できます。

次の表に、<Configurations> の子要素を示します。

子要素 必須かどうか 説明
<Property> 必須

リクエスト / レスポンス ヘッダーやコンテンツをサーバーに送信するかどうかを指定します。指定可能な値は true または false です。デフォルトは false です。

<FlowVariable> 必須

サーバーに送信する必要がある追加のフロー変数を指定します。

<Property>

<Property> 要素は、リクエスト / レスポンス ヘッダーやコンテンツをサーバーに送信するかどうかを指定します。指定できる値は true(アイテムが送信される)または false(アイテムが送信されない)です。デフォルト値は false です。

次の表に、<Property> 要素の属性を示します。

属性 説明 デフォルト 要否
name

サーバーに送信するコンテンツを指定します。name に指定できる値は次のとおりです。

  • with.request.content
  • with.request.headers
  • with.response.content
  • with.response.headers
なし 必須 文字列

<FlowVariable>

<FlowVariable> 要素には、サーバーに送信される追加のフロー変数を指定します。<FlowVariable> の値は、完全な変数名ではなく、変数の接頭辞です。たとえば、要素が a.b.c の場合、a.b.c という名前の変数の値がサーバーに送信されます。同様に、a.b.c.my-variable という名前の変数の値がサーバーに送信されます。ただし、a.x.another-variable という名前の変数には接頭辞 a.b.c がないため、値は送信されません。次に例を示します。

<Configurations>
  <FlowVariable>a.b.c</FlowVariable>
  <FlowVariable>d.e.f</FlowVariable>
</Configurations>

エラー リファレンス

デプロイエラー

エラー名 原因
FAILED_PRECONDITION このエラーは、プロキシが <Authentication> タグで構成されている場合に、サービス アカウントがないと発生します。

例:


Deployment of \"organizations/foo/apis/apiproxy/revisions/1\"
requires a service account identity, but one was not provided
with the request.
PERMISSION_DENIED プロキシが <Authentication> タグを使用して構成されている場合に、サービス アカウントに権限の問題があると、このエラーが発生します。考えられる原因:
  • サービス アカウントが存在しない。
  • サービス アカウントが Apigee 組織と同じ Google Cloud プロジェクトに作成されていない。
  • デプロイ担当者に、サービス アカウントに対する iam.serviceAccounts.actAs 権限が付与されていない。詳細については、サービス アカウントの権限についてをご覧ください。

ランタイム エラー

次の表では、ポリシーの実行時に発生する可能性のあるランタイム エラーについて説明します。

障害コード HTTP ステータス 原因
GrpcTlsInitFailed 500

gRPC サーバーで TLS を初期化に問題(キーストアやトラストストアに関する問題など)がある場合、このエラーが発生します。

steps.externalcallout.[error_code] 500

[error_code] は、障害メッセージの errorCode フィールドによって決定されます。エラーの障害文字列は、障害メッセージの faultstring フィールドになります。

steps.externalcallout.ExecutionError 500

このエラーは、このポリシーの実行中に他の例外が発生すると発生します。根本的な例外は障害文字列で公開されます。gRPC サーバーの認証情報に問題がある場合は、次のようなエラーが表示されます。


{
  "fault": {
    "faultstring": "Encountered the following exception while sending the gRPC request or
     processing the response: [io.grpc.StatusRuntimeException: UNAVAILABLE: Credentials failed
     to obtain metadata].",
    "detail": {
      "errorcode": "steps.externalcallout.ExecutionError"
    }
  }
}

詳細なデバッグ ポインタについては、MP のログを確認できます。

googletoken.EmptyIDTokenAudience 500

<GoogleIDToken> が有効になっていますが、useTargetUrl が false に設定されており、エラー時に <Audience> に直接または参照を介して値が提供されていません。

steps.externalcallout.ExecutionError

次の障害文字列を含みます。

Encountered the following exception while sending the gRPC request or processing the response: [io.grpc.StatusRuntimeException: UNAVAILABLE: Credentials failed to obtain metadata]

500

このエラーは、API プロキシが <Authentication> 要素で構成されている場合に発生します。考えられる原因:

  • プロキシを使用してデプロイされたサービス アカウントが次の状態になっている。
    • プロジェクトに存在しない(デプロイ時に存在していたが、デプロイ後に削除された)
    • 無効になっている
    • (Apigee ハイブリッドのみ)apigee-runtime サービス アカウントで roles/iam.serviceAccountTokenCreator ロールを付与していない。
  • (Apigee ハイブリッドのみ)apigee-runtime サービス アカウントのソース プロジェクトで IAMCredentials API が無効になっている。

    注: Apigee ハイブリッドの場合のみ、ランタイム コンテナのログで externalcallout.ExecutionError を検索して、問題のデバッグに役立つ詳細なエラー メッセージを見つけます。

steps.externalcallout.ExecutionError は、PERMISSION DENIED を含む障害文字列に使用されます。

たとえば、Cloud Run で障害文字列は次のようになります。

Encountered the following exception while sending the gRPC request or processing the response: [io.grpc.StatusRuntimeException: PERMISSION_DENIED: HTTP status code 403 …]

500

このエラーは、API プロキシが <Authentication> 要素で構成されている場合に発生します。考えられる原因:

  • プロキシ サービス アカウントが存在し、有効になっていますが、サービスにアクセスするための適切な権限がありません。
  • サービスには認証が必要ですが、リクエストに認証ヘッダーがありません(例: 認証 XML がポリシー XML に含まれていません)。

その他のエラー

次の表に、その他のエラーを示します。詳しくは、原因をご確認ください。

障害コード 原因
ReferencesExistToGrpcServer

このエラーは、ユーザーが gRPC ターゲット サーバーを削除しようとしたものの、そのサーバーが他のポリシーによって使用されている場合に発生します。

障害

次の表に示す障害変数は、デフォルトですべてのポリシーに対して設定されています。ポリシーエラーに固有の変数をご覧ください。

変数 場所
fault.name="fault_name" fault_name は、上記のランタイム エラーの表に記載されている障害の名前です。障害名は、障害コードの最後の部分です。 fault.name は「ExecutionError」と一致します。
externalcallout.[policy_name].failed policy_name は、障害が発生したポリシーのユーザー指定の名前です。 externalcallout.ExternalCallout-1.failed = true

関連トピック