如何管理 Aurora PostgreSQL 兼容版数据库集群连接的密码复杂性和到期时间?
我想管理 Amazon Aurora PostgreSQL 兼容版数据库 (DB) 集群连接的密码复杂性和到期时间。
简短描述
要管理 Aurora PostgreSQL 兼容版数据库集群的密码,您可以使用以下方法:
- 使用可信语言扩展 (TLE) 创建密码检查钩子。
- 开启受限密码管理功能。
- 使用 AWS Identity and Access Management (IAM) 数据库身份验证。
- 为 IAM 用户创建自定义密码策略。
- 使用 AWS Secrets Manager。
解决方法
在 TLE 中使用密码检查钩子
要在 TLE 中使用密码检查钩子,必须先在 Aurora PostgreSQL 兼容版数据库集群中设置 TLE。然后,创建密码检查钩子。
**注意:**为钩子命名时,不能使用 user-password-check-rules。
密码检查钩子代码示例:
SELECT pgtle.install_extension( 'user-password-check-rules', '1.0', 'Do not let users use the 10 most commonly used passwords', $_pgtle_$ CREATE SCHEMA password_check; REVOKE ALL ON SCHEMA password_check FROM PUBLIC; GRANT USAGE ON SCHEMA password_check TO PUBLIC; -- Create table for bad passwords CREATE TABLE password_check.bad_passwords (plaintext) AS VALUES ('123456'), ('password'), ('12345678'), ('qwerty'), ('123456789'), ('12345'), ('1234'), ('111111'), ('1234567'), ('dragon'); -- Create table for tracking user password changes CREATE TABLE password_check.usertime ( user_name text PRIMARY KEY, lasttime timestamp ); CREATE UNIQUE INDEX ON password_check.bad_passwords (plaintext); CREATE FUNCTION password_check.passcheck_hook(username text, password text, password_type pgtle.password_types, valid_until timestamptz, valid_null boolean) RETURNS void AS $$ DECLARE invalid bool := false; userexists bool; last_password_change timestamp; BEGIN -- Check if user already exists SELECT EXISTS (SELECT user_name FROM password_check.usertime WHERE user_name = username) INTO userexists; -- If user exists, check password age IF (userexists) THEN SELECT lasttime INTO last_password_change FROM password_check.usertime WHERE user_name = username; -- Check if password is older than 90 days IF (CURRENT_TIMESTAMP - last_password_change) > INTERVAL '90 days' THEN RAISE EXCEPTION 'Password has expired. It must be changed every 90 days. Last change was on %', last_password_change; END IF; -- Update timestamp for new password change UPDATE password_check.usertime SET lasttime = CURRENT_TIMESTAMP WHERE user_name = username; ELSE -- First time user, add to tracking table INSERT INTO password_check.usertime VALUES(username, CURRENT_TIMESTAMP); END IF; -- Existing password length check IF length(password) < 8 THEN RAISE EXCEPTION 'Password must be at least 8 characters long.'; END IF; -- Existing common password check IF password_type = 'PASSWORD_TYPE_MD5' THEN SELECT EXISTS( SELECT 1 FROM password_check.bad_passwords bp WHERE ('md5' || md5(bp.plaintext || username)) = password ) INTO invalid; IF invalid THEN RAISE EXCEPTION 'Cannot use passwords from the common password dictionary'; END IF; ELSIF password_type = 'PASSWORD_TYPE_PLAINTEXT' THEN SELECT EXISTS( SELECT 1 FROM password_check.bad_passwords bp WHERE bp.plaintext = password ) INTO invalid; IF invalid THEN RAISE EXCEPTION 'Cannot use passwords from the common password dictionary'; END IF; END IF; -- Existing complexity check IF NOT (password ~ '[A-Z]' AND password ~ '[a-z]' AND password ~ '[0-9]' AND password ~ '[^a-zA-Z0-9]') THEN RAISE EXCEPTION 'Password must contain uppercase letters, lowercase letters, numbers, and special characters'; END IF; END $$ LANGUAGE plpgsql SECURITY DEFINER; GRANT EXECUTE ON FUNCTION password_check.passcheck_hook TO PUBLIC; SELECT pgtle.register_feature('password_check.passcheck_hook', 'passcheck'); $_pgtle_$ );
**注意:**请根据您的需求修改代码。例如,您可以向 bad_passwords 表中添加更多密码,更改密码长度要求,或检查密码复杂性。
要检查密码是否符合长度要求,请运行以下命令:
CREATE ROLE user1 PASSWORD '123456';
预期输出:
ERROR: Password must be at least 8 characters long. CONTEXT: PL/pgSQL function password_check.passcheck_hook(text,text,pgtle.password_types,timestamptz,bool) SQL statement "SELECT password_check.passcheck_hook($1::pg_catalog.text, $2::pg_catalog.text, $3::pgtle.password_types, $4::pg_catalog.timestamptz, $5::pg_catalog.bool)"
**注意:**上述示例表明存在错误,因为密码长度必须至少为八个字符。
要检查密码是否过于常见,请运行以下命令:
CREATE ROLE user1 PASSWORD 'password';
预期输出:
ERROR: Cannot use passwords from the common password dictionary CONTEXT: PL/pgSQL function password_check.passcheck_hook(text,text,pgtle.password_types,timestamptz,bool) SQL statement "SELECT password_check.passcheck_hook($1::pg_catalog.text, $2::pg_catalog.text, $3::pgtle.password_types, $4::pg_catalog.timestamptz, $5::pg_catalog.bool)"
**注意:**上述示例表明存在错误,因为您无法使用通用密码词典中的密码。
要检查密码的到期时间,请完成以下步骤:
-
运行以下命令,查看用户上次更改密码的时间:
SELECT * FROM password_check.usertime WHERE user_name = 'user1';预期输出:
user_name | lasttime ----------+---------------------------- user1 | 2025-10-01 18:48:07.319908 (1 row) -
运行以下命令,将上次更改时间设置为 91 天前:
UPDATE password_check.usertime SET lasttime = CURRENT_TIMESTAMP - INTERVAL '91 days' WHERE user_name = 'user1';预期输出:
UPDATE 1 -
运行以下命令,检查上次更改时间是否已设为 91 天前:
SELECT * FROM password_check.usertime WHERE user_name = 'user1';预期输出:
user_name | lasttime ----------+---------------------------- user1 | 2025-07-02 18:55:36.248913 (1 row) -
运行以下命令,测试密码到期功能:
ALTER USER user1 WITH PASSWORD 'NewTestPass786!';预期输出:
NOTICE: Password has expired. It must be changed every 90 days. Last change was on 2025-07-02 18:55:36.248913 ALTER ROLE -
运行以下命令,验证用户密码是否已更改及上次更改时间是否已更新:
SELECT * FROM password_check.usertime WHERE user_name = 'user1';预期输出:
user_name | lasttime ----------+---------------------------- user1 | 2025-10-01 19:18:42.028533 (1 row)
开启受限密码管理功能
将 rds.restrict_password_commands 参数设置为 1,以便仅允许授予 rds_password 角色的数据库用户管理密码。
完成以下步骤:
- 创建数据库集群参数组。
- 将数据库集群参数组与您的数据库集群相关联。
- 修改数据库集群参数组,将 rds.restrict_password_commands 设置为 1。
**注意:**要应用此更改,您必须重启 Aurora PostgreSQL 兼容版主数据库实例。
使用 IAM 数据库身份验证
使用 IAM 数据库身份验证,您可以使用身份验证令牌连接到数据库集群,而无需使用密码。
要使用 IAM 数据库身份验证,请完成以下步骤:
- 开启 IAM 数据库身份验证。
- 为 IAM 数据库访问创建 IAM 策略。
- 以主用户或可以创建和授予权限的用户身份连接到数据库集群。
- 向用户授予 rds_iam 角色。
- 使用 IAM 身份验证连接到您的数据库集群。
为 IAM 用户创建自定义密码策略
有关更多信息,请参阅为 IAM 用户设置账户密码策略。
使用 Secrets Manager
使用 AWS Secrets Manager 管理主用户密码。使用 IAM 条件键强制执行 Aurora 对主用户密码的管理。
有关更多信息,请参阅使用 Amazon Aurora 和 AWS Secrets Manager 进行密码管理。
