Aurora ServerlessのData APIを有効化してEC2/Lambdaから接続する

Aurora ServerlessのData APIを有効化してEC2/Lambdaから接続する

Aurora ServerlessのData APIを有効化してEC2(AWS CLI)とLambda(Boto3)から接続する

以下のページで、Aurora Serverlessの基本的な事項について取り上げました。

あわせて読みたい
CFNでAurora Serverless v1作成 【CloudFormationでAurora Serverless v1作成】 Aurora ServerlessはAWSが提供するマネージデータベースサービスです。 Amazon Aurora Serverless は、Amazon Aurora の...

Aurora Serverless v1の特徴の1つに、Data APIがあります。

Aurora Serverless v1 の Data API を使用すると、Aurora Serverless v1 DB クラスターへのウェブサービスインターフェイスを操作できます。Data API は、DB クラスターへの永続的な接続を必要としません。代わりに、セキュア HTTP エンドポイントおよび AWS SDK との統合を利用できます。

Aurora Serverless v1 の Data API の使用

本ページでは、Data APIを使用して、EC2インスタンスおよびLambda関数からAurora Serverlessに接続します。

構築する環境

Diagram of connect Aurora Serverless from EC2/Lambda using Data API.

VPC内に3つのサブネットを作成します。
いずれもインターネットにアクセス不可なプライベートサブネットとします。

Aurora Serverlessを作成し、AZが異なる2つのサブネットと関連付けます。
MySQLタイプの最新のバージョンを指定します。
Data APIを有効化します。

EC2インスタンスを作成します。
Aurora Serverlessに接続するクライアントです。
OSは最新版のAmazon Linux 2とします。

SSM用のエンドポイントを作成します。
SSM Session Managerを使用して、EC2インスタンスにリモートアクセスするためです。

RDS Data用のエンドポイントも作成します。
Data APIを使用して、EC2インスタンスからAurora Serverlessに接続するためです。

VPC外にLambda関数を作成します。
こちらもAurora Serverlessに接続するクライアントです。
ランタイム環境にPython3.8を選択し、Function URLを有効化します。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

https://github.com/awstut-an-r/awstut-fa/tree/main/059

テンプレートファイルのポイント解説

本ページはAurora ServerlessのData APIを有効化し、EC2/Lambdaから接続する方法を取り上げます。
Aurora Serverlessに関する基本的な事項については、冒頭にご紹介したページをご確認ください。

セキュリティグループ

Resources:
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${Prefix}-InstanceSecurityGroup"
      GroupDescription: Deny All.
      VpcId: !Ref VPC

  DBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${Prefix}-DBSecurityGroup"
      GroupDescription: DBSecurityGroup.
      VpcId: !Ref VPC
      #    SecurityGroupIngress:
      #      - IpProtocol: tcp
      #        FromPort: !Ref MySQLPort
      #        ToPort: !Ref MySQLPort
      #        SourceSecurityGroupId: !Ref InstanceSecurityGroup

  EndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${Prefix}-EndpointSecurityGroup"
      GroupDescription: Allow HTTPS from InstanceSecurityGroup.
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: !Ref HTTPSPort
          ToPort: !Ref HTTPSPort
          SourceSecurityGroupId: !Ref InstanceSecurityGroup
Code language: YAML (yaml)

3つのセキュリティグループを定義します。

1つ目はEC2インスタンス用です。
冒頭でご紹介したページと同様に、今回の構成でも、インスタンスに対するインバウンド通信は発生しません。
ですから何もインバウンド通信を許可しません。

2つ目はAurora Serverless用です。
こちらも何もインバウンド通信を許可しません。
今回はData APIを使ってAurora Serverlessに接続するため、MySQLポートを解放する必要はありません。
またData APIでの接続はHTTPS通信によって実行されますが、この通信はAurora ServerlessからData API用エンドポイント向けにアウトバウンド通信のため、こちらもセキュリティグループで許可する必要はありません。

