概要

別の AWS アカウントにある S3 へアクセスする方法を解説しています。
説明のためここからはアクセス元のアカウントをアカウントA、アクセス先のをアカウントBとします。

アクセス許可を設定するためには、まずアカウントBで IAM ロールを作成します。
そして、その作成したロールを使うことができるようにアカウントAでポリシーの設定を行います。

最後に、例としてそのロールを ServerlessFramework の serverless.ymlで使用する方法を書いています。

ポリシーを作成する

まずはアカウントBの方でポリシーを作成します。

ブラウザで IAM のコンソールを開いて、左のメニューからポリシーを選択します。 ポリシーの作成から JSON タブを押して以下を貼り付けします。
途中の mybucket の箇所は任意のバケット名に置き換えてください。

{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": "s3:ListAllMyBuckets", "Resource": "*" },
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket", "s3:GetBucketLocation"],
      "Resource": "arn:aws:s3:::mybucket"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::mybucket/*"
    }
  ]
}

貼り付けたら、名前を CrossAccountAccessS3Policy として作成します。

ロールを作成する

ポリシーを作成したので、今度はそれをアタッチするロールを作成します。
後に、作成するロールを使用できるアカウントを指定するために AWS のアカウント ID が必要になります。
あらかじめ、アカウントAの ID をメモしておきましょう。
ここではアカウント ID の例として111111111111を使います。

再び アカウントB の IAM コンソールからロール、ロールの作成を選択します。
信頼されたエンティティの種類を選択 の画面で 別のAWSアカウント を選択し、アカウントAの ID を入力します。
次へ進むとポリシーの選択画面に行くので先ほど作成したポリシーにチェックを入れ、CrossAccountAccessS3Role という名前で作成します。

作成したロールの使用例

ロールが作成できたのでさっそく使ってみましょう。
今回は ServerlessFramework での使い方を紹介します。

以下は serverless.yml の内容です。
111111111111の箇所は適切なアカウント ID へ変更してください。

service: cross-account-s3

provider:
  name: aws
  region: ap-northeast-1
  runtime: ruby2.5
  iamRoleStatements:
    - Effect: "Allow"
      Action: "sts:AssumeRole"
      Resource: "arn:aws:iam::111111111111:role/CrossAccountAccessS3Role"

functions:
  cross_account_s3:
    handler: handler.endpoint
    events:
      - http:
          path: /
          method: get

そして次が Lambda 関数のコードになります。
こちらも 111111111111 の箇所を変更してください。

require 'aws-sdk-core'
require 'aws-sdk-s3'

def endpoint(event:, context:)
  sts = Aws::STS::Client.new(region: 'ap-northeast-1')
  role_credentials = Aws::AssumeRoleCredentials.new(
    client: sts,
    role_arn: 'arn:aws:iam::111111111111:role/CrossAccountAccessS3Role',
    role_session_name: 'session'
  )

  client = Aws::S3::Client.new(region: 'ap-northeast-1', credentials: role_credentials)
  resp = client.list_buckets

  { statusCode: 200, body: resp.to_h.to_json }
end

AWS プロファイルの設定がアカウントAのものになっているかを確認してからデプロイしましょう。

デプロイが完了したら CLI に出力される APIGateway の URL へアクセスしてください。
表示されている値にはアカウントA の S3 バケットだけでなく、アカウントBのバケットも含まれているはずです。