ForgeVision Engineer Blog

フォージビジョン エンジニア ブログ

Amazon Athenaデータソースコネクターを使ってみた ~ AthenaMySQLConnector編 ~

こんにちは、クラウドインテグレーション事業部の平原です。

皆様は、ネクターというジュースを飲んだことがあるでしょうか?
私はたまにあの濃厚なピーチの味が恋しくなり飲んだりします!特に夏の季節は!!

といったところで今回は、Amazon Athenaとデータソース(RDSやOpenSearchなど)を連携するデータソースコネクターについて記事にします。
AWSサービスのAmazon Athenaをご利用し、濃厚なデータ分析を行っている方もいるかと思います。
Amazon Athenaをご利用の方の参考になればと思います。

はじめに

今回の記事は、データソースコネクターのAthenaMySQLConnector編です。
この記事とは別にOpenSearchと連携するAthenaElasticsearchConnector編も記事にしていますので、そちらも見て頂けると嬉しいです。

使用可能なデータソースコネクターは下記ページが参考になります。 docs.aws.amazon.com

また、参考程度となりますが、CloudFormationテンプレートの記載についても記述します。

データソースコネクターの作成

AWSマネージメントコンソールからデータソースコネクターを作成する方法を記載します。

  1. AWSマネージメントコンソールのAthenaページに遷移する

  2. 左ペインのデータソースを選択し、「データソースの作成」をクリックする

  3. "データソースを選択"で、"MySQL"をチェックし、「次へ」をクリックする

  4. "データソースの詳細を入力"で、以下を入力し、「Lambda関数の作成」をクリックする
    (AWS Lambdaアプリケーション画面が開く)
     ・データソース名: 任意の名前
     ・説明: 任意の説明(入力しなくても良い)

  5. AWS Lambdaアプリケーション AthenaMySQLConnectorの"設定とデプロイ"で、"アプリケーションの設定"に以下の様に入力し、「デプロイ」をクリックする
    ※ データソースコネクターのアプリケーションは、AWS CloudFormationを利用してデプロイされる

     ・アプリケーション名: AWS CloudFormationスタック名
     ・SecretNamePrefix: RDSの認証に使用しているAmazon Secrets Managerのシークレット名のプレフィックス
      この値が、AWS Lambda関数のIAMロールのポリシーで使用される
       例) シークレット名が"test-rds-secret"の場合、ここの値は"test"にする
     ・SpillBucket: Amazon S3バケット名
      Amazon Athenaのクエリ実行が、AWS Lambda関数のTime Out時間を超える場合、一時的に使用されるバケット
     ・DefaultConnectionString: AWS Lambda関数からRDSに接続する際に使用されるURL
      [書式] mysql://jdbc:mysql://<RDSのエンドポイント>/<RDSのDB名>?${<AWS Secrets Manager シークレット名>}
       <RDSのエンドポイント>は、RDS Proxyのエンドポイントを指定することが可能
       例) mysql://jdbc:mysql://test-mysqlproxy.proxy-xxxxxx123456.ap-northeast-1.rds.amazonaws.com/test_db?${test-rds-secret}
     ・DisableSpillEncryption: SpillBucketの暗号化を無効とするか否か
      "false"の場合、暗号化が有効
     ・LambdaFunctionName: AWS Lambdaの関数名
     ・LambdaMemory: AWS Lambdaのメモリサイズ
     ・LambdaRoleARN: AWS Lambda関数に割り当てるIAMロールのARN
      指定しない場合、このデプロイで作成されるIAMロールが割り当てられる
     ・LambdaTimeout: AWS Lambda関数のTime Out時間
     ・PermissionsBoundaryARN: AWS Lambda関数に割り当てるIAMロールに設定するPermissionsBoundaryポリシーのARN
     ・SecurityGroupIds: AWS Lambda関数にアタッチするセキュリティグループのID
     ・SpillPrefix: SpillBucketが利用される際の保存先プレフィックス
     ・SubnetIds: AWS Lambda関数が作成されるVPCサブネットのID
     ・このアプリがカスタム IAM ロールとリソースポリシーを作成することを承認します: チェックする

  6. CloudFormationスタック作成後、Amazon Athenaの"データソースの詳細を入力"画面に戻る

  7. "接続の詳細"で、作成したAWS Lambda関数を選択し、「次へ」をクリックする
     必要に応じて、更新ボタンをクリック

  8. "確認と作成"で、設定内容を確認し「データソースの作成」をクリックする

※ "SecurityGroupIds"や"SubnetIds"から分かるように、AWS Lambda関数はVPC Lambdaとなる
※ AWS Lambda関数は、権限はもちろんだが、ネットワーク的にAWS APIにアクセスできる設定にする必要あり
 AWS Lambda関数をPublicサブネットに配置したが、Public IPアドレスが振られておらず"Network Failure"エラーとなり、ハマりました...