3つ目はVPCエンドポイント用です。
今回はSSM用およびRDS Data用で合計4つのエンドポイントを作成します。
いずれもインスタンスからのHTTPS通信が流れますので、それを反映する内容です。

Aurora Serverless

Resources:
  DBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DatabaseName: !Ref DBName
      DBClusterIdentifier: !Ref DBClusterIdentifier
      DBSubnetGroupName: !Ref DBSubnetGroup
      EnableHttpEndpoint: true
      Engine: !Ref DBEngine
      EngineMode: serverless
      EngineVersion: !Ref DBEngineVersion
      MasterUsername: !Ref DBMasterUsername
      MasterUserPassword: !Ref DBMasterUserPassword
      StorageEncrypted: true
      VpcSecurityGroupIds:
        - !Ref DBSecurityGroup
Code language: YAML (yaml)

ポイントはEnableHttpEndpointプロパティです。
Aurora ServerlessでData APIを有効化するためには、本プロパティに「true」を設定します。
この設定によってData API用のHTTPエンドポイントが用意されます。

他は特別な設定は不要です。

Secrets Manager

Resources:
  Secret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: !Sub "${Prefix}-Secret"
      SecretString: !Sub '{"username":"${DBMasterUsername}","password":"${DBMasterUserPassword}"}'
Code language: YAML (yaml)

Data APIを使用してAurora Serverlessに接続するためには、Sercrets Managerを使用する必要があります。

Data API は AWS Secrets Manager に保存されたデータベース認証情報を使用するため、ユーザーは Data API の呼び出しで認証情報を渡す必要はありません。

Aurora Serverless v1 の Data API の使用

具体的には、Aurora DBクラスターを定義時に設定したマスターユーザーとパスワードに関する情報からシークレットを作成します。
SecretStringプロパティに、JSON形式でシークレット文字列を定義します。
2つの情報はそれぞれussername、passwordの値として設定します。

VPCエンドポイント

Resources:
  RDSDataEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.rds-data"
      SubnetIds:
        - !Ref PrivateSubnet1
      VpcEndpointType: Interface
      VpcId: !Ref VPC

  #S3Endpoint:
  #  Type: AWS::EC2::VPCEndpoint
  #  Properties:
  #    RouteTableIds:
  #      - !Ref PrivateRouteTable
  #    ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
  #    VpcId: !Ref VPC
Code language: YAML (yaml)

Data APIを使用してAurora Serverlessに接続するためには、Data API用HTTPエンドポイント向けに通信を行います。
プライベートサブネット内のEC2インスタンスが、同エンドポイント向けに通信を行うためには、RDS Data用VPCエンドポイントを作成する必要があります。

詳細につきましては、以下のAWS公式ページをご確認ください。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/data-api.html#data-api.vpc-endpoint

なお冒頭でご紹介したページとは異なり、S3用VPCエンドポイントは作成しません。
本エンドポイントは、プライベートサブネット上のインスタンスが、S3上に構築されたyumリポジトリにアクセスし、MySQLクライアントパッケージをインストールするために使用しました。
しかし今回はMySQL通信ではなく、HTTPS通信によってAurora Serverlessと通信します。
ですからクライアントパッケージは不要となり、本エンドポイントも不要となります。

EC2インスタンス

Resources:
  Instance:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref PrivateSubnet
          GroupSet:
            - !Ref InstanceSecurityGroup
      #UserData: !Base64 |
      #  #!/bin/bash -xe
      #  yum update -y
      #  yum install -y mariadb
Code language: YAML (yaml)

Data APIを使用して、Aurora Serverlessに接続するクライアントとしてのEC2インスタンスです。

先述の通り、MySQLクライアントは不要ですので、ユーザーデータを使用したパッケージのインストールは実行しません。

Lambda関数

