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に指定のバケットの読み取りが行えるかの確認も走ります。アクセス情報に問題なければジョブが作成されます。
あとは、通常のジョブと同様手動で実行したりスケジュールで実行したりすることができます。