📝

S3 汎用バケットをコピーした記録

に公開

今回既存の S3 バケットのアクセス制御を OAI(オリジンアクセスアイデンティティ)から OAC(オリジンアクセスコントロール)に移行するべく、S3 のバケットをコピーする方法を調べていました。その手順を備忘録としてまとめます。

コピーする方法|概要

S3 汎用バケットの設定と中身をコピーしたいというのが今回やりたいことでしたが現時点では複数の手順を組み合わせることで実現できました。好みはありますがおそらくシンプルなやり方だと思います。

前提

AWS CLI の設定はできている前提で進めます。
既存のコピー元バケットはコンソールから作成したもの前提です。IaC 化できていればもっとシンプルになったと思いますが、今回は諸々事情があり IaC 化までは行わない方法で進めます。

手順|概要

  1. AWS コンソールから S3 バケットを作成します。この時コピー元のバケットの設定をなるべく引き継ぐべく「既存のバケットから設定をコピー」 - オプションを有効にして元のバケットを選択します。
  2. AWS CLI でオブジェクトの中身をコピーします。

今回コピーしたいS3のバケット設定を確認する|事前準備

S3 にはさまざまな設定があります。バケットを作成する前にまずは何をコピーする必要があるのかを確認します。ここでの設定は S3 を作成する際のバケットの設定です。オブジェクトの設定は次のチャプターで設定します。その中でどの設定が必要かつ、コピーすべきなのかを復習も兼ねてまとめていきます。設定項目は AWS コンソールに入った時に表示されるものでまとめていきます。

バケットのバージョニング

バケットをバージョニングするかどうかを決めます。今回はコピー元が有効だったので有効にしました。

デフォルトの暗号化

ファイルをアップロードすると S3 が自動的に暗号化をしてくれます。その時どのようなタイプの鍵を使用するかどうかをここで決めます。今回はデフォルトの設定である SSE-S3 を使用していたのでそれを使用します。
SSE-S3 は S3 が自動で管理してくれるサーバー側の暗号化です。動きとしてはサーバーにアップロードし保存前の段階で暗号化され保存されます、ダウンロードする際にサーバーで複合化されてからダウンロードされる形になります。

サーバーアクセスのログ記録

今回は元のバケットにしたがい有効にします。これは S3 バケットへのリクエストを記録するログになります。

静的 Web サイトホスティング

S3 を使って HTML サイトを表示する機能で、今回は画像を保存しているだけなので無効にします。

パブリックアクセスをすべて ブロック

今回は元のバケットが OAI で制御されておりこちらはオフになっていたがコピー時はオンで立ち上げました。オンにすることでセキュリティレベルは向上します。

ACL(アクセスコントロールリスト|バケットに設定するもの)

こちらは元のバケットが歴史的経緯から有効かつ権限も広く設定されていました。今回はベストプラクティスに従いオブジェクトの ACL は使用しない設定で進めます。

バケットポリシー

バケットポリシーもとりあえず OAI での設定をコピーします。


{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXX"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::example-bucket-name/*"
        }
    ]
}

コピー後に OAC の設定も追加してテスト OAI が不要になるタイミングまで、今回は以下のように両方の機能を使えるように設定しました。


{
    "Version":"2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipalReadOnly",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3 bucket name>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/<CloudFront distribution ID>"
                }
            }
        },
        {
            "Sid": "AllowLegacyOAIReadOnly",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3 bucket name>/*"
        }
    ]
}

OAI が不要になり OAC のみに設定する際には以下のように OAI 部分を削除します。


{
    "Version":"2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipalReadOnly",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3 bucket name>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/<CloudFront distribution ID>"
                }
            }
        }
    ]
}

ライフサイクルルール

今回は特に設定しませんでした。

上記以外の設定についてはデフォルトで進めました。「既存のバケットから設定をコピー」はすべての設定をコピーするわけではなさそうなので適宜必要な設定は確認しながら進める必要がありそうです。

バケットの新規作成

これまで確認してきた項目を実際にせっていせってい S3 のコンソールを開いて以下の通り進めてみます。

  1. 「バケットを作成ボタン」を押します。
  2. 「バケットタイプ」汎用を選択します。
  3. 「バケット名」を入力します。この名前はグローバルで一意である必要があります。つまり他の AWS ユーザーが作成したものとも一致してはいけません。
  4. 「既存のバケットから設定をコピー」を選択し、コピー元のバケット名を指定します。
  5. 「パブリックアクセスをすべてブロック」にチェックが入っていることを確認します。
  6. 「バケットのバージョニング」が有効になっていることを確認します。
  7. 「デフォルトの暗号化」が SSE-S3 になっていることを確認します。
  8. 「バケットを作成」ボタンを押します。
  9. 作成後、「アクセス許可」タブから「バケットポリシー」を編集し、上記で確認した OAI または OAC のポリシーを設定します。
  10. 「プロパティ」タブから「サーバーアクセスのログ記録」を有効化します。

AWS CLI でオブジェクトの中身をコピー

オブジェクト(ファイルの実態とパス)をコピーしていきます。
まずはコピーする項目としてどのような要素があるのかを整理します。

オブジェクト

example.jpg などのファイル自体です。ファイルには保存場所のような階層も作れますのでそちらも含めてコピーします。

ACL(オブジェクトに設定するもの)

アクセスコントロールリストにはバケットに設定するもの以外にも、オブジェクト自体に設定するものもあります。コンソールで表示する際はオブジェクトを開いた際に「アクセス許可」タブをクリックすると確認できます。

被付与者 オブジェクト オブジェクト ACL
オブジェクト所有者(AWS アカウント) 読み込み 読み取り、書き込み
全員(パブリックアクセス) - -
Authenticated Users グループ(AWS アカウントを持つすべてのユーザー) - -

※ デフォルトではオブジェクト所有者のみが権限を持ち、その他のアクセスは無効になっています。


コピーコマンド

以下のコマンドでローカルの PC など aws cli 環境が使える環境から実行をします。

【コピー時にリージョンを跨ぐ場合】


# まずはドライラン(実行せず差分だけ表示)
aws s3 sync s3://<bucket-a>/ s3://<bucket-b>/ \
  --source-region <src-region> --region <dst-region> --dryrun

# 問題なければ本番実行
aws s3 sync s3://<bucket-a>/ s3://<bucket-b>/ \
  --source-region <src-region> --region <dst-region> \
  --only-show-errors --exact-timestamps

【同じリージョンにコピーする場合】


aws s3 sync s3://bucket-a/ s3://bucket-b/ --dryrun

aws s3 sync s3://bucket-a/ s3://bucket-b/

超大規模(億〜数十億オブジェクト、何十 TB〜)であれば S3 Batch Operations を使用する必要があるとのことでした。

上記コマンドではオブジェクトの「主要メタデータ」「タグ」などコピーされない要素もあります。こちらもコピーする必要がある場は適宜調査してみてください。

料金コストについて

今回設定した内容ではおそらくよほど大規模データを扱っていない限り数円〜数百円で収まると思いますが、料金を確認する際は公式サイトをご参照の上計算してみてください。

https://aws.amazon.com/jp/s3/pricing/

参考

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html##migrate-from-oai-to-oac

Discussion