AWS CloudShell内のpsqlとPython(Psycopg)からAurora DSQLに接続してみた

AWS CloudShell内のpsqlとPython(Psycopg)からAurora DSQLに接続してみた

Clock Icon2024.12.16

Aurora DSQLはマルチリージョン対応のデータベースで、DynamoDBのようにインターネット経由でアクセスします。

本記事では、AWSのマネジメントコンソールに統合されているリージョナルなターミナル環境「AWS CloudShell」を利用し、psqlとPython(Psycopg)経由でAurora DSQLに接続する方法を紹介します。

この構成のメリットは以下です

  • AWS CloudShellは無料で利用可能
  • AWS CloudShellはリージョナルリソース
  • AWS CloudShellにはAWS CLIもpsqlもデフォルトでインストールされている
  • Aurora DSQLはCloudShellもインターネット経由で通信するので、ネットワークのことを考えなくて良い

Aurora DSQL接続の注意点

Aurora DSQLのワイアプロトコルはPostgreSQLです。

Aurora DSQLに接続する際、以下の3つに注意ください

  • 一時トークンの取得が必要
    • 従来のAurora/RDSと異なり、DSQLのクラスター構築時にパスワードの設定欄がありません。DSQLでは、有効期限付きのトークンをAWS API経由で取得します。
  • TLS通信必須
    • インターネット経由での通信ということもあり、TLS通信が必須です。
  • ユーザー名とデータベース名が固定
    • ユーザー名(postgres)とデータベース名(postgres)が固定されています。

この3点に注意すれば、PostgreSQLと同じ感覚でDSQLと接続できます。

1. Aurora DSQLクラスターを構築

コンソールからAurora DSQLクラスターを構築し、エンドポイントを控えます。

dsql-endpoint

Active-Active構成で構築した場合、エンドポイントは2つあります。
エンドポイントとリージョンのペアを間違えない限り、どちらのエンドポイントを使っても構いません。
適宜読み替えてください。

2. CloudShell にアクセス

AWS コンソールのメニューから、CloudShellを起動します。

cloudshell

AWS CLIとPostgreSQLクライアント(psql)がインストール済みであることを確認します。

$ aws --version
aws-cli/2.22.12 Python/3.12.6 Linux/6.1.115-126.197.amzn2023.x86_64 exec-env/CloudShell exe/x86_64.amzn.2023

$ psql --version
psql (PostgreSQL) 15.9

なお、CloudShellにプリインストールされるソフトウェアは、自動的にアップデートも行われます。

参考 https://docs.aws.amazon.com/cloudshell/latest/userguide/vm-specs.html

3. psql からDSQLに接続

まずはPostgreSQLクライアント(psql)からDSQLに接続します。

一時トークン取得のために、以下の引数でAPIを実行します

  • エンドポイント(--hostname)
  • そのエンドポイントのリージョン(--region)
  • トークンの有効期間(--expires-in)
$ export HOST=xxx.dsql.us-east-1.on.aws
$ aws dsql generate-db-connect-admin-auth-token \
  --region us-east-1 \
  --expires-in 3600 \
  --hostname $HOST

caabtv4vbsxldsnxd3nzelop4a.dsql.us-east-1.on.aws/?Action=DbConnectAdmin&...&X-Amz-Signature=xxx

この一時トークンとともにTLS通信でエンドポイントに通信します。

$ export PGPASSWORD=$(aws dsql generate-db-connect-admin-auth-token \
--region us-east-1 \
--expires-in 3600 \
--hostname $HOST)

$ export PGSSLMODE=require

$ psql \
--username admin \
--dbname postgres \
--host $HOST

psql (15.9, server 16.5)
WARNING: psql major version 15, server major version 16.
         Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_128_GCM_SHA256, compression: off)
Type "help" for help.

postgres=> 

参考

4. Python(Psycopg)からDSQLに接続

PythonからDSQLに接続する方法は先程のpsqlと同等です。

AWSとの通信にAWS SDK(boto3)、PostgreSQLのワイアプロトコルに Psycopg3 を利用します。

CloudShellにプリインストールされているPythonのバージョンは3.9と少し古いため、uv を使ってより新しいPythonランタイムと関連ライブラリをインストールします。

uv は Rust製のオールインワンなパッケージ・プロジェクト管理ツールです。

https://docs.astral.sh/uv/

$ curl -LsSf https://astral.sh/uv/install.sh | sh
downloading uv 0.5.9 x86_64-unknown-linux-gnu
no checksums to verify
installing to /home/cloudshell-user/.local/bin
  uv
  uvx
everything's installed!

Python 3.13 でDSQL用の環境を作成し、boto3(一時トークン取得のため)とPsycopg(PostgreSQLプロトコルのため)をインストールします。

$ uv init dsql -p 3.13
Initialized project `dsql` at `/home/cloudshell-user/dsql`

$ cd dsql

$ uv add boto3 "psycopg[binary]>=3"

次に、ドキュメントのサンプルコードを参考に、接続コードを用意します。

コード内の以下は適宜修正してください

  • リージョン : region = 'us-east-1'
  • エンドポイント : cluster_endpoint = "xxx.dsql.us-east-1.on.aws"
import psycopg
import boto3

def main(cluster_endpoint):
    region = 'us-east-1' # XXX

    # Generate a password token
    client = boto3.client("dsql", region_name=region)
    password_token = client.generate_db_connect_admin_auth_token(cluster_endpoint, region)

    conn = psycopg.connect(
        dbname='postgres',
        user='admin',
        host=cluster_endpoint,
        password=password_token,
        sslmode='require',
        autocommit=True,
    )

    cur = conn.cursor()

    cur.execute(b"""
        CREATE TABLE IF NOT EXISTS owner(
            id uuid NOT NULL DEFAULT gen_random_uuid(),
            name varchar(30) NOT NULL,
            city varchar(80) NOT NULL,
            telephone varchar(20) DEFAULT NULL,
            PRIMARY KEY (id))"""
        )

    # Insert some rows
    cur.execute("INSERT INTO owner(name, city, telephone) VALUES('John Doe', 'Anytown', '555-555-1999')")

    cur.execute("SELECT * FROM owner WHERE name='John Doe'")
    row = cur.fetchone()

    print(row)

    # Placing this cleanup the table after the example. If we run the example
    # again we do not have to worry about data inserted by previous runs
    cur.execute("DELETE FROM owner where name = 'John Doe'")

if __name__ == "__main__":
    # Replace with your own cluster's endpoint
    cluster_endpoint = "xxx.dsql.us-east-1.on.aws" # XXX
    main(cluster_endpoint)

ドキュメント通りに sslmode=verify-full とすると、ホスト名がIPv6で解決されて接続エラーになったため、sslmode=require に変更しています。

最後に uv 経由で実行します

$ uv run test.py
(UUID('c26dd462-23d9-4241-9812-fcace766d5f3'), 'John Doe', 'Anytown', '555-555-1999')

接続成功です。

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.