業界・業務から探す
導入目的・課題から探す
データ・AIについて学ぶ
News
Hakkyについて
ウェビナーコラム
◆トップ【Hakkyの社内Wiki】Strapi
クラウドとオンプレの違いAIシステム導入時におすすめのクラウドシステムスクレイピングのためのプロキシサーバのAPI
TerraformでGCPからAWSのリソースにアクセスするGoogle Cloudとは?
AI

執筆者:Handbook編集部

AssumeRoleWithWebIdentityを使用してCloudFunctionからAWSのリソースにアクセスする

はじめに

この記事ではAssumeRoleWithWebIdentityを使用してCloudFunctionからAWSのリソースにアクセスする方法を解説します。

外部のサービスからAWSのリソースにアクセスするうえでもっとも簡単な方法は、IAMユーザーのアクセスキーを発行することだと思います。 しかし、キーが漏洩したことによる多額の利用請求や情報漏洩などのリスクを考えると、AWSの公式が推奨している通りIAMロールを使用するほうが賢明といえます。

AssumePolicyやIAMについてはこちらの記事で紹介しています。

全体像の解説

まず、OIDCプロバイダーに自身が何者かという証明をしてもらう必要があります。

これらのアイデンティティ情報が含まれたJWTをID Tokenと言います。

ID TOKENを取得する方法はこちらの記事でも紹介されているようにいくつかありますが、今回はCloudFunction上で動作させるためメタデータサーバーから取得する方法を採用します。 GCPのサービスによっては対応していないものもあるためご注意ください。

ID Tokenを取得し、AWS STSにAssumeRoleWithWebIdentityを使用してroleのassumeを依頼します。

AssumeRoleWithWebIdentityを使用することで、外部のサービスからでもAWSのサービスにアクセスすることが可能になります。

AWS STSは署名が本物かを確かめるためにFederatedの情報をもとにOIDCプロバイダーに問い合わせて(今回はaccounts.google.com)、公開鍵を取得し検証を行います。本物であることが明らかになればID Tokenの内容を信頼し、情報をもとにAssumeRolePolicyをもとに条件に当てはまっていれば、一時的なアクセスキーを発行します。

AWSでIAMを定義する。

resource "aws_iam_role" "role" {
  name = "GoogleWebIdentifyAssumePolicy"

  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            #基本的にDenyかAllowを指定する。
            "Effect": "Allow",
            #Idpの指定
            "Principal": {"Federated": "accounts.google.com"},
            "Action": "sts:AssumeRoleWithWebIdentity",
            #ロールをAssumeすることのできる条件を定義
            "Condition": {
                "StringEquals": {
                    "accounts.google.com:aud": "<azp-value>",
                    "accounts.google.com:oaud": "<aud-value>",
                    "accounts.google.com:sub": "<sub-value>"
                }
            }
        }
    ]
}
EOF
}

#IAM自身のポリシーを定義
resource "aws_iam_policy" "dynamodb_read_policy" {
  name        = "DynamoDBReadPolicy"
  description = "Allows read access to DynamoDB tables"

  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Action = [
          "dynamodb:DescribeTable",
          "dynamodb:GetItem",
          "dynamodb:BatchGetItem",
          "dynamodb:Query",
          "dynamodb:Scan"
        ],
        Resource = "*"
      }
    ]
  })
}

#ロールにポリシーを付与する。
resource "aws_iam_role_policy_attachment" "default" {
  role       = aws_iam_role.role.name
  policy_arn = aws_iam_policy.dynamodb_read_policy.arn
}

<placeholder values>の値をGoogle ID Tokenからの値で置き換えてください。

  • accounts.google.com
    Google ID tokenのaud (AUDIENCE) フィールド
  • accounts.google.com
    ID tokenの aud azp (AUTHORIZED_PARTY) フィールド
  • accounts.google.com
    ID tokenの sub sub (SUBJECT) フィールド

メタデータをサーバーから取得する方法は以下の通りです。

request = google.auth.transport.requests.Request()
credentials = compute_engine.IDTokenCredentials(
    request=request,
    #audの指定
    target_audience="XXXXXXXXX",
    use_metadata_identity_endpoint=True,
)
credentials.refresh(request)
# ID TOKENをhttps://jwt.io/などでデコードする
print(credentials.token)

Cloud FunctionからAWSにアクセスする。

CloudFunctionでAWSにアクセスする手順は以下の通りです。

  • ID TOKENをGCPのメタデータサーバーから取得
  • boto3を使用してAssume role をAWSのSTSにリクエスト
  • 一時的に権限が付与されたキーを使用してboto3で操作を実行

Pythonで書くと以下のようになります。

import os

import boto3
import google.auth.transport.requests
from google.auth import compute_engine
from google.cloud import bigquery

TABLE_ID = os.environ.get("TABLE_ID")
PROJECT_ID = os.environ.get("PROJECT_ID")
POLICY_ARN = "arn:aws:iam::XXXXXX:policy/DynamoDBReadPolicy"
ROLE_ARN = "arn:aws:iam::XXXXXXX:role/GoogleWebIdentifyAssumePolicy"


def main(data, context):
    # ID TOKEN の取得
    request = google.auth.transport.requests.Request()
    credentials = compute_engine.IDTokenCredentials(
        request=request,
        #audの指定
        target_audience="XXXXXXXXX",
        use_metadata_identity_endpoint=True,
    )
    credentials.refresh(request)

    # AssumeRoleWithWebIdentityを使用して、ロールをassumeする。
    client = boto3.client("sts")
    response = client.assume_role_with_web_identity(
        RoleArn=ROLE_ARN,
        # CLIでの実行を誰が行ったか識別するため
        RoleSessionName="get_data_from_dynamodb",
        WebIdentityToken=credentials.token,
    )
    aws_access_key_id = response["Credentials"]["AccessKeyId"]
    aws_secret_access_key = response["Credentials"]["SecretAccessKey"]
    aws_session_token = response["Credentials"]["SessionToken"]

    # 操作の実行
    client = boto3.client(
        "dynamodb",
        aws_secret_access_key=aws_secret_access_key,
        aws_access_key_id=aws_access_key_id,
        aws_session_token=aws_session_token,
        region_name="ap-northeast-1",
    )
    response = client.scan(TableName="TABLE_NAME")

まとめ

AssumeRoleWithWebIdentityを活用することで、比較的簡単に外部のサービスからAWSのリソースにアクセスすることができるようになります。

また、サービスアカウントキーの管理やセキュリティー上のリスクから解放されるため非常に有用です。 ぜひとも使ってみてください。

参考

info
備考

Hakky ではエンジニアを募集中です!まずは話してみたいなどでも構いませんので、ぜひお気軽に採用ページからお問い合わせくださいませ。

2025年06月15日に最終更新
読み込み中...