CDK で DynamoDB Stream を Lambdaのトリガーにする時の注意点
タイトルを実現するために、半日近く溶かしたので備忘録として残しておきます。
CDKの細かい説明は省きます。
正常に動作するコードがこちら
import { DynamoEventSource } from '@aws-cdk/aws-lambda-event-sources'; import * as dynamodb from '@aws-cdk/aws-dynamodb'; import * as lambda from '@aws-cdk/aws-lambda'; . . . const Table = dynamodb.Table.fromTableAttributes(...,{ // tableArn: でもOK // tableArn tablaName のどちらか片方必須 tableName: {table名}, tableStreamArn: {tableのStreamArn}' }); const Event = new DynamoEventSource(Table, { startingPosition: lambda.StartingPosition.LATEST, }); const fn = new lambda.Function(...,{ . . . events:[Event] });
別のコンストラクタのスタックとして作成したDynamoDBを取得してStreamArnを使ってイベントソースを作成するには、fromTableAttributes()
でテーブルを取得しないといけないようです。
fromTableArn()
、fromTableName()
で取得するとストリームが設定されていないですよと怒られます。
ドキュメント内を解決策は探しても見つからず結局GitHubのIssueが解決の糸口となりました...
1/26 追記
あとは// tableArn tablaName のどちらか片方必須
というのも味噌です。
公式→issue→ブログくらいの順番で探すのが良さそうですね。
VPC内にElasticsearchを置く時の注意点
VPC内のプライベートサブネットにElasticsearchを置いたはいいけど、LambdaからAPI叩けないしKibanaもアクセスできなくて困ったときのメモです。
解決策
- BastionServerとして同VPC内にEC2(パブリックサブネット)を置く
- EC2にSSH接続してダイナミックフォワードを行う(ダイナミックフォワードあまりわかっていない...)
- Lambdaを同じVPC内に置く
- 仕様によってプライベートかパブリックかを選択する
- それぞれのリソースに適切なセキュリティグループ(後述)を設定する
セキュリティグループ設定
EC2
Lambda
- 今回はインバウンドの設定は不要(仕様による)
Elasticsearch
ハマりポイント
ElasticsearchのアクセスコントロールでEC2のプライベートIPを許可しようとしたが以下のエラーが出ました。
UpdateElasticsearchDomainConfig: {"message":"You can’t attach an IP-based policy to a domain that has a VPC endpoint. Instead, use a security group to control IP-based access."}
解決策が見つからず2時間くらいはまりましたが、ちゃんと公式に書いてありました。
VPCs ではセキュリティグループを通じてドメインへのアクセスを管理できます。多くのユースケースでは、このセキュリティ機能の組み合わせで十分となり、ドメインにオープンなアクセスポリシーを安心して適用できます。
Amazon Elasticsearch Service ドメインの VPC サポート - Amazon Elasticsearch Service
どうやらセキュリティグループでの制限で十分のようです。
つまりVPC内にElasticsearchを置くケースだとオープンアクセスを選択しておいて、アタッチしているセキュリティグループのみでアクセスの制限を行う形になります。
追記(2021/1/16)
CDKでElasticsearchを作成する時は明示的にオープンアクセスを設定しなければいけないみたいです。
以下がオープンアクセスのポリシーステートメントです。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "es:*", "Resource": "{domain ARN}/*" } ] }
またKibanaにアクセスするためにSOCKSプロキシを用いたダイナミックフォワード方式ではなく、ローカルフォワード方式でSSHトンネルを掘るときには、EC2にアタッチするセキュリティグループにローカルマシンからの443ポート
アクセスを許可し、8157ポート
を閉じておきましょう。
コマンドもこちらに残しておきます。
$ ssh -i xxxxxxxx.pem ec2-user@{dns} -N -L 9200:{elasticsearch-domain}:443
https://localhost:9200/_plugin/_kibana
へアクセスすると、Kibanaが表示されるはずです。
参考
VPC内にLambdaを置く時の注意点
LambdaをVPC内に置こうとしてエラーが発生した時のメモです。
マネコンからVPC、サブネット、セキュリティグループを指定して保存しようとすると以下のエラーが出ました。
The provided execution role does not have permissions to call CreateNetworkInterface on EC2
ネットワークインターフェイスを作る権限がないみたい。
Lambda VPC ネットワークインターフェース でググると公式がヒット。
Lambda は、関数のアクセス許可を使用してネットワークインターフェイスを作成および管理します。VPC に接続するには、関数の実行ロールに次のアクセス許可が必要です。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-vpc.html
AWS管理ポリシーであるAWSLambdaVPCAccessExecutionRole
をLambdaの実行ロールにアタッチしてあげなければいけません。
公式を参照する癖をつけたいですね。