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が表示されるはずです。

参考

github.com

aws.amazon.com

docs.aws.amazon.com

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の実行ロールにアタッチしてあげなければいけません。 公式を参照する癖をつけたいですね。