電通総研 テックブログ

電通総研が運営する技術ブログ

TerraformでAmazon Aurora DSQLをデプロイしてみる

はじめまして。XI本部 クラウドイノベーションセンター所属、2年目の米田です。

AWS re:Invent 2024 にて発表され、2025年5月に正式リリースされた「Amazon Aurora DSQL(以下Aurora DSQL)」について触れる機会がありましたので、こちらで共有いたします 。

今回の記事では特に、 Aurora DSQLの仕様や、Terraformを活用したIaC(Infrastructure as Code)化 の観点から、その特徴や実践ポイントをわかりやすく紹介します。
これから Aurora DSQL の導入を検討されている方にとって、少しでも参考になる内容になれば幸いです。

Aurora DSQLとは

Aurora DSQLは、従来のAuroraと比較して、より高可用性なフルマネージドのサーバーレス分散SQLデータベースになります。ここで、フルマネージドサービスとは、ユーザーがインフラ運用を意識せず、AWS が裏で全部管理・自動化してくれるサービスのことを指します。具体的には、Aurora DSQLはクラスター管理や容量計画が不要で、データは自動的に複数AZへ分散されるため、運用負荷の大幅な軽減が期待されます。
AWS公式ドキュメントでも以下のように記載されており、Aurora DSQLが高い可用性とほぼ無制限のスケーラビリティを実現する次世代データベースサービスであることがわかります。

Amazon Aurora DSQL は、トランザクションワークロード用に最適化されたサーバーレスの分散リレーショナルデータベースサービスです。Aurora DSQL は実質的に無制限のスケールを提供し、インフラストラクチャを管理する必要はありません。アクティブ/アクティブ高可用性アーキテクチャは、99.99% の単一リージョンと 99.999% のマルチリージョンの可用性を提供します。
AWS公式ドキュメントより引用)

今回触れるきっかけとなったのは、以下3点にメリットを感じてになります。

1,分散データ処理
単一リージョンで99.99%、マルチリージョンで99.999%の可用性を提供するアクティブ/アクティブ構成の高可用性を実現してくれます。

2,インフラストラクチャの管理が完全に不要
フルマネージドのサーバーレスサービスであるため、パッチ適用/アップグレード/メンテナンス作業が発生せず、バックアップに関してもAWS Backupを利用することで自動化できます。

3,使用量に応じた従量課金制
Aurora DSQLにかかるコストは従量課金制なため、従来のデータベースと比較してコスト効率よく運用することができます。例えば、アクセス頻度がそれほど高くないユースケースでは、常時稼働するインスタンス単位(時間課金)のデータベースと比べて、Aurora DSQL のような使用量に応じた課金モデルの方が、よりコスト効率よく利用できる可能性があります。
具体的にはDPUと呼ばれるデータベースの処理能力単位に比例して課金されるため、実際に利用する際にはCloudwatchやAurora DSQLのダッシュボードから以下のようなDPU消費メトリクスを確認するのが良いでしょう。

  • WriteDPU:Aurora DSQL クラスターの書き込み時に使用したDPU
  • ReadDPU:Aurora DSQL クラスターの読み込み時に使用したDPU
  • ComputeDPU:Aurora DSQL クラスターの計算時に使用したDPU

データベースへの認証

Aurora DSQLへアクセスするにあたって、誰でもアクセスできてしまってはセキュリティ上好ましくありません。そこで重要になってくるのがデータベースロールトークン認証です。

データベースロール

データベースロールとは、その名のとおり実際にデータベースを操作するために必要なロールで、これはIAMロールとはまた別物である点に注意してください。
データベースロールは、全てのアクションが可能なAdminロールと、ユーザが定義した範囲内でアクションが可能なカスタムロールの、2つに分けられます。とりあえずAdminロールを使用してアクセスすれば全てのテーブル操作が可能ですが、AWSのベストプラクティスに則ってセキュリティ面を考慮すると、必要最低限のアクションを定義したカスタムロールを使用するべきです。
以下の表に、データベースロールごとの主な違いをまとめました。

