S3初心者向け『例 4: バケット所有者が自分が所有しないオブジェクトへのクロスアカウントアクセス許可を付与』をやってみた

2019.09.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

概要

大阪オフィスのちゃだいんです。

手を動かして学ぶために、公式ドキュメントのチュートリアルをやってみました。

Amazon S3のアクセス管理チュートリアル 最終回です。前回の続編で、内容は以下のものです。

例 4: バケット所有者が自分が所有しないオブジェクトへのクロスアカウントアクセス許可を付与 - Amazon Simple Storage Service

今回のシナリオでは、「アカウントAのバケットに、アカウントBのオブジェクトをアップロードして、そのオブジェクトへアカウントCのアクセスを許可する」という、アカウントが3つ登場するものです。

前提条件

AWS CLIが使用できる環境で行ってます。

また、2つのアカウントはドキュメントと同様に以下のように記載します。

AWSアカウントID アカウントの呼び方 アカウントの管理者ユーザー
1111-1111-1111 アカウント A AccountAadmin
2222-2222-2222 アカウント B AccountBadmin
3333-3333-3333 アカウント C AccountCadmin

早速やってみた

1.(アカウントA作業)S3バケットを作成し、バケットポリシーを設定する

  • アカウントAにて、S3バケット190910testbucketを作成します。

  • バケットポリシーはドキュメントのものを少し変更しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "111",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::222222222222:user/TestAdminB"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::190910testbucket/*"
        },
        {
            "Sid": "112",
            "Effect": "Deny",
            "Principal": {
                "AWS": "arn:aws:iam::222222222222:user/TestAdminB"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::190910testbucket/*",
            "Condition": {
                "StringNotEquals": {
                    "s3:x-amz-grant-full-control": "id=********************************************"
                }
            }
        }
    ]
}

※ id=*******...の部分はダミーですが、実際はアカウントAの正規ユーザーIDをS3バケットから取得しています。

  • コンソールで見るとこんな感じです。

2.(アカウントA作業)IAMポリシーを作成し、IAMロールに割り当てる

  • アカウントCに使ってもらうためのIAMロールを、アカウントAにて作成します。

  • IAMロールに割り当てるIAMポリシーをまず作成します。

  • ドキュメントのポリシーのバケット名のみ以下変更してます。

  • ポリシーの名前はTestPolicyForCとして保存します。

  • 次に、IAMロールを作成します。

  • ドキュメントから少しマネコンが変更になっていますが、Trusted entityのタイプはAnother AWS accountを選びます。

※ AccountIDでは、アカウントCのIDを入れています。

  • 次に、先ほど作成したTestPolicyForCのポリシーをアタッチします。

  • IAMロールの名前をTestRoleForCとし、Trusted entities がアカウントCになっていることを確認して、作成します。

  • IAMロールはできました。これでアカウントA側の作業は終了です。

3.(アカウントB作業)オブジェクトをバケットにアップロードする

  • 次はアカウントBの作業です。バケットポリシーにてアカウントBによるオペレーションが許可されているので、オブジェクトを実際にアップロードします。
$ aws s3api put-object --bucket 190910testbucket \
--key CheapGoodCurry.jpg --body ~/desktop/CheapGoodCurry.jpg \
--grant-full-control id="*************************************************************" \
--profile TestAdminB

※ id=*******...の部分はダミーですが、実際はアカウントAの正規ユーザーIDをS3バケットから取得しています。

  • どうやらアップロードできたようです。

【コラム】今回のバケットポリシーの特徴

ちなみに少し遡りますが、今回のバケットポリシーは少し厳格なルールにしてあります。というのも、後半にDenyのポリシーを入れているためです。

ものすごくカジュアルに今回のバケットポリシーをいうと、 222222222222アカウントのTestAdminBは、190910testbucketに対して、s3:PutObjectしてもOKよ。ただし、その時にバケット所有者である私(アカウントA)にそのオブジェクトに対してのフルコントロールの権限も同時にくれないとNGよ。」 というものです。

バケットポリシーのAllowが前半、Denyが後半となります。

この後半を入れた理由はなぜでしょうか?

理由は、これを入れておかないと、アカウントBから画像のアップロードができても、アカウントAやアカウントCが何もできない為です。

なので、バケットポリシーにて「オブジェクトに対するフルコントロール権を同時に与えてくれないオブジェクトのアップロード」は拒否するようにしている訳です。なるほど。

4.(アカウントC作業)IAMユーザーを作成し、ポリシーを割り当てる

  • それではアカウントCの作業に入ります。

  • いつも通り、まずなんの権限も持たないIAMユーザーTestUserCを作成します。

  • それからインラインポリシーにて、ドキュメントのポリシーを少し変更した以下を登録します。
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["sts:AssumeRole"],
      "Resource": "arn:aws:iam::111111111111:role/TestRoleForC"
    }
  ]
}

5.(アカウントC作業)一時的な認証情報を発行する

  • まず、先ほど作成したTestUserCのCredencialsを記入しておきます。
[profile TestUserC]
aws_access_key_id = TestUserCAccessKeyID
aws_secret_access_key = TestUserCSecretAccessKey
  • 次に、AWS CLI assume-roleコマンドを実行して、一時的な認証情報を発行します。
$ aws sts assume-role --role-arn arn:aws:iam::111111111111:role/TestRoleForC \
--profile TestUserC --role-session-name test

{
    "AssumedRoleUser": {
        "AssumedRoleId": "AROA2UJCVL7Q46H472X7R:test",
        "Arn": "arn:aws:sts::111111111111:assumed-role/TestRoleForC/test"
    },
    "Credentials": {
        "SecretAccessKey": "***********************************",
        "SessionToken": "************************************************************************************************************************************************************************************************************************************************************************",
        "Expiration": "2019-09-10T11:30:04Z",
        "AccessKeyId": "************************"
    }
}

※ ******の箇所は全てダミーです。実際は文字列が入っています。

  • 上記の通り、一時的な認証情報が発行されました。こちらをcredentialsに記入します。
[profile TempCred]
aws_access_key_id = temp-access-key-ID
aws_secret_access_key = temp-secret-access-key
aws_session_token = session-token

6.(アカウントC作業)オブジェクトを取得する

  • これがラストです。アカウントAのバケットに保存されたアカウントBの画像を、アカウントCが取得します。

  • ドキュメントのコマンドを修正し以下の通りに実行してみました。

$ aws s3api get-object --bucket 190910testbucket --key CheapGoodCurry.jpg SaveFileAs.jpg --profile TestTempCred
{
    "AcceptRanges": "bytes",
    "ContentType": "binary/octet-stream",
    "LastModified": "Tue, 10 Sep 2019 10:15:02 GMT",
    "ContentLength": 1436514,
    "ETag": "\"a45be69192b1e5aaad0a4d18ed8ed14b\"",
    "Metadata": {}
}
  • いけました。ちなみに許可されていないアクションもやってみます。
$ aws s3api get-object-acl --bucket 190910testbucket --key CheapGoodCurry.jpg --profile TestTempCred

An error occurred (AccessDenied) when calling the GetObjectAcl operation: Access Denied
  • それは許さんと言われました。以上で終了です。

  • ちなみにCheapGoodCurry.jpgとは、以下の画像でした。(肥後橋の某人気立ち飲み屋さんが、昼間にランチでやっている安くて美味しいカレーです)

ハマったところ

ちなみにハマったポイントとして、

バケットポリシーの "s3:x-amz-grant-full-control": "id=********************************************" 部分を作成する際に、コピペを誤って "s3:x-amz-grant-full-control": "********************************************"id=がない) という状態にしていた為、アカウントBから画像がアップロードできない問題に悩まされました。 ケアレスミスすぎる...

感想

とはいえ、アカウント3つ巴の運用で、さらにIAMロールによって別アカウントからのオペレーションを許可する方法がわかりました。途中でちらっと説明した今回のバケットポリシーのDenyの設定も、実運用の場では必須と言えそうです。

これにてS3公式ドキュメントのアクセス管理4つのチュートリアルを終えました。 おかげさまで、すこーしS3のアクセスポリシーのことが理解できた気がします。

しかし、まだまだ先は長い、深い。言葉にならないくらい。ですので、精進します。

誰かのお役に立てば幸いです。それではまた、大阪オフィスのちゃだいんでした。