Resources:
  Function:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          DBCLUSTER_ARN: !Ref DBClusterArn
          DBNAME: !Ref DBName
          DBTABLE: !Ref DBTableName
          REGION: !Ref AWS::Region
          SECRET_ARN: !Ref SecretArn
      Code:
        ZipFile: |
          import boto3
          import json
          import os

          dbcluster_arn = os.environ['DBCLUSTER_ARN']
          dbname = os.environ['DBNAME']
          dbtable = os.environ['DBTABLE']
          region = os.environ['REGION']
          secret_arn = os.environ['SECRET_ARN']

          sql = 'select * from {table};'.format(table=dbtable)
          client = boto3.client('rds-data', region_name=region)

          def lambda_handler(event, context):
            response = client.execute_statement(
              database=dbname,
              resourceArn=dbcluster_arn,
              schema='mysql',
              secretArn=secret_arn,
              sql=sql
            )

            return {
              'statusCode': 200,
              'body': json.dumps(response, indent=2)
            }
      FunctionName: !Sub "${Prefix}-function"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole.Arn
Code language: YAML (yaml)

Data APIを使用して、Aurora Serverlessに接続するクライアントとしてのLambda関数です。

インライン表記で実行するコードを定義します。
詳細については、以下のページをご確認ください。

あわせて読みたい
CloudFormationでLambdaを作成する3パータン(S3/インライン/コンテナ) 【CloudFormationでLambdaを作成する】 CloudFormationでLambdaを作成する場合、大別すると以下の3パターンあります。 S3バケットにコードをアップロードする インライ...

Environmentプロパティで、環境変数として、DBクラスターやSecrets Managerシークレット等のパラメータを設定します。
コード内では、os.envrionで環境変数にアクセスします。

Boto3を使用して、RDS Data用クライアントオブジェクトを作成します。
execute_statementを実行して、Aurora Serverlessに接続します。
先述の各種パラメータを引数として渡します。
なお実行するSQL分ですが、特定のテーブル(Pets)内のテーブルを取得する内容です。
SQLの実行結果を関数の実行結果として返します。

Function URLを有効化します。
特定のURLからLambda関数を実行できる機能です。
Function URLの詳細については、以下のページをご確認ください。

あわせて読みたい
CFNでLambda Function URL – 認証方式: NONE 【CloudFormationでLambda Function URLを作成する(NONEバージョン)】 2022年4月22日にLambda Function URLがリリースされました。 この新機能は、AWS Lambda サービス...

IAMロール

Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

  FunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  AuroraServerlessDataAPIPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub "${Prefix}-AuroraServerlessDataAPIPolicy"
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - secretsmanager:GetSecretValue
            Resource:
              - !Ref SecretArn
          - Effect: Allow
            Action:
              - rds-data:BatchExecuteStatement
              - rds-data:BeginTransaction
              - rds-data:CommitTransaction
              - rds-data:ExecuteStatement
              - rds-data:RollbackTransaction
            Resource:
              - !Ref DBClusterArn
      Roles:
        - !Ref FunctionRole
        - !Ref InstanceRole
Code language: YAML (yaml)

EC2インスタンスおよびLambda関数用のIAMロールを作成します。
両者に共通する権限は、IAMポリシーとして定義します。

ポイントは2つです。
1つ目はSecrets Managerへのアクセスです。
先述のシークレットにアクセスする権限を与えます。

2つ目はData APIを使用するための権限です。
先述のAurora Server DBクラスターに対して、SQLを実行するための最低限の権限を与えます。

なお今回の設定は以下のページを参考に設定しました。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/data-api.html#data-api.access

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • EC2インスタンス:i-02b21e07f33a5074c
  • Lambda関数:fa-059-function
  • Lambda関数のFunction URL:https://7vgt4c3bmf7n3xp7htprqdhi5u0tfdms.lambda-url.ap-northeast-1.on.aws/
  • Aurora Serverlessに作成するデータベース名:testdb
  • Aurora Serverlessのデータベースに作成するテーブル名:Pets
  • Aurora Serverless DBクラスターのARN:arn:aws:rds:ap-northeast-1:[account-id]:cluster:fa-059-dbcluster
  • Secrets ManagerシークレットのARN:arn:aws:secretsmanager:ap-northeast-1:[account-id]:secret:fa-059-Secret-poaIGs

