[小ネタ] CDK(Python)で CfnBucketにバケットポリシーを付与する

2020.01.24

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

AWS Cloud Development Kit (CDK) の強みに High Level Construct でより簡単にリソースが定義できるところがあります。

一方で CloudFormationのリソースと 1対1 で対応する Low Level Construct(CFNリソース) も扱えます。 High Level Construct が対応していないリソースや、 要件がしっかり固まっている場合などは、こちらを使用することがおすすめです。

(個人的には CFNリソースだけでもプログラムでインフラを書いていけるメリットは 十分に感じています。CloudFormationのほうがやってみた記事・ブログが 多いので、それらを参考にしながらCDKで書くことができます。)

今回は CFNリソースの s3.CfnBucket にバケットポリシーを付与してみます。 内容自体はシンプルですが少し迷うところがあったので備忘録として残します。

目次

  1. 環境
  2. やること
  3. やってみた
  4. app.py 詳細
  5. おわりに

環境

CDKインストールとセットアップ詳細は割愛します (以下の AWS Workshopや 弊社ブログを参照ください)

環境は以下のとおり

  • cdk: 1.20.0
  • Python: 3.7.3

やること

CfnBucket で作成した S3バケットにバケットポリシーを付与します。

今回は Application Load Balancer がアクセスログを S3に格納するときに必要になる、 以下のバケットポリシーを付与します。 (東京リージョンを想定)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::(aws-account-id):root"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::(bucket-name)/(prefix)/*"
    }
  ]
}

参考: Application Load Balancer のアクセスログ > バケットのアクセス許可

(aws-account-id) にはALBのリージョンに対応する AWSアカウントID、 (bucket-name)/(prefix) にはバケット名とプレフィクスが入ります。

やってみた

以下 requirements.txtapp.py を作成しました。

./requirements.txt

aws-cdk.core
aws-cdk.aws-s3
aws-cdk.aws-iam

./app.py

#!/usr/bin/env python3

from aws_cdk import (
    core,
    aws_iam as iam,
    aws_s3 as s3,
)


class CfnBucketWithPolicyStack(core.Stack):

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

        bucket_name = "cfn-bucket-with-policy-test-abcdefg"
        bucket_prefix = "alb-log"
        elb_account_id = "582318560864"

        # ポリシー作成
        policy_statement = iam.PolicyStatement()
        policy_statement.add_aws_account_principal(elb_account_id)
        policy_statement.add_actions("s3:PutObject")
        policy_statement.add_resources(
            "arn:aws:s3:::{0}/{1}/*".format(bucket_name, bucket_prefix))

        policy_document = iam.PolicyDocument(
            statements=[policy_statement]
        )

        # S3 バケット(CfnBucket)
        bucket = s3.CfnBucket(
            self, "Bucket",
            bucket_name=bucket_name
        )

        # バケットポリシー(CfnBucketPolicy)
        s3.CfnBucketPolicy(
            self, "BucketPolicy",
            bucket=bucket.ref,
            policy_document=policy_document.to_json()
        )


# スタック作成
app = core.App()
CfnBucketWithPolicyStack(app, "CfnBucketWithPolicyStack")

app.synth()

スタック作成

1. pip install -r requirements.txt で必要なパッケージをインストールします。

2. cdk ls でスタック一覧を確認して、

$ cdk ls
CfnBucketWithPolicyStack

3. cdk deploy でスタックを作成します。

確認

マネジメントコンソールから作成されたバケットのバケットポリシーを見てみます。

所望のバケットポリシーになっていることを確認できました。

app.py 詳細

使用したクラスは以下の通り。

▼ iam.PolicyDocument 部分

        bucket_name = "cfn-bucket-with-policy-test-abcdefg"
        bucket_prefix = "alb-log"
        elb_account_id = "582318560864"

        # ポリシー作成
        policy_statement = iam.PolicyStatement()
        policy_statement.add_aws_account_principal(elb_account_id)
        policy_statement.add_actions("s3:PutObject")
        policy_statement.add_resources(
            "arn:aws:s3:::{0}/{1}/*".format(bucket_name, bucket_prefix))

        policy_document = iam.PolicyDocument(
            statements=[policy_statement]
        )

後述する CfnBucketPolicy のコンストラクタ引数: policy_document にバケットポリシーを入れるためのポリシー作成です。

aws_iam.PolicyStatement を作成し、 以下メソッドでステートメント情報を入れていきます。

  • add_aws_account_principal: プリンシパルの追加
  • add_actions: アクションの追加
  • add_resources: リソースの追加

このステートメントをもとに、 aws_iam.PolicyDocument を作成します。

▼ s3.CfnBucketPolicy 部分

        # バケットポリシー(CfnBucketPolicy)
        s3.CfnBucketPolicy(
            self, "BucketPolicy",
            bucket=bucket.ref,
            policy_document=policy_document.to_json()
        )

policy_document=policy_document.to_json() の部分でバケットポリシーを指定します。

おわりに

s3.CfnBucketPolicy のドキュメントを見ても、 policy_document の型 が Any なのでどんなデータを入れたら良いのかいまいち分からなかったのが 本ブログのモチベーションでした。

この記事が少しでもどなたかのお役に立てば幸いです。