It's a peacehell world.

こんな名前ですが情報技術について主に扱うブログです。

[AWS] Lambda で S3 バケットに対する権限を CDK Python で付与したい

はじめに

Lambda から S3 バケットに対して Read/Write したいけどバケットを Public にするわけにはいかない。

そんなときはバケットポリシーで特定の Lambda に対してのみ Read/Write 権限を付与しましょう。

CDK Python でやるときはこんな感じになります。

サンプル

from aws_cdk import (core,
                     aws_s3,
                     aws_iam,
                     )
from aws_cdk.aws_lambda import Runtime
from aws_cdk.aws_lambda_python import PythonFunction


class SampleStack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # lambda
        lambda_ = PythonFunction(
            self, 'SampleLambda',
            runtime=Runtime.PYTHON_3_8,
            entry='src',
            index='sample.py',
            handler='handler')

        # S3
        bucket_ = aws_s3.Bucket(self, 'sample-bucket-name')
        bucket_.add_to_resource_policy(
            aws_iam.PolicyStatement(
                effect=aws_iam.Effect.ALLOW,
                actions=['s3:PutObject', 's3:GetObject'],
                principals=[
                    aws_iam.ArnPrincipal(
                        lambda_.role.role_arn
                    )
                ],
                resources=[
                    bucket_.arn_for_objects('*')
                ]
            )
        )

こちらをデプロイすると S3 のバケットポリシーは以下のようになります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": ["{Lambda Role ARN}"]
      },
      "Action": ["s3:PutObject", "s3:GetObject"],
      "Resource": "{S3 Bucket ARN}/*"
    }
  ]
}

これで対象の Lambda 以外からは Access Denied を返すようになりました。

サンプルでは Put と Get 両方付与していますが、S3 バケットから読み取りのみ行う Lambda であれば Action には s3:GetObject のみ設定してください。

おわりに

ArnPrincipal を使うことで "AWS": ["{ARN}"] の書き方ができます。

Lambda だけでなく特定ユーザーのみ操作できるようにするといった場合は IAM ユーザー ARN を設定すればよさそうです。

S3 バケット名は全世界でユニークなので公開は極力控えていきましょう。