S3保管したCloudTrailログに別アカウントのLambdaからアクセスする

2016.08.26

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

こんにちは、虎塚です。

今回は、S3バケットに格納したCloudTrailログに、別のアカウントのAWS Lambdaからアクセスする方法をご紹介します。

前提となる構成

2つのAWSアカウントがあるとします。

  • アカウントA: AWSアカウントID 000000000000
  • アカウントB: AWSアカウントID 111111111111

LambdaでS3バケット内のCloudTrailログにアクセス

アカウントAではCloudTrailログを有効にしていて、gz形式のログファイルをアカウントAのS3バケット に保管しています。アカウントBのLambdaファンクションから、このログファイルへアクセスして、getObjectでファイルを参照しようとしています。

S3バケットには、CloudTrailログの保存先として必要なバケットポリシーが設定されているものとします。次の公式ドキュメントにあるポリシーをそのまま使っていると考えてください。

さて、どのAWSリソースに対して、どのような権限を設定すれば、意図したアクセスができるでしょうか。

設定手順

アカウントA側での操作

CloudTrailログをS3バケットに保管している側のアカウントで、次の手順をおこないます。

1. IAMロールを作成

まず、アカウントAで、アカウントBにアクセスを提供するためのIAMロールを作成します。アカウントBのLambdaファンクションが、このロールを後ほど利用します。

AWS Management ConsoleのIAMダッシュボードを開き、ロール一覧で[Create New Role]ボタンを押します。次の設定でロールを作成します。

  • Role Name: 任意 (cross-role-for-cloudtrail)
  • Role Type: 「Provide access between AWS accounts you own」
  • Account ID: アカウントBのAWSアカウントID (111111111111)
  • Policy: 未選択

作成したロールのarnは、「arn:aws:iam::000000000000:role/cross-role-for-cloudtrail」のようになります。

2. IAMポリシーを作成

次に、アカウントAで、S3バケット (my-cloudtrail-bucket) へのアクセスを許可するIAMポリシーを作成します。

AWS Management ConsoleのIAMダッシュボードを開き、ポリシー一覧で[Create Policy]ボタンを押します。[Create Your Own Policy]を選んで、次の設定でポリシーを作成します。

  • Policy Name: 任意 (S3GetAndListAccess)
  • Policy Document: 次のとおり
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": "arn:aws:s3:::my-cloudtrail-bucket/*"
        }
    ]
}

3. ポリシーをロールに適用

ステップ2で作成したポリシーを、ステップ1で作成したロールに適用します。

ロール一覧でcross-role-for-cloudtrailをダブルクリックして、[Permissions]タブの[Attach Policy]ボタンを押します。ポリシー一覧から、ステップ2で作成したポリシー (S3GetAndListAccess) を選択します。

アカウントB側での操作

もう片方のAWSアカウントで、次の手順をおこないます。

4. AssumeRole許可を定義したIAMポリシーを作成

次の設定でIAMポリシーを作成し、他のロールを引き受けるために必要な権限を定義します。

AWS Management ConsoleのIAMダッシュボードを開き、ポリシー一覧で[Create Policy]ボタンを押します。[Create Your Own Policy]を選んで、次の設定でポリシーを作成します。

  • Policy Name: 任意 (AssumeRolePolicy)
  • Policy Document: 次のとおり
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

5. Lambdaファンクションの実行ロールを作成

この後作成するLambdaファンクションに適用するためのIAMロールを、アカウントBに作成します。

  • Role Name: 任意 (cloudtrail-cross-access-lambda-role)
  • Role Type: AWS Service Rolesの「AWS Lambda」を選択
  • Policy: ステップ4で作成したポリシー (AssumeRolePolicy)

このロールは、ステップ6で作成するLambdaファンクションに適用するため、本来はステップ4で作成したポリシーに加えて、Lambdaファンクションの実行に必要な権限のポリシーも必要です。今回は、ステップ4で作成したポリシーだけで動くサンプルコードのため、後者を省略しました。

6. Lambdaファンクションの作成

最後に、アカウントBでLambdaファンクションを作成します。このLambdaファンクションは、アカウントAのS3バケットのオブジェクト(CloudTrailログ)に対して、GetObject APIを実行します。

Management ConsoleのLambdaダッシュボードで、[Create a Lambda function]ボタンを選択します。次の設定で、Lambdaファンクションを作成します。

  • Select blueprint画面: 「s3-get-object-python」を選択
  • Configure triggers画面: [Remove]ボタンを選択して、何も指定しない状態にする
  • Name: 任意 (get-cloudtrail-in-s3)
  • Runtime: Python 2.7
  • Lambda function code: デフォルトのコードを削除して、次のコードをコピーアンドペーストする
import boto3
import os

def lambda_handler(event, context):
  sts_client = boto3.client('sts')

  assumedRoleObject = sts_client.assume_role(
    RoleArn="arn:aws:iam::000000000000:role/cross-role-for-cloudtrail",
    RoleSessionName="AssumeRoleSession1"
  )

  credentials = assumedRoleObject['Credentials']

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

  s3_resource.Object('my-cloudtrail-bucket', 'AWSLogs/000000000000/CloudTrail/ap-northeast-1/2016/08/25/000000000000_CloudTrail_ap-northeast-1_20160825T1310Z_XXXXXXXXXXXXXXXX.json.gz').download_file('/tmp/hoge.gz')
  files = os.listdir('/tmp/')
  for file in files:
    print file

コードの中で、ステップ1で作成したアカウントAのロールARN、CloudTrail用S3バケット名、特定のログファイル名の指定が必要です。

  • Handler: lambda_function.lambda_handler
  • Role: Choose an existing role
  • Existing role: ステップ5で作成したロール (cloudtrail-cross-access-lambda-role)
  • Memory (MB): 128
  • Timeout: 5 sec
  • VPC: no vpc

設定を保存したら、[Test]ボタンを押して実行します。

「null」が出力され、次のようなログを得られれば成功です。

START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: $LATEST
hoge.gz
END RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
REPORT RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx   Duration: 2448.14 ms    Billed Duration: 2500 ms     Memory Size: 128 MB    Max Memory Used: 41 MB

説明

なぜアカウントBのLambdaファンクションが、アカウントAのS3オブジェクトにアクセスできたかを、簡単に説明します。

ロールとSTSの利用

アカウントBのLambdaファンクションでは、アカウントAのロールの認証情報を取得します(ステップ6)。これは、Lambdaファンクションに実行ロールを通してAssumeRole許可を与えていたため(ステップ4、5)、そしてアカウントAのロールでアカウントBを信頼するように設定していたため(ステップ1)、実現できました。

Lambdaファンクションが利用する一時的な認証情報 (STS) で可能な操作は、アカウントAのロールに対してポリシーで許可された操作(ステップ2、3)に限定されます。

おわりに

今回の設定は、クロスアカウントのためのロール引き受けと、AWS LambdaでのSTS利用がポイントでした。

それでは、また。