データベースロール 権限範囲 主な操作 推奨用途
Adminロール 全権限 CREATE、DROP、SELECT、INSERT、UPDATE、DELETE等全て 管理者や全てのテーブルにアクセスする必要のあるリソースに対して利用
カスタムロール ユーザー定義 必要な操作のみ許可 Aurora DSQL操作を必要最低限に抑えたい場合に利用


カスタムロールはDSQLクラスタ内部で作成します。作成した後はIAMロールと紐づけることで、紐づけ先IAMロールにDB操作権限を紐づけることができます。
※Adminロールはデフォルトで存在しており、作成したり紐づけたりといった作業は不要です

トークン認証

IAMロールをデータベースロールに紐づけたので、そのIAMロールを用いてAurora DSQLにアクセスしてみよう、と思うかもしれませんが、それではうまくいきません。
実際はAurora DSQLの認証にはトークが必要になります。ややこしいかもしれませんが、IAMロールを用いて可能なのはあくまでもAurora DSQLのトークンの取得であり、実際にデータベースへアクセスするにはそのトークンを使用した認証が必要になります。
トークンを取得する方法は2通りあり、一つはAdmin権限として取得する方法(Adminロール)、もう一つはカスタムロールで定義した権限内の操作のみを許可するトークンを取得する方法(カスタムロール)です。後者の場合の私なりのイメージを図にしました。

Admin権限トークンをリクエストする場合と、紐づけたカスタムロールで定義した権限トークンをリクエストする場合とで、エンドポイントが異なります(以下CLIでの実行例)

# Adminの場合
aws dsql generate-db-connect-admin-auth-token \
  --hostname <DSQL Endpoint> \
  --region ap-northeast-1 \
  --expires-in 3600 #トークン期限

# カスタムロールの権限内に限定したトークン取得の場合
aws dsql generate-db-connect-auth-token \
  --hostname <DSQL Endpoint> \
  --region ap-northeast-1 \
  --expires-in 3600 

同様に、IAMロールにアタッチしておくべきアクションもデータベースロールによって異なります。Adminとしてトークンを取得する場合はdsql:DbConnectAdminアクションが必要となる一方で、IAMロールに紐づけたカスタムロールに権限を絞る場合はdsql:DbConnectアクションが必要となります。

取得したトークンを用いてAurora DSQLに接続し、クエリを実行することで必要な操作を実現します。
このように、IAM認証とトークン認証を組み合わせることで、セキュアにAurora DSQLへアクセスすることが可能になります。

IaC化してみる

ここまでの流れを実際にIaC化してみようと思います。実装にはTerraformを利用し、プロバイダーはTerraform公式のAWS Providerを用いることにします。
今回はAurora DSQLクラスタと、データ取得・更新を実施するLambda関数というめちゃくちゃ簡単なアーキテクチャをTerraformで用意してみました。

今回利用する環境は以下のとおりです

  • provider:hashicorp/aws
  • version:v6.14.1

まず、クラスタの作成にはTerraformのAWS Providerでサポートされているaws_dsql_clusterリソースを利用します。

resource "aws_dsql_cluster" "this" {
  deletion_protection_enabled = true
  tags = {
    Name = "BlogCluster"
  }
}
  • シングルリージョン
  • 削除保護の有効化
  • タグ設定:TestCluster

次にLambdaにアタッチする実行ロールを作成します。(Lambda関数自体の作成は割愛し、ここではIAMロールの作成だけを記載してます)

data "aws_iam_policy_document" "dsql_role_assume_role" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }
  }
}

data "aws_iam_policy_document" "dsql_role" {
  statement {
    effect = "Allow"
    actions = ["dsql:DbConnect"]
    resources = ["<DSQL Endpoint>"]
  }
}

