/ #aws #cdk 

【Python】CDKでLambdaにDynamoDBのGSIにアクセス許可を付与する

もくじ

あけましておめでとうございます! 今年もよろしくおねがいします 🙇

CDK で作った Lambda に DynamoDB の GSI(グローバルセカンダリインデックス)の権限をどうやって付加するか?という話です。

やりたいことは、ざっくり図にするとこんな感じです。

DynamoDB、Lambda、GSI を CDK でデプロイして GSI に Lambda から Scan を投げみるというデモです 👍

CDK では Lambda に GSI の許可を行ういい感じの機能が用意されていないので、ポリシー作ってアタッチするという力技になります 🙇

⚠ 記事を書き終える間近に気が付きました!

普通にバージョンアップで対応されてた 😅

https://github.com/aws/aws-cdk/pull/1564

古い内容の記事を書いていてもあれなので、泣く泣く記事の大部分を修正 😞

結果。記事にする必用もないくらい簡単なものになってしまった 😅

前提

cdk のシリーズで、 過去記事の続き。

※Dynamo の GSI の作り方等は、上記の過去記事を参照ください!今回は主に過去記事との差分を書いていきます!

では 作っていきましょう 👻

requirements.txt

DynamoDB と Lambda が必用です 👍

aws-cdk.core==1.72.0

aws-cdk.aws-lambda==1.72.0
aws-cdk.aws_dynamodb==1.72.0

スタックファイル

DynamoDB のテーブルと lambda を作って、lambda にテーブルの読み込み権限を与えます。こうすると、GSI にも読み込み権限が付与されます(泣)

from aws_cdk import aws_lambda, core
from aws_cdk.aws_dynamodb import Attribute, AttributeType, ProjectionType, Table


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

        # =======> DynamoDB

        gsi_name = "HogeGSI"

        table = Table(
            self,
            "DynamoTableGsiTable",
            partition_key=Attribute(name="pk", type=AttributeType.NUMBER),
            sort_key=Attribute(name="sk", type=AttributeType.STRING),
            removal_policy=core.RemovalPolicy.DESTROY,
        )

        table.add_global_secondary_index(
            index_name=gsi_name,
            partition_key=Attribute(name="gsi_pk", type=AttributeType.NUMBER),
            sort_key=Attribute(name="gsi_sk", type=AttributeType.STRING),
            projection_type=ProjectionType.KEYS_ONLY,
        )

        # =======> Lambda

        lambda_ = aws_lambda.Function(
            self,
            "LambdaDynamoTableGsi",
            code=aws_lambda.Code.asset("lambdas/dynamo_table_gsi"),
            runtime=aws_lambda.Runtime.PYTHON_3_8,
            handler="lambda_function.lambda_handler",
            environment={"TABLE_NAME": table.table_name, "GSI_NAME": gsi_name},
        )
        table.grant_read_data(lambda_)  # これがあればGSIに読み込み権限が付与される

Lambda

いつものおまけです 👍

import os

import boto3

dynamodb = boto3.client("dynamodb")


def lambda_handler(event, context):

    return dynamodb.scan(TableName=os.getenv("TABLE_NAME"), IndexName=os.getenv("GSI_NAME"))["Items"]

デプロイ 🚀

$ cdk deploy dynamo-table-gsi-stack

動作確認

作ったテーブルと Lambda の名前を取得します。

$ aws dynamodb list-tables | grep dynamo-table-gsi-stack
$ aws lambda list-functions | grep dynamo-table-gsi-stack

今回はこんな(↓)名前でした。

dynamo-table-gsi-stack-DynamoTableGsiTable3CEEAFD7-1EZY6822T8XOK dynamo-table-gsi-stack-LambdaDynamoTableGsiE0F0C0D-1LS4QF6WDEC9Y

以下のように確認してみました。

# リソース名を変数に入れてみる
$ TABLE_NAME=dynamo-table-gsi-stack-DynamoTableGsiTable3CEEAFD7-1EZY6822T8XOK
$ LAMBDA_NAME=dynamo-table-gsi-stack-LambdaDynamoTableGsiE0F0C0D-1LS4QF6WDEC9Y

# ダミーのデータをPUTしてみる
$ aws dynamodb put-item \
  --table-name $TABLE_NAME \
  --item '{"pk":{"N":"1234"},"sk":{"S":"hogehoge"},"gsi_pk":{"N":"987"},"gsi_sk":{"S":"hugohugo"},"dummy":{"S":"GSIでは取得されないパラメータ"}}'

# Lambdaを叩いてレスポンスを確認してみる
$ aws lambda invoke --function-name $LAMBDA_NAME --payload '{}' response.json
$ cat response.json

[{"gsi_pk": {"N": "987"}, "sk": {"S": "hogehoge"}, "pk": {"N": "1234"}, "gsi_sk": {"S": "hugohugo"}}]

動作確認完了 👍

デストロイ

$ cdk destroy dynamo-table-gsi-stack

まとめ

今回は CDK で Lambda と DynamoDB のテーブルと GSI を作って、Lambda に権限を付与する。ということをやってみました 👍

GSI への権限不要は、昔はポリシーを力技でアタッチする方法でしたが、今は Grant で普通に設定可能でした 😅

今回のリポジトリはこちら

https://github.com/sisi100/cdk-my-template/tree/20210131.0

Author

Sisii

インフラが好きなエンジニアぶってるなにか