Google Cloud の Storage Transfer Serviceを使ってS3→GCSへデータ転送

## これは一体…？

GCのStorage Transfer Serviceを使ってS3→GCSへデータ転送し、送信後はデータを送信元(S3)から削除する、までをやってみました。メモとして残します。

なお、今回VPC service controlsは使っていません。
[GC公式の手順](https://cloud.google.com/architecture/transferring-data-from-amazon-s3-to-cloud-storage-using-vpc-service-controls-and-storage-transfer-service)では、これを使用する方法が載っており、おそらくこの方がセキュアなんだろうと思いますが…

デフォルトでHTTPS使っている(以下参照)し、大丈夫だろうということでやってみました。

```
Storage Transfer Service では、デフォルトで次の処理を行います。
・ファイルがデータシンク内に存在しない場合、またはデータソースとデータシンクの間でファイルのバージョンが異なる場合は、
Storage Transfer Service はデータソースからファイルをコピーする。
・転送オペレーション後にソース内のファイルを保持する。
・HTTPs 接続に TLS 暗号化を使用する。唯一の例外は、URL リストの転送に HTTP URL を指定した場合です。
```
https://cloud.google.com/storage-transfer/docs/overview

VPC service controlsを使うと得られるメリットは、今のところ以下だと考えています。
そもそもVPC service controlsは、仮想的なセキュリティの境界を定義して、GCへの各種リソースのアクセスを制限するものです。

・承認を受けたネットワーク以外は機密データに[アクセスできない](https://cloud.google.com/vpc-service-controls)ようにする
→特定のIPからのみBQやGCSへアクセスを許可させる、など

・BQやGCSのデータのコピー先、持ち出し先を、特定のGCプロジェクトに制限する。


この辺は機会があれば、今度まとめてみたいと思います。

## 前提

今回は検証、やってみた的なメモなので、本番環境などでは、念のためVPC service controls使用を考えた方がいいかなと思います。


## やってみた

**Access Context Manager, Cloud Storage, and Storage Transfer Service API を有効になっていることを確認**

**[IAM と管理] で、ストレージ管理者のロールと Access Context Manager 管理者のロールをアカウントに付与する**
VPC service controls使わないのであれば、Access Context Manager 管理者のロールは必要ないと思います。

**Storage Transfer Service 用の AWS IAM ポリシーを作成してバケットに適用する**
[公式手順](https://cloud.google.com/architecture/transferring-data-from-amazon-s3-to-cloud-storage-using-vpc-service-controls-and-storage-transfer-service#create_an_aws_iam_policy_for_storage_transfer_service_and_apply_it_to_your_bucket)

ただ、これだとなぜかできなかったので、画面下の方にあるポリシーに変えました。

**AWS IAM ユーザーを AWS IAM ポリシーに追加する**
[公式手順](https://cloud.google.com/architecture/transferring-data-from-amazon-s3-to-cloud-storage-using-vpc-service-controls-and-storage-transfer-service#add_aws_iam_users_to_your_aws_iam_policy)

**Cloud Storage バケットを作成する**
[公式手順](https://cloud.google.com/architecture/transferring-data-from-amazon-s3-to-cloud-storage-using-vpc-service-controls-and-storage-transfer-service#creating_a_cloud_storage_bucket)

**IAMポリシー**
[公式参考](https://cloud.google.com/architecture/transferring-data-from-amazon-s3-to-cloud-storage-using-vpc-service-controls-and-storage-transfer-service#create_an_aws_iam_policy_for_storage_transfer_service_and_apply_it_to_your_bucket)

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ここは任意",
            "Effect": "Allow",
            "Action": [
                "s3:PutAnalyticsConfiguration",
                "s3:PutAccessPointConfigurationForObjectLambda",
                "s3:GetObjectVersionTagging",
                "s3:DeleteAccessPoint",
                "s3:CreateBucket",
                "s3:DeleteAccessPointForObjectLambda",
                "s3:GetStorageLensConfigurationTagging",
                "s3:ReplicateObject",
                "s3:GetObjectAcl",
                "s3:GetBucketObjectLockConfiguration",
                "s3:DeleteBucketWebsite",
                "s3:GetIntelligentTieringConfiguration",
                "s3:PutLifecycleConfiguration",
                "s3:GetObjectVersionAcl",
                "s3:DeleteObject",
                "s3:CreateMultiRegionAccessPoint",
                "s3:GetBucketPolicyStatus",
                "s3:GetObjectRetention",
                "s3:GetBucketWebsite",
                "s3:GetJobTagging",
                "s3:GetMultiRegionAccessPoint",
                "s3:PutReplicationConfiguration",
                "s3:PutObjectLegalHold",
                "s3:GetObjectLegalHold",
                "s3:GetBucketNotification",
                "s3:PutBucketCORS",
                "s3:DescribeMultiRegionAccessPointOperation",
                "s3:GetReplicationConfiguration",
                "s3:ListMultipartUploadParts",
                "s3:PutObject",
                "s3:GetObject",
                "s3:PutBucketNotification",
                "s3:DescribeJob",
                "s3:PutBucketLogging",
                "s3:GetAnalyticsConfiguration",
                "s3:PutBucketObjectLockConfiguration",
                "s3:GetObjectVersionForReplication",
                "s3:GetAccessPointForObjectLambda",
                "s3:GetStorageLensDashboard",
                "s3:CreateAccessPoint",
                "s3:GetLifecycleConfiguration",
                "s3:GetInventoryConfiguration",
                "s3:GetBucketTagging",
                "s3:PutAccelerateConfiguration",
                "s3:GetAccessPointPolicyForObjectLambda",
                "s3:DeleteObjectVersion",
                "s3:GetBucketLogging",
                "s3:ListBucketVersions",
                "s3:RestoreObject",
                "s3:ListBucket",
                "s3:GetAccelerateConfiguration",
                "s3:GetBucketPolicy",
                "s3:PutEncryptionConfiguration",
                "s3:GetEncryptionConfiguration",
                "s3:GetObjectVersionTorrent",
                "s3:AbortMultipartUpload",
                "s3:GetBucketRequestPayment",
                "s3:DeleteBucketOwnershipControls",
                "s3:GetAccessPointPolicyStatus",
                "s3:UpdateJobPriority",
                "s3:GetObjectTagging",
                "s3:GetMetricsConfiguration",
                "s3:GetBucketOwnershipControls",
                "s3:DeleteBucket",
                "s3:PutBucketVersioning",
                "s3:GetBucketPublicAccessBlock",
                "s3:GetMultiRegionAccessPointPolicyStatus",
                "s3:ListBucketMultipartUploads",
                "s3:PutIntelligentTieringConfiguration",
                "s3:GetMultiRegionAccessPointPolicy",
                "s3:GetAccessPointPolicyStatusForObjectLambda",
                "s3:PutMetricsConfiguration",
                "s3:PutBucketOwnershipControls",
                "s3:DeleteMultiRegionAccessPoint",
                "s3:UpdateJobStatus",
                "s3:GetBucketVersioning",
                "s3:GetBucketAcl",
                "s3:GetAccessPointConfigurationForObjectLambda",
                "s3:PutInventoryConfiguration",
                "s3:GetObjectTorrent",
                "s3:GetStorageLensConfiguration",
                "s3:DeleteStorageLensConfiguration",
                "s3:PutBucketWebsite",
                "s3:PutBucketRequestPayment",
                "s3:PutObjectRetention",
                "s3:CreateAccessPointForObjectLambda",
                "s3:GetBucketCORS",
                "s3:GetBucketLocation",
                "s3:GetAccessPointPolicy",
                "s3:ReplicateDelete",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::S3バケットの名前"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:ListStorageLensConfigurations",
                "s3:ListAccessPointsForObjectLambda",
                "s3:GetAccessPoint",
                "s3:GetAccountPublicAccessBlock",
                "s3:ListAllMyBuckets",
                "s3:ListAccessPoints",
                "s3:ListJobs",
                "s3:PutStorageLensConfiguration",
                "s3:ListMultiRegionAccessPoints",
                "s3:CreateJob"
            ],
            "Resource": "arn:aws:s3:::S3バケットの名前/*"
        }
    ]
}
```

ただ、これだと、なぜか送信できなかったので、ググって以下のポリシーを参考にさせていただきました。

**IAMポリシー**
[参考](https://note.com/ucwork/n/n5fe04382409b)

```
{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Effect": "Allow",
           "Action": [
               "s3:ListBucket",
               "s3:GetBucketLocation"
           ],
           "Resource": "arn:aws:s3:::S3バケットの名前"
       },
       {
           "Effect": "Allow",
           "Action": [
               "s3:GetObject"
           ],
           "Resource": "arn:aws:s3:::S3バケットの名前/*"
       }
   ]
}
```

ただ、こちらだと、ソース元が削除できないエラーが発生したので、最終的に以下にしました。

**IAMポリシー**

```
/// DeleteObjectを追加

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation"
            ],
            "Resource": "arn:aws:s3:::S3バケットの名前"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::S3バケットの名前/*"
        }
    ]
}
```

[ここ](https://cloud.google.com/storage-transfer/docs/iam-transfer#source-permissions)に書いてありました。

**転送を開始**

[公式手順](https://cloud.google.com/architecture/transferring-data-from-amazon-s3-to-cloud-storage-using-vpc-service-controls-and-storage-transfer-service#initiating_the_transfer)

いざ転送！
なんですが、ファイルパス指定が最初よくわかりませんでした。

```
/ 例
Source
S3
path:2021/01/

Destination
Google Cloud Storage
path:logs/2021/01

の場合、GCSに届く時のファイルパスは、gcs-bucket/logs/2021/01/2021/01
になります。
→つまり、GCSのpath指定は、S3のファイル指定まで含める必要はないということを学びました。（二重になる）
```

**転送成功**

![スクリーンショット 2021-10-07 15.29.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/bcae5db7-e6e3-75ef-2e15-2d595fb3b2f3.png)

![スクリーンショット 2021-10-07 17.31.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/11bf7fed-2a69-75d1-5f74-9ef834482563.png)

送信元からも削除されています。

![スクリーンショット 2021-10-07 17.31.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/af80c354-cef4-8ff4-902c-b98be9c1a94f.png)


## 参考

```
https://cloud.google.com/architecture/transferring-data-from-amazon-s3-to-cloud-storage-using-vpc-service-controls-and-storage-transfer-service
https://cloud.google.com/vpc-service-controls
https://medium.com/google-cloud/designing-secure-data-pipelines-with-vpc-service-controls-e3b4502307df
https://note.com/ucwork/n/n5fe04382409b
https://cloud.google.com/storage-transfer/docs/iam-transfer#source-permissions
```

参考にさせていただきました。ありがとうございます。