AWS CloudShell内のpsqlとPython(Psycopg)からAurora DSQLに接続してみた
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クラスターを構築し、エンドポイントを控えます。
Active-Active構成で構築した場合、エンドポイントは2つあります。
エンドポイントとリージョンのペアを間違えない限り、どちらのエンドポイントを使っても構いません。
適宜読み替えてください。
2. CloudShell にアクセス
AWS コンソールのメニューから、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=>
参考
- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dsql/generate-db-connect-admin-auth-token.html
- https://docs.aws.amazon.com/aurora-dsql/latest/userguide/authentication-token-cli.html
4. Python(Psycopg)からDSQLに接続
PythonからDSQLに接続する方法は先程のpsqlと同等です。
AWSとの通信にAWS SDK(boto3)、PostgreSQLのワイアプロトコルに Psycopg3 を利用します。
CloudShellにプリインストールされているPythonのバージョンは3.9と少し古いため、uv を使ってより新しいPythonランタイムと関連ライブラリをインストールします。
uv は Rust製のオールインワンなパッケージ・プロジェクト管理ツールです。
$ 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')
接続成功です。
参考