VPC LambdaからVPCエンドポイント経由でDynamoDBにアクセスしてみた

サーバーレス開発部改め、CX事業本部の佐藤です。

概要

VPC LambdaからDynamoDBにアクセスするユースケースがあったため、実際にやってみました。

VPCにあるRDSなどにアクセスする際は、VPC Lambdaにする必要があります。VPC Lambdaにした場合はLambdaのインターネットアクセスが失われるため、VPC以外のAWSリソースにはアクセスできません(DynamoDBなど)。VPC Lambdaがインターネットにアクセスする際は、AWSの制約でLambdaをプライベートサブネットに配置し、パブリックサブネットにNAT ゲートウェイを配置する必要があります。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/internet-access-lambda-function/

以前は、VPC LambdaからDynamoDBなどにアクセスする際は、この記事のようにNATゲートウェイを配置する必要があったんですが、VPC エンドポイントがDynamoDBに対応したため、VPCエンドポイント経由でアクセスすることが可能になりました。

https://aws.amazon.com/jp/blogs/news/new-vpc-endpoints-for-dynamodb/

実際に動かしていきたいと思います。

VPC、プライベートサブネット、セキュリティグループを作成する

VPCとプライベートサブネット、セキュリティーグループを作成します。マネージメントコンソールやCloudFormationで作成できます。今回は、CloudFormationで作成していきます。テスト用のDynamoDBテーブルも一緒に作成しています。

以下の内容でスタックを作成します。

AWSTemplateFormatVersion: 2010-09-09
Description: "Create VPC"
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: "blog"
  PrivateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/24
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: "Private Subnet A"
  PrivateSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: "Private Subnet C"
  VPCPrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
  VPCPrivateSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetA
      RouteTableId: !Ref VPCPrivateRouteTable
  VPCPrivateSubnetCRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetC
      RouteTableId: !Ref VPCPrivateRouteTable
  LambdaSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Lambda Security Group
      VpcId: !Ref VPC
  BlogTestTable:
    Type: "AWS::DynamoDB::Table"
    Properties:
      AttributeDefinitions:
        -
          AttributeName: "id"
          AttributeType: "N"
      KeySchema:
        -
          AttributeName: "id"
          KeyType: "HASH"
      BillingMode: PAY_PER_REQUEST

CLIでスタックを作成します

aws cloudformation create-stack --stack-name 任意のスタック名 --template-body file://上記の保存したファイル名

VPC Lambdaを作成する

テスト用のVPC Lambdaを作成します。さきほど作ったVPCとサブネットを割り当てていきます。事前に、Lambdaに割り当てるIAMロールに適切なポリシーをアタッチしておいてください。

Lambdaを作成

  • マネージメントコンソールからLambdaを選択します

  • 関数の作成をクリックし、適当な名前を入力し、ランタイムにPython3.7を選択し、関数の作成をクリックします

  • テスト用のコードを書きます。DynamoDBから1レコード取得して返すだけのものです
    import json
    import boto3
    
    client = boto3.resource('dynamodb')
    
    def lambda_handler(event, context):
    
      table = client.Table(cloudformationで作成されたテーブル名)
      res = table.get_item(Key={ "id": 1 })
      item = res['Item']
    
      return item
    
  • Lambdaの設定画面のネットワークの項目で「非VPC」となっているところをさきほど作ったVPC、サブネット、セキュリティーグループを選択します

  • 保存をクリックします

これでVPC Lambdaが作成できました。

VPC エンドポイントなしで実行してみる

VPCエンドポイントなしで、実行してみます。

DynamoDBのテーブルに適当なデータを一行追加して、先ほど作ったVPC Lambdaを実行してみます。実行すると以下のように、Lambdaがタイムアウトしてエラーになりました。インターネットアクセスがないため、DynamoDBにアクセスできていないようです。

VPCエンドポイントを設定する

プライベートサブネットに配置したLambdaからDynamoDBにアクセスするためにVPCエンドポイントを作成します。

  • マネージメントコンソールからVPCを選択します

  • 左側のメニューからエンドポイントを選択します

  • エンドポイントの作成をクリックします

  • エンドポイントのサービス名の中から com.amazonaws.リージョン名.dynamodbを選択します

  • VPC欄に先ほど作ったVPCを選択します。ルートテーブル欄で、VPC Lambdaが割り当てられているプライベートサブネットのルートテーブルを選択します

  • エンドポイントの作成をクリックします

簡単にエンドポイントを作成できました。

VPCエンドポイントありで実行してみる

VPCエンドポイントを作成しましたので、Lambdaを再度実行してみます。さきほどはタイムアウトになっていましたが、今回はDynamoDBからデータが取得されました。

まとめ

VPCエンドポイントにより、簡単にVPC LambdaからAWSリソースにアクセスすることができるようになりました。VPC LambdaからVPC外のAWSリソースにアクセスする場合に参考にしてみてください。