データソースコネクター設定後の確認

  1. Amazon Athenaのデータソースコネクター画面にて、一覧から作成したデータソースコネクターをクリックする

  2. "関連付けられたデータベース"で、意図したデータベースが表示されることを確認する

  3. 任意のデータベースをクリックし、"関連付けられたテーブル"に意図したテーブルが表示されることを確認する

  4. Amazon Athenaの左ペインよりクエリエディタを選択し、遷移する

  5. 上部の"設定"タブにて、クエリ結果の出力先とするS3バケットを設定する

  6. 上部の"エディタ"タブにて、"データソース": 作成したデータソース / "データベース": 任意のデータベースを選択する

  7. クエリのテキストに、クエリ文を記載し、「実行」をクリックする

CloudFormation記載例

参考程度ですが、CloudFormationでの記載例を記述します。
(このまま利用してもCloudFormationは成功しません)

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31

Resources:
  # --------------------------------------------------------------
  # Lambda Application: Connector
  # --------------------------------------------------------------
  AthenaMySQLConnector:
    Type: AWS::Serverless::Application
    Properties:
      Location:
        ApplicationId: arn:aws:serverlessrepo:us-east-1:292517598671:applications/AthenaMySQLConnector # 利用リージョンに関わらず、ここは"us-east-1"
        SemanticVersion: 2023.25.1 ###### バージョンを指定
      Parameters: 
        # The default connection string is used when catalog is "lambda:${LambdaFunctionName}". Catalog specific Connection Strings can be added later. Format: ${DatabaseType}://${NativeJdbcConnectionString}.
        DefaultConnectionString: 'mysql://jdbc:mysql://<RDSのエンドポイント>/<RDSのDB名>?${!<AWS Secrets Manager シークレット名>}'
        # If set to 'false' data spilled to S3 is encrypted with AES GCM
        DisableSpillEncryption: 'false'
        # This is the name of the lambda function that will be created. This name must satisfy the pattern ^[a-z0-9-_]{1,64}$
        LambdaFunctionName: 'test-athena-mysql-connector'
        # Lambda memory in MB (min 128 - 3008 max).
        LambdaMemory: '3008'
        # (Optional) A custom role to be used by the Connector lambda
        LambdaRoleARN: ' '
        # Maximum Lambda invocation runtime in seconds. (min 1 - 900 max)
        LambdaTimeout: '900'
        # (Optional) An IAM policy ARN to use as the PermissionsBoundary for the created Lambda function's execution role
        PermissionsBoundaryARN: ' '
        # Used to create resource-based authorization policy for "secretsmanager:GetSecretValue" action. E.g. All Athena MySQL Federation secret names can be prefixed with "AthenaMySQLFederation" and authorization policy will allow "arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:AthenaJdbcFederation*". Parameter value in this case should be "AthenaMySQLFederation". If you do not have a prefix, you can manually update the IAM policy to add allow any secret names.
        SecretNamePrefix: 'test'
        # One or more SecurityGroup IDs corresponding to the SecurityGroup that should be applied to the Lambda function. (e.g. sg1,sg2,sg3)
        SecurityGroupIds: 'sg-xxxxxx'
        # The name of the bucket where this function can spill data.
        SpillBucket: 'test-athena-mysql-connector-bucket'
        # The prefix within SpillBucket where this function can spill data.
        # SpillPrefix: 'athena-spill'
        # One or more Subnet IDs corresponding to the Subnet that the Lambda function can use to access you data source. (e.g. subnet1,subnet2)
        SubnetIds: 'subnet-aaaaaa, subnet-bbbbbb'

  # --------------------------------------------------------------
  # Athena
  # --------------------------------------------------------------
  AthenaMysqlDataCatalog:
    Type: AWS::Athena::DataCatalog
    Properties: 
      Name: "test-athena-mysql-datasource"
      Description: Athena - Aurora Mysql DataSource
      Parameters: 
        function: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:test-athena-mysql-connector"
      Type: "LAMBDA"

※ 下記の部分は、"${}"がテンプレート内のパラメータと判定されない為に、"!"でエスケープしています

DefaultConnectionString: "mysql://jdbc:mysql://<RDSのエンドポイント>/<RDSのDB名>?${!<AWS Secrets Manager シークレット名>}"

さいごに

権限やネットワーク周りで引っかかることはあるかもしれませんが、データソースコネクターの作成自体はそれほど難しくないかなと思います。
ネクターを飲んで、データソースコネクターを利用しようと考えてる方の参考になれば幸いです!