PostgreSQL上でのパスワード変更時に認証情報をAWS Secrets Managerに連携するようにしてみました
初めに
現在Amazon RDSではAWS Secrets Manager統合機能を利用してSecrets Managerを活用した認証情報の管理が可能となっております。
こちらを利用することでDBの認証情報でSecrets Managerのパスワードローテーションの恩恵を受けることが可能であり、またアプリ側としてもSecrets Manager上のシークレットを参照していれば認証情報変更の際に特別対応を行う必要がないというのがメリットとなります。
一方でこちらの機能はSecrets Manager主体の管理となるため、アプリ的にSecrets Managerに認証を格納したいけどDB管理者としては今まで通りPostrgreSQL上でSQLを流してやりたいという場合には利用しづらいかもしれません。
今回はそれを実現できるようPostgreSQL側からSecrets Managerにいい感じにパスワードを同期できる様にしてみます。
なお本記事はRDSを利用する形で記載をしておりますが、仕組み上オンプレミス上のPostgreSQL環境などRDS外でも同等のことが実現可能となります(少し変更は必要ですが)。
実装概要
PostgreSQLの拡張機能であるpg_tle
のパスワードチェックフックおよびaws_lambda
を利用します。
こちらを利用してパスワード変更時にlambda関数を呼び出しそこからSecrets Managerに認証情報を登録します。
RDSに割り当てるIAMロールおよびlambda関数はSAMで実装を行い以下に格納をしています。
Lambda関数側の処理としてはほぼシンプルにSecretsを格納しているだけで複雑なことはしていません。
RDSの作成・設定、VPCエンドポイントもしくはNAT Gatewayの作成(プライベートサブネットの場合)は別途手動で行う形を想定しております。
手動設定
上記のSAMによるデプロイとは別にRDS側への設定を行います。
パラメーターグループに以下の値を割り当てます。
パラメータ | 値 | 備考 |
---|---|---|
shared_preload_library | pg_tle | 既存パラメータがある場合そこへの追加 |
pgtle.enable_password_check | on | |
rds.custom_dns_resolution | 1 | VPCエンドポイントを利用する場合 |
またRDSがLambda関数を実行できるようにSAMで作成されるIAMロールを割り当てておきます。
上記実行後以下のSQLを実行しパスワード変更時のフック処理をインストールします。
CREATE EXTENSION aws_lambda CASCADE;
CREATE EXTENSION pg_tle;
SELECT pgtle.install_extension(
'sync_secrets',
'1.0',
'Sync credential to Secrets Manager',
$_pgtle_$
CREATE SCHEMA sync_secrets;
CREATE FUNCTION sync_secrets.hook_function(username text, password text, password_type pgtle.password_types, valid_until timestamptz, valid_null boolean)
RETURNS void AS $$
DECLARE
context json;
BEGIN
context := '{"userName": "'|| hook_function.username ||'", "password": "'|| hook_function.password || '"}';
PERFORM aws_lambda.invoke(
'arn:aws:lambda:ap-northeast-1:xxxxxx:function:pgsql-sync-login-user-info-SyncUserFunction-xxxxxx',
context::json
);
END
$$ LANGUAGE plpgsql;
-- 上記の関数をパスワード変更時のフック処理として登録
SELECT pgtle.register_feature('sync_secrets.hook_function', 'passcheck');
REVOKE ALL ON SCHEMA sync_secrets FROM PUBLIC;
$_pgtle_$,
'{aws_lambda}'
);
上記実行後CREATE EXTENSION
で拡張機能を有効化します。
CREATE EXTENSION sync_secrets;
動作確認
DB側でパスワード変更をフック処理となっておりますので特別な手順は必要なくALTER USER
によるパスワードの変更を行うのみでOKです。
postgres=> ALTER USER postgres WITH PASSWORD 'password';
ALTER ROLE
こうすることで先ほどhook_function
に記載したlambda関数の実行処理が呼び出され、その処理を通してSecretsの書き換えが行われます。
終わりに
パスワードの変更フック処理を活用してDBを起点にSecrets Managerに変更された認証情報を自動で連携するようにしてみました。
DB側の作業は現行通りSQLで行いたい、AWSレイヤーを意識しないでほしいといったようなケースでも利用かつ、アプリ側でSecrets Managerを利用していれば別口での認証情報の引き渡しを不要とし手間を削減することが可能です。
Secrets Managert統合もあくまでシークレットの内容でDB側のパスワードを変えているだけであり、それを無視してDB側でパスワードを変更すると乖離が起きる問題も今回のパスワードフックチェックによる逆方向同期を仕込むことで回避きそうではあります。
(そもそもそれが起きないように制限をかけるべき部分ではありますが...)
一応今回の処理としてはパスワード自体は生でLambdaに引き渡している関係でちょっとしたデバッグでevent
の値を吐き出してしまってパスワードがログ上に露出...ということもあり得るため実際に利用する場合はその辺りをどうにかする必要は出てきそうです。