終末 A.I.

データいじりや機械学習するエンジニアのブログ

Cloud Storage Transfer ServiceでAssumeRoleを使ってS3からデータを移行する

※ この記事は2021年10月の情報に基づいて記載しています。

※ 最新情報はGCPのドキュメントを参照ください。

Cloud Storage Transfer Serviceは、GCP内から直接S3等のクラウドストレージ(もしくはオンプレミス)のデータ移行を行うことにより、高速で高並列にGCSへのデータ移行を実現できるサービスです。

一方で、データソースをS3とする場合は、AWSのアクセスキーとシークレットをGCPに設定しておく必要があり、アクセス情報の漏洩に対して、あまりセキュアではありませんでした。

それに対応できる機能が、2021年7月にパブリックプレビューとなりました。AWSのAssumeRoleWithWebIdentityを利用したフェデレーテッドアクセスにより、データの転送が行えるようになったのです。以下では、その使い方について、簡単に説明したいと思います。

GCPが管理する専用のサービスアカウント(SA)を確認する

Storage Transfer Serviceでは、GCPが管理する専用のサービスアカウントを用いてデータの転送処理を行っています。

通常のIAM一覧上では確認できず、必要な情報はサービス専用の googleServiceAccounts.get を呼び出すことで取得できます。このAPIの戻り値は以下のようになります。

{
  "accountEmail": "project-xxxxxxx@storage-transfer-service.iam.gserviceaccount.com",
  "subjectId": "xxxxxxx"
}

accountEmailは見ての通りSAを識別するための固有のメールアドレスで、xxxxの部分にはプロジェクト固有のプロジェクト識別番号が入ります。subjectIdもアカウントを識別するための固有のIDで、後でAWS上でフェデレーテッドアクセスを設定するために使用する情報になります。

AWSに専用のロールを作成する

続いて、AWS上に上記のSAがフェデレーテッドアクセスするためのロールを作成します。ロールには、GCPのSAがAssumeRoleを行うための権限と、該当のS3バケットからデータを読み出すための権限設定が必要です。

まず、フェデレーテッドアクセス用の権限ですが、対象のロールのAssumeRolePolicyに下記を設定すれば良いです。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "accounts.google.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "accounts.google.com:sub": "SAのsubjectId"
        }
      }
    }
  ]
}

設定内容の詳しい説明はAWSのドキュメントを参照していただきたいのですが、GoogleからOIDCでAssumeRoleを呼び出された場合に、アカウントのsubjectIdが指定したものについてのみ許可するという設定になります。

次にS3からデータを読み出すための権限をロールのポリシーに指定します。適宜必要に応じて追加したり削ったりしてもらえれば良いですが、簡単には下記のようになります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
          "s3:Get*",
          "s3:List*",
       ],
      "Resource": "送信元バケット"
    }
  ]
}

GCSの書き込み権限を設定する

Storage Transfer Serviceが使用するSAには、対象のGCSバケットに書き込みを行う権限も必要になります。GCSの権限設定を用いて、バケットにSAが roles/storage.legacyBucketWriter および roles/storage.objectViewer を使用してアクセスできるように設定を行います。

Storage Transfer ServiceのJobを作成する

最後に、上記で作成したロールを用いてS3にアクセスするように設定したジョブを作成します。記事を書いている時点では、Webコンソールにて設定する方法はありませんでしたので、API呼び出しで作成する方法について記載します。

ジョブの作成は、transferJobs.createを使用して行います。設定内容は以下が設定されていれば最低限問題ありません。

{
  "name": "ジョブの名称",
  "projectId": "GCPのプロジェクトのID",
  "transferSpec": {
    "awsS3DataSource": {
      "bucketName": "送信元バケット名",
      "roleArn": "作成したAWSのロールのARN"
    },
    "gcsDataSink": {
      "bucketName": "送信先バケット名"
    }
  },
  "status": "ENABLED"
}

このAPIを実行したタイミングで、AssumeRoleでフェデレーテッドアクセスができるか、ロールでS3に指定のバケットの読み取りが行えるかの確認も走ります。アクセス情報に問題なければジョブが作成されます。

あとは、通常のジョブと同様手動で実行したりスケジュールで実行したりすることができます。