AWS Management ConsoleからもAurora Serverlessの作成状況を確認します。

Detail of Aurora Serverless 1.
Detail of Aurora Serverless 2.

正常にAurora Serverlessが作成されています。
そしてData APIが有効化されていることも確認できます。

動作確認

EC2インスタンス

準備が整いましたので、EC2インスタンスにアクセスします。
インスタンスへのアクセスはSSM Session Managerを使用します。

% aws ssm start-session --target i-02b21e07f33a5074c

Starting session with SessionId: root-0815f8b32141bb9b4

sh-4.2$
Code language: Bash (bash)

SSM Session Managerの詳細につきましては、以下のページをご確認ください。

あわせて読みたい
LinuxインスタンスにSSM Session Manager経由でアクセスする 【LinuxインスタンスにSSM Session Manager経由でアクセスする】 EC2インスタンスにSSM Session Manager経由でアクセスする構成を確認します。 Session Manager は完全...

AWS CLIからData APIを使用して、Aurora Serverlessに接続します。
まずAurora ServerlessのデータベースにPetsテーブルを作成します。

sh-4.2$ aws rds-data execute-statement \
--resource-arn "arn:aws:rds:ap-northeast-1:[account-id]:cluster:fa-059-dbcluster" \
 --schema "mysql" \
--secret-arn "arn:aws:secretsmanager:ap-northeast-1:[account-id]:secret:fa-059-Secret-poaIGs" \
 --region ap-northeast-1 \
 --sql "create table Pets(id varchar(200), type varchar(200), price float)" \
--database "testdb"
{
    "numberOfRecordsUpdated": 0,
    "generatedFields": []
}
Code language: Bash (bash)

正常に実行されました。

次に作成したテーブルにレコードを追加します。

sh-4.2$ aws rds-data execute-statement \
--resource-arn "arn:aws:rds:ap-northeast-1:[account-id]:cluster:fa-059-dbcluster" \
 --schema "mysql" \
--secret-arn "arn:aws:secretsmanager:ap-northeast-1:[account-id]:secret:fa-059-Secret-poaIGs" \
 --region ap-northeast-1 \
 --sql "insert into Pets values (111, 'dog', 123)" \
--database "testdb"
{
    "numberOfRecordsUpdated": 1,
    "generatedFields": []
}
Code language: YAML (yaml)

こちらも正常に実行されました。

追加されたレコードを確認します。

sh-4.2$ aws rds-data execute-statement \
--resource-arn "arn:aws:rds:ap-northeast-1:[account-id]:cluster:fa-059-dbcluster" \
 --schema "mysql" \
--secret-arn "arn:aws:secretsmanager:ap-northeast-1:[account-id]:secret:fa-059-Secret-poaIGs" \
 --region ap-northeast-1 \
 --sql "select * from Pets" \
--database "testdb"
{
    "records": [
        [
            {
                "stringValue": "111"
            },
            {
                "stringValue": "dog"
            },
            {
                "doubleValue": 123.0
            }
        ]
    ],
    "numberOfRecordsUpdated": 0
}Code language: JavaScript (javascript)

保存されたレコードを取得することができました。

以上の通り、EC2インスタンスにおいて、Data APIを使用して、AWS CLIからAurora Serverlessに接続することができました。

Lambda関数

関数の実行はFunction URLにアクセスして行います。
以下が実行結果です。

Result of Aurora Serverless Data API.

こちらも正常に実行されました。

以上の通り、Lambda関数において、Data APIを使用して、Aurora Serverlessに接続することができました。

まとめ

Aurora ServerlessでData APIを有効化する方法を確認しました。

EC2インスタンスおよびLambda関数からData APIを使用する方法も確認しました。