resource "aws_iam_role" "dsql_role" {
  name               = "dsql-blog-role"
  assume_role_policy = data.aws_iam_policy_document.dsql_role_assume_role.json
}

resource "aws_iam_role_policy_attachment" "dsql_role" {
  role       = aws_iam_role.dsql_role.name
  policy_arn = aws_iam_policy.dsql_role.arn
}

resource "aws_iam_policy" "dsql_role" {
  name   = "dsql-blog-policy"
  policy = data.aws_iam_policy_document.dsql_role.json
}

最後にAurora DSQLでカスタムロールの作成とIAMロールへの紐づけを実施します。マッピング対象のIAMロールは、今回はLambda関数の実行ロールになります。Aurora DSQLへの接続はAWSコンソールより可能で、Cloudshell上でクエリを実行できます。


以下はblog_userというカスタムロールを作成する流れです。

# blog_userというカスタムロールを作成
CREATE ROLE 'blog_user' WITH LOGIN;
# カスタムロールとIAMロールのマッピング
AWS IAM GRANT 'blog_user' TO '<Lambda IAM Role ARN>';
# カスタムロールにprivateスキーマへのアクセス権限を付与
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA private TO 'blog_user';

ただ、コンソールからの手動作成ではなく、実際はIaCの実行と同時に自動でクエリも実行されることが望ましいと思います。それにより、運用の負担を軽減し、ヒューマンエラーの低減が期待できます。

そこで今回は、Terraformの実行と組み合わせて、自動でカスタムロール作成まで実施してくれるように実装してみました。具体的にはTerraform実行時に外部スクリプトを呼び出し、リソースの構築と同時にスクリプトで定義したクエリを実行する、といったものです。
以下実装コードになります。

resource "terraform_data" "this" {
  triggers_replace = {
    cluster_id  = aws_dsql_cluster.this.identifier
    file_sha256 = filebase64sha256("${path.module}/scripts/dsql.sh")
  }

  #shell scriptを呼び出して実行
  provisioner "local-exec" {
    command = "sh ${path.module}/scripts/dsql.sh"
  }
}
#!/bin/bash

# トークン生成
export PGPASSWORD=$(aws dsql generate-db-connect-admin-auth-token \
  --expires-in 3600 \
  --region ap-northeast-1 \
  --hostname <DSQL Endpoint>)
export PGSSLMODE=require

# psql でロール作成
psql --dbname postgres --username admin --host <DSQL Endpoint> <<EOF
CREATE ROLE blog_user WITH LOGIN;
AWS IAM GRANT blog_user TO '<IAM Role ARN>';
CREATE SCHEMA IF NOT EXISTS private;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA private TO blog_user;
\q
EOF

あとはterraform init→terraform plan→terraform applyの順でコマンドを実行すれば、DSQLクラスターが自動的にプロビジョニングされ、データベースロールの作成とIAMロールへの紐づけ、アクセス権限の付与までの処理が自動で走ります。
これにより手動での操作が軽減され、より効率的にリソースが作成されるようになりました。

実行結果

Lambdaを呼び出して、Aurora DSQLへの接続と基本的なクエリ実行が正常に動作することを確認します。

クリックして展開

import boto3
import ssl
import pg8000

def lambda_handler(event, context):
    # Aurora DSQL 情報
    dsql_endpoint = "<DSQL Endpoint>"
    aws_region   = "ap-northeast-1"
    
    # トークン生成
    dsql_client = boto3.client('dsql', region_name=aws_region)
    auth_token = dsql_client.generate_db_connect_auth_token(
        Hostname=dsql_endpoint,
        ExpiresIn=900
    )
    
    # SSL 設定
    ssl_context = ssl.create_default_context()
    ssl_context.check_hostname = False
    ssl_context.verify_mode = ssl.CERT_REQUIRED
    
    # データベース接続
    conn = pg8000.connect(
        host=dsql_endpoint,
        database='postgres',
        user='blog_user',
        password=auth_token,
        port=5432,
        ssl_context=ssl_context
    )

    # blogテーブルの内容を取得
    cursor = conn.cursor()
    cursor.execute("""
        SELECT member_id, title, content
        FROM private.blog;
    """)

    columns = [desc[0] for desc in cursor.description]
    rows = cursor.fetchall()
    blogs = [dict(zip(columns, row)) for row in rows]

    cursor.close()
    conn.close()

    return {
        "blogs": blogs
    }

