1. はじめに

Lambdaから別AWSアカウントのリソースにアクセスする要件がたまにあります。

別AWSリソースにアクセスすることをクロスアカウントアクセスといいます。

ただ、私はクロスアカウントアクセスという単語を耳にしたことがありますが、自分自身で設定をおこなったことがなかったので、一度設定をしてみました。

ここでは、LambdaからクロスアカウントのS3にアクセスするための設定をまとめます。

2. 前提

  • AWSアカウントを2つ用意していること。

  • LambdaがあるアカウントをAアカウント、S3があるアカウントをBアカウントとする。

3. 関連知識

クロスアカウントアクセスに必要な知識を解説します。

3.1 AWS Security Token Service (AWS STS) とは

AWS Security Token Service (以下、AWS STS) とは、AWSリソースへのアクセスコントロールできるサービスで一時的な認証情報発行します。

AWS STSは、クロスアカウントのアクセスや他要素認証などに利用されます。この一時的なクレデンシャルは数分~最大12時間までの有効期限を設定できます。

3.2 Assume Roleとは

**Assume Role(アシュームロール)**とは、一時的に別の権限を持ったロールを使えるようにする仕組みです。

AWSでは、通常IAMユーザーやLambdaなどが操作を行いますが、Assume Roleを使うと、

一時的な認証情報を作成して、そのロールを引き受けて、そのロールが持っている権限でAWSサービスにアクセスできます。

この一時的な認証情報は**AWS STS(Security Token Service)**が発行します。

4. AWS構成図

構成図

5. クロスアカウントアクセスするための設定

5.1 Aアカウント側のLambdaの実行ロール

Lambda実行ロール作成します。 クロスアカウントアクセスするために重要なのが、sts.AssumeRoleを付与しやポリシーを作成することです。 Resourceには、クロスアカウント先のロールを取得します。 ここでは、アカウントBに作成するS3にアクセスするための、ロールを作成し、そのロールを引き受けられるように設定します。

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: 'lambda-execution-role'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: 'allow-cloud-watchlogs-access'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                  - logs:DescribeLogStreams
                  - logs:CreateLogGroup
                Resource: '*'
        - PolicyName: 'allow-access-s3-bucket'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: sts:AssumeRole
                Resource: arn:aws:iam::{アカウントB}:role/CrossAccountLambdaAccessRole

5.2 Lambdaのアプリケーションコード

STSでアカウントBのCrossAccountLambdaAccessRoleへの一時的な認証情報を取得し、アカウントAのLambdaがCrossAccountLambdaAccessRoleを引き受けます。

CrossAccountLambdaAccessRoleを引き受けることによってアカウントBのS3へアクセスします。

※ Lambdaは、マネージメントコンソールから作成しました。Lambdaには、5.1 Aアカウント側のLambdaの実行ロールを紐付けてください。 ※ AWS SAMやCloudFomration、CDKで作成したい方は、別途調べて作成してください

import boto3

def lambda_handler(event, context):

    sts = boto3.client('sts')
    assumed = sts.assume_role(
        RoleArn='arn:aws:iam::{アカウントB}:role/CrossAccountLambdaAccessRole',
        RoleSessionName='LambdaSession'
    )
    credentials = assumed['Credentials']

    s3 = boto3.client(
        's3',
        aws_access_key_id=credentials['AccessKeyId'],
        aws_secret_access_key=credentials['SecretAccessKey'],
        aws_session_token=credentials['SessionToken']
    )

    s3_response = s3.get_object(
            Bucket='cross-account-test-bucket', Key='file.txt'
        )

    print(s3_response['Body'].read().decode('utf-8'))

5.3 Bアカウント側の設定

  • 作成するリソース
    • S3バケット
    • バケットポリシー
    • IAMロール

アカウントBのポリシーはアカウントAのLambda実行ロールを信頼ポリシーに設定します。 許可ポリシーには、S3バケットへのアクセス許可を設定します。

AWSTemplateFormatVersion: 2010-09-09
Resources:
 # アカウントAのLambdaがアカウントBにアクセスするためのIAMロール
  S3AccessRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: CrossAccountLambdaAccessRole
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: "arn:aws:iam::{アカウントA}:role/lambda-execution-role"
            Action: sts:AssumeRole
      Policies:
        - PolicyName: AllowS3Access
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                Resource: "arn:aws:s3:::cross-account-test-bucket/*"
 # S3バケット
  CrossAccountTestBucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: "cross-account-test-bucket"
      PublicAccessBlockConfiguration:
        BlockPublicAcls: false
        BlockPublicPolicy: false
        IgnorePublicAcls: false
        RestrictPublicBuckets: false
  # バケットポリシー
  SreBlogStaticBucketPolicy:
    Type: 'AWS::S3::BucketPolicy'
    DependsOn: CrossAccountTestBucket
    Properties:
      Bucket: !Ref CrossAccountTestBucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: "arn:aws:iam::{アカウントA}:role/$lambda-execution-role"
            Action:
              - "s3:GetObject"
              - "s3:PutObject"
            Resource: "arn:aws:s3:::cross-account-test-bucket/*"

6. おわりに

クロスアカウントアクセスは、はじめて設定する際、戸惑うことがありました。AWS STSやAssume Roleなど関連の単語は聞いたことがありましたが、きちんと理解できていませんでした。

やはり、わからないことを理解するには、一つ一つわからない要素を理解する必要があるなと思いました。

7. 参考ページ

IAM の一時的な認証情報 AssumeRole Amazon S3 バケットにあるオブジェクトに対するクロスアカウントアクセス許可を付与するにはどうすればよいですか?