RDS PostgreSQL でパスワードポリシーを設定する方法を教えて下さい

RDS PostgreSQL でパスワードポリシーを設定する方法を教えて下さい

Clock Icon2025.03.07

困っていること

RDS PostgreSQL (Aurora PostgreSQL 含む) で、以下のようなパスワードポリシーを設定する方法を教えてください。

  • n 文字以上
  • 小文字英字、大文字英字、数字、記号のうち n 種以上
  • 有効期限 n 日以内
  • 直近 n 回以内のパスワードの再利用不可

どう対応すればいいの?

パスワードの有効期限に関してのみ、 VALID UNTIL を利用することで設定することが可能です。
それ以外のポリシーに関しては標準機能での設定方法がないため、 TLE 拡張機能の利用を検討する必要があります。

本記事では、 TLE 拡張機能を利用してパスワードポリシーを実装する例を以下にご紹介します。
なお、「直近 n 回以内のパスワードの再利用不可」については、こちらの記事がより詳しいため、それ以外の実装方法について説明いたします。

pg_tle 1.3.0で実装されたパスワードチェックフックを利用してRDS for PostgreSQLで直近利用したパスワードへの変更制限を実装してみました | DevelopersIO

前提条件

利用可能バージョン

TLE 拡張機能が利用可能なバージョンは RDS PostgreSQL 及び Aurora PostgreSQL でそれぞれ以下の通りです。

  • RDS PostgreSQL
    • バージョン 16.1 以降のバージョン 16
    • バージョン 15.2 以降のバージョン 15
    • バージョン 14.5 以降のバージョン 14
    • バージョン 13.12 以降のバージョン 13
  • Aurora PostgreSQL
    • バージョン 14.5 以降

設定するロールの権限

TLE 拡張機能を利用したパスワードポリシーの実装には、 rds_superuser 権限を持つロールでの操作が必要となります。

カスタム DB パラメータグループの利用

以下のパラメータをカスタム DB パラメータグループに設定する必要があります。

  • shared_preload_library
    • 値に pg_tle を追加する。既存の値があればカンマ区切りで追加
    • 静的パラメータのため、変更時には再起動が必要
  • pgtle.enable_password_check
    • 値に on を追加する
    • 動的パラメータのため、変更時の再起動は不要

やってみた

拡張機能の設定

まずは DB インスタンスに接続し、以下のクエリを実行した結果に pg_tle が含まれ、 TLE 拡張機能が利用可能なことを確認します。

postgres=> SHOW shared_preload_libraries;
            shared_preload_libraries             
-------------------------------------------------
 rdsutils,pg_tle,pg_stat_statements,writeforward
(1 row)

次に、以下のクエリを実行して TLE 拡張機能を有効化します。

CREATE EXTENSION pg_tle;

次に、以下のクエリを実行し、変更しようとしたパスワードがパスワードポリシーを満たすかを確認する関数を持つフックを設定します。

以下の例では、パスワードの文字数は 8 文字以上、文字種数は小文字英字、大文字英字、数字、記号のうち 3 種類以上、有効期限は 90 日以内と設定しています。ここの値は要件に応じて適宜変更してください。

SELECT pgtle.install_extension(
  'passwordcheck',
  '1.0',
  'Password policy enforcement functions',
  $_pgtle_$
    CREATE SCHEMA passwordcheck;
    REVOKE ALL ON SCHEMA passwordcheck FROM PUBLIC;
    GRANT USAGE ON SCHEMA passwordcheck TO PUBLIC; -- 注意: 検証のために広めの権限付与を行っています

    CREATE OR REPLACE FUNCTION passwordcheck.passwordcheck_hook(
      username text,
      password text,
      password_type pgtle.password_types,
      valid_until timestamptz,
      valid_null boolean
    )
    RETURNS void AS
    $$
    DECLARE
      min_length INT := 8;              -- 最小文字数
      min_categories INT := 3;          -- 必要な文字種別数
      password_max_age INT := 90;       -- パスワード有効期限(日数)
      categories INT := 0;
    BEGIN
      -- 文字長チェック
      IF length(password) < min_length THEN
        RAISE EXCEPTION 'パスワードは少なくとも % 文字以上である必要があります', min_length;
      END IF;

      -- 文字種別チェック
      IF password ~ '[a-z]' THEN categories := categories + 1; END IF;
      IF password ~ '[A-Z]' THEN categories := categories + 1; END IF;
      IF password ~ '[0-9]' THEN categories := categories + 1; END IF;
      IF password ~ '[!#%&()*+,\-.\/;<=>?@[\]\^_{|}-]' THEN categories := categories + 1; END IF;

      IF categories < min_categories THEN
        RAISE EXCEPTION 'パスワードは少なくとも % 種類の文字(小文字、大文字、数字、記号)を含む必要があります', min_categories;
      END IF;

      -- パスワード有効期限チェック
      IF valid_null THEN
        RAISE EXCEPTION 'パスワードには有効期限を設定する必要があります(最大 % 日間)', password_max_age;
      END IF;

      IF valid_until IS NOT NULL AND valid_until > now() + (password_max_age || ' days')::interval THEN
        RAISE EXCEPTION 'パスワードの有効期限は最大 % 日間です', password_max_age;
      END IF;
    END;
    $$ LANGUAGE plpgsql SECURITY DEFINER;

    GRANT EXECUTE ON FUNCTION passwordcheck.passwordcheck_hook TO PUBLIC;
    SELECT pgtle.register_feature('passwordcheck.passwordcheck_hook', 'passcheck');
  $_pgtle_$
);

あとは、拡張機能を有効化すれば設定完了です。

CREATE EXTENSION passwordcheck;

動作確認

8 文字未満のパスワードが設定できないことを確認します。

postgres=> CREATE ROLE test_role PASSWORD 'W0rd';
ERROR:  パスワードは少なくとも 8 文字以上である必要があります

次に、文字種が 3 種類未満のパスワードが設定できないことを確認します。

postgres=> CREATE ROLE test_role PASSWORD 'passw0rd';
ERROR:  パスワードは少なくとも 3 種類の文字(小文字、大文字、数字、記号)を含む必要があります

次に、有効期限が未設定のパスワードが設定できないことを確認します。

postgres=> CREATE ROLE test_role PASSWORD 'Passw0rd';
ERROR:  パスワードには有効期限を設定する必要があります(最大 90 日間)

次に、有効期限が 90 日を超えたパスワードが設定できないことを確認します。

postgres=> CREATE ROLE test_role PASSWORD 'Passw0rd' VALID UNTIL '2025-06-06'; -- 記事執筆時点の 91 日後を指定
ERROR:  パスワードの有効期限は最大 90 日間です

最後に、これらのパスワードポリシーをすべて満たしたパスワードが設定できることを確認します。

postgres=> CREATE ROLE test_role PASSWORD 'Passw0rd' VALID UNTIL '2025-06-05';
CREATE ROLE

さいごに

プロジェクトによって TLE 拡張機能の利用可否は変わるとは思いますが、 TLE 拡張機能を利用することで、標準機能のみでは実現できない任意のパスワードポリシーを設定できるほか、クライアント認証の追加等のカスタマイズも実装することができます。 AWS から TLE 拡張機能の利用例としてサンプルコードがいくつか提供されておりますので、合わせて参考にしていただけましたら幸いです。

pg_tle/docs/04_hooks.md at main · aws/pg_tle

参考情報

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.