以上を実行すると、事前にprivateスキーマに作成したblogテーブルからデータを取得することができました。

{
  "blogs": [
    {
      "member_id": 1,
      "title": "はじめての投稿",
      "content": "これは最初のブログ記事です。"
    },
    {
      "member_id": 2,
      "title": "お知らせ",
      "content": "システムをアップデートしました。"
    },
    {
      "member_id": 3,
      "title": "Tips",
      "content": "PostgreSQLでスキーマを使い分けよう。"
    }
  ]
}

注意すべきポイント

最後に、実際に触ってみてDSQLならではの注意すべき点と感じたポイントをまとめてみました。

  • 接続にはトークン認証が必須になりますが、デフォルトで15分、最大で1週間という期限が設定されています。したがって、定期的にトークンの更新処理が発生します。今回はリクエストの都度トークンを取得してくる想定で実装しましたが、トークンを再利用する場合は注意が必要です。
  • DSQLはPostgreSQLと互換性があり、大変便利なサービスですが、逆に言えばPostgreSQL以外のデータベースシステムとは互換性がありません。ですので、PostgreSQLで対応できない処理に関してはおすすめできません
  • スキーマの作成はAdminロールでしか実施できません。カスタムロールで試行しても、権限不足というエラーメッセージが出力されます。したがって、スキーマ作成者は誤った操作をしないように注意が必要です。
    ただし、本記事でも紹介したようにデータベース操作ごと自動化してしまえば、人的ミスも未然に防ぐことができます。
  • DSQLでは、ALTER TABLE で列の型変更や削除、ユニークキーの追加ができません。したがって、テーブルを編集した場合は、テーブルの削除→新規作成という手順が必要になります。新規作成になるのでテーブル単位の権限を与えていた場合は再度権限を与える必要があります。このことを考えると、カスタムロールに与える権限はスキーマ単位で与えておくのが良いと思います。
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA <スキーマ> TO <カスタムロール>;
  • 部分インデックスがサポートされていないので例えば以下のように特定の条件に一致する行のみにインデックスを作成することができません。(これはなにかと不便ですね。。。)
CREATE INDEX idx_user_id
ON setting_category (category, user_id)
WHERE category = '重要';
  • 1つのトランザクションで変更可能なテーブル行の最大値が3000行となっているようで、それ以上の処理を実施する際にはページングなどが必要になります。

まとめ

本記事では比較的新しいサービスであるAurora DSQLを触ってみた感想をお伝えしました。
PostgreSQL互換ということもあって非常に使いやすく、コストも他のデータベースサービスと比べて比較的安価に利用できるサービスだと思います。
今回はIaC化による構築手順についてメインでお伝えしましたが、今後は運用した中で得られた知見やベストプラクティスについても共有していきたいと思います。
もし今後Aurora DSQLの導入を検討されている方に参考になればと思います。

参考文献

https://qiita.com/har1101/items/7dd1a6d803e48e3e0525
https://docs.aws.amazon.com/ja_jp/aurora-dsql/latest/userguide/what-is-aurora-dsql.html
https://docs.aws.amazon.com/ja_jp/aurora-dsql/latest/userguide/SECTION_authentication-token.html
https://docs.aws.amazon.com/ja_jp/aurora-dsql/latest/userguide/using-database-and-iam-roles.html

執筆:@yoneda.kosuke
レビュー:@kobayashi.hinami
Shodoで執筆されました