AWS からリソースにアクセスする

このドキュメントでは、ID 連携を使用して Amazon Web Services(AWS)から Google Cloud リソースにアクセスする方法について説明します。

従来、Google Cloud の外部で実行されているアプリケーションは、サービス アカウント キーを使用して Google Cloud リソースにアクセスしていました。ID 連携を使用すると、AWS のユーザーまたはロールでサービス アカウントになり代わることができます。これにより、ワークロードは短期間だけ有効なアクセス トークンを使用して Google Cloud リソースに直接アクセスでき、サービス アカウント キーに関連するメンテナンスとセキュリティの負担が軽減されます。

始める前に

  1. Workload Identity プール管理者ロール(roles/iam.workloadIdentityPoolAdmin)があることを確認します。

    IAM の基本ロールであるオーナー(roles/owner)と編集者(roles/editor)のロールでも、ID 連携を構成する権限が付与されます。それでも、Workload Identity プール管理者ロールを使用して、Google Cloud リソースへの不要なアクセス権の付与を避けることをおすすめします。

  2. AWS ロールを作成し、Amazon Resource Name(ARN)をメモします。

  3. Google Cloud サービス アカウントを作成します。

  4. サービス アカウントにアクセス権を付与して、ワークロードに必要な Google Cloud APIs を呼び出します。

Workload Identity プールの作成

Workload Identity プールは、外部 ID のコレクション用のコンテナです。Workload Identity プールは相互に分離されていますが、1 つのプールは任意の数のサービス アカウントになり代わることができます。一般に、開発、ステージング、本番環境など、環境ごとに新しいプールを作成することをおすすめします。つまり、通常は AWS アカウントごとに 1 つのプールとなります。

新しい Workload Identity プールを作成するには、ID を指定する必要があります。オプションの説明と表示名を指定することもできます。

gcloud コマンド

gcloud beta iam workload-identity-pools create コマンドを実行して Workload Identity プールを作成します。

gcloud beta iam workload-identity-pools create pool-id \
    --location="global" \
    --description="description" \
    --display-name="display-name"

REST API

projects.locations.workloadIdentityPools.create メソッドにより、Workload Identity プールが作成されます。

HTTP メソッドと URL:

POST https://iam.googleapis.com/v1beta/projects/project-id/locations/global/workloadIdentityPools?workloadIdentityPoolId=pool-id

JSON 本文のリクエスト:

{
  "description": "description",
  "display-name": "display-name"
}

リクエストを送信するには、次のいずれかのオプションを展開します。

 

ID プロバイダとして AWS を追加する

AWS を Workload Identity プールの ID プロバイダとして構成するには、少なくとも次の情報を指定します。

  • プロバイダの ID。

  • このドキュメントの前のセクションの Workload Identity プール ID。

  • AWS アカウント ID

次の複数のオプション パラメータを指定することもできます。

  • 表示名と説明。

  • AWS トークンの属性を Google トークンの属性にマッピングする属性マッピングのリスト。デフォルトでは、各プールは次の属性マッピングを使用します。これらは最も一般的なシナリオに対応しています。

    Google AWS 説明
    google.subject assertion.arn プリンシパル IAM が認証されています。これは、Cloud Logging ログエントリに表示される件名でもあります。このマッピングには、自動的に arn:aws:sts::[ACCOUNT-ID]:assumed-role/[AWS-ROLE]/[AWS-SESSION-NAME] の形式で ARN が入力されます。
    attribute.aws_role AWS のロール AWS のロールです。arn:aws:sts::[ACCOUNT-ID]:assumed-role/[AWS-ROLE] の形式を使用します。

    IAM バインディングで参照できるカスタム マッピングを指定することもできます。assertion を使用して AWS 認証情報を参照します。Google 属性の場合は google、カスタム属性の場合は attribute を使用します。たとえば、次の例では、google.subject のデフォルトのマッピングに加えて、attribute.aws_accountassertion.account にマッピングされています。

    google.subject=assertion.arn,
    attribute.aws_account=assertion.account
    

    参照できる AWS トークンの属性のリストについては、GetCallerIdentity() のドキュメントをご覧ください。AWS のドキュメントでは、属性にキャメルケースが使用されるのに対して、属性のマッピングには小文字が使用されます。たとえば、Accountassertion.account になります。

    より複雑なアサーションの場合は、Common Expression Language を使用できます。例:

    attribute.environment=assertion.arn.contains(":instance-profile/Production") ? "prod" : "test"
    

    式で使用されている属性の特定の部分を参照するには、CEL の extract() 関数を使用します。この関数は、指定したテンプレートに基づいて属性から値を抽出します。extract() の詳細については、リソース名からの値の抽出をご覧ください。

    認証情報に属性が含まれているかどうかを確認するには、has() 関数を使用します。

  • プリンシパルが提示する必要がある属性を指定する属性条件。この条件は、外部の認証情報と Google の認証情報に適用できます。条件を満たしていないリクエストは拒否されます。

    属性条件は、ブール値を返す CEL 式の形式になります。たとえば下記では、特定の AWS ロールを持たない ID からのリクエストは拒否されます。

    attribute.aws_role == "role-mapping"
    

    属性条件の一般的なユースケースの詳細については、Workload Identity 連携の概要をご覧ください。

次の例では、AWS を ID プロバイダとして追加する方法を説明します。

gcloud コマンド

gcloud beta iam workload-identity-pools providers create-aws コマンドを実行して AWS を ID プロバイダとして追加します。

gcloud beta iam workload-identity-pools providers create-aws provider-id \
  --workload-identity-pool="pool-id"
  --account-id="aws-account-id"
  --location="global"

REST API

projects.locations.workloadIdentityPools.providers.create メソッドにより、AWS がプロバイダとして追加されます。

HTTP メソッドと URL:

POST https://iam.googleapis.com/v1beta/projects/project-id/locations/global/workloadIdentityPools/pool-id/providers?workloadIdentityPoolProviderId=provider-id

JSON 本文のリクエスト:

{
  "aws": {
    "accountId": "aws-account-id"
  }
}

リクエストを送信するには、次のいずれかのオプションを展開します。

 

サービス アカウントになり代わる

Workload Identity プールとプロバイダから連携された ID に、IAM を使用してリソースのロールを付与できます。Workload Identity ユーザーのロール(roles/iam.workloadIdentityUser)により、サービス アカウントになり代わる権限が付与されます。これにより、外部 ID で Google Cloud リソースにアクセスできるようになります。

代わりに、Workload Identity プール内の個々の ID にロールを付与するか、組織のドメイン制限を無効にします。

AWS ロール用にこのバインディングを追加するには、次の形式を使用します。

attribute.aws_role/arn:aws:sts::aws-account-id:assumed-role/aws-role-name

例:

gcloud iam service-accounts add-iam-policy-binding service-account-email \
  --role roles/iam.workloadIdentityUser \
  --member "principalSet://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/attribute.aws_role/arn:aws:sts::aws-account-id:assumed-role/aws-role-name"

AWS ユーザー用にこのバインディングを追加するには、次の形式を使用します。

subject/arn:aws:sts::aws-account-id:assumed-role/aws-role-name/aws-session-name

AWS ARN から AWS ロール セッションを抽出する方法については、IAM 識別子の AWS ドキュメントをご覧ください。

次の例では、AWS ユーザー用にバインディングを追加する方法を示しています。

gcloud iam service-accounts add-iam-policy-binding service-account-email \
  --role roles/iam.workloadIdentityUser \
  --member "principal://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/subject/arn:aws:sts::aws-account-id:assumed-role/aws-role-name/aws-session-name

カスタム属性に基づいてアクセス権を付与することもできます。例:

gcloud iam service-accounts add-iam-policy-binding service-account-email \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/attribute.custom-attribute/arn:aws:sts::aws-account-id:aws-role-name"

アクセス権を取り消すには、add-iam-policy-bindingremove-iam-policy-binding に置き換えます。

REST API またはクライアント ライブラリを使用して、バインディングの追加または削除を行うこともできます。詳細については、リソースへのアクセス権の付与、変更、取り消しをご覧ください。

AWS トークンを Google トークンと交換する

AWS のロールまたはユーザーでサービス アカウントになり代わることができる状態であれば、AWS 認証情報を Google 認証情報と交換できます。交換プロセスの一部として、AWS の GetCallerIdentity() メソッドに対するシリアル化されたバージョンのリクエストをセキュリティ トークン サービスに渡します。これにより、Google Cloud は AWS プリンシパルの ID を検証し、サービス アカウントになり代わる権限があることを確認できます。

認証情報を交換するには、次のようにします。

  1. 一時的な AWS 認証情報を取得します

  2. バージョン 4 の署名を使用して、AWS の GetCallerIdentity() メソッドに対するシリアル化された署名付きリクエストを作成します。

    リクエストには次のフィールドが含まれます。

    • url: GetCallerIdentity() の AWS STS エンドポイントの URL(https://sts.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15 など)。リージョン エンドポイントもサポートされます。
    • method: HTTP リクエスト メソッド: POST
    • headers: HTTP リクエスト ヘッダー。次の情報を含める必要があります。
      • Authorization: リクエストの署名。
      • host: url フィールドのホスト名。たとえば、sts.amazonaws.com です。
      • x-amz-date: リクエストを送信する時刻。ISO 8601 の基本文字列の形式になります。これは通常、現在の時刻に設定され、リプレイ攻撃の防止に使用されます。
      • x-goog-cloud-target-resource: ID プロバイダの完全なリソース名。HTTPS 接頭辞は省略可能です。たとえば、次の 2 つはいずれも有効です。
        //iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id
        https://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id
        

    リクエストは次のようになります。

    {
      "url": "https://sts.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
      "method": "POST",
      "headers": [
        {
          "key": "Authorization",
          "value" : "AWS4-HMAC-SHA256 Credential=AKIASOZTBDV4D7ABCDEDF/20200228/us-east-1/sts/aws4_request, SignedHeaders=host;x-amz-date,Signature=abcedefdfedfd"
        },
        {
          "key": "host",
          "value": "sts.amazonaws.com"
        },
        {
          "key": "x-amz-date",
          "value": "20200228T225005Z"
        },
        {
          "key": "x-goog-cloud-target-resource",
          "value": "//iam.googleapis.com/projects/12345678/locations/global/workloadIdentityPools/my-pool/providers/my-aws-provider"
        }
      ]
    }
    
  3. シリアル化されたリクエストをセキュリティ トークン サービス token() メソッドに渡して、AWS 認証情報を連携アクセス トークンと交換します。

    REST API

    token メソッドにより、サードパーティ トークンが Google トークンに交換されます。

    後述のリクエストのデータを使用する前に、次のように置き換えます。

    • project-id: Google Cloud プロジェクト ID
    • pool-id: このチュートリアルで前に作成した Workload Identity プールの ID。
    • provider-id: このチュートリアルで前に構成した AWS ID プロバイダの ID。
    • aws-request: GetCallerIdentity() に対するシリアル化された署名付きリクエスト。URL の生成から除外された JSON 形式になります。

    HTTP メソッドと URL:

    POST https://sts.googleapis.com/v1beta/token

    JSON 本文のリクエスト:

    {
      "audience": "https://iam.googleapis.com/projects/project-id/locations/global/workloadIdentityPools/pool-id/providers/provider-id",
      "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
      "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
      "scope": "https://www.googleapis.com/auth/cloud-platform",
      "subject_token_type": "urn:ietf:params:aws:token-type:aws4_request",
      "subject_token": "aws-request"
    }
    

    リクエストを送信するには、次のいずれかのオプションを展開します。

     

    このメソッドは連携トークンを返します。

  4. generateAccessToken() を呼び出して、連携トークンを OAuth 2.0 アクセス トークンと交換します。

    REST API

    curl -X POST -H "Authorization: Bearer federated-token \
      https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/service-account-email:generateAccessToken
    

サービス アカウントのアクセス トークンを取得したら、リクエストの Authorization ヘッダーにトークンを含めることで、Google Cloud APIs の呼び出しに使用できます。

Authorization: Bearer access-token

リクエストはサービス アカウントとして承認されます。

次のステップ