Passer au contenu

Comment gérer la complexité et l'expiration des mots de passe pour les connexions de clusters de bases de données Aurora compatible avec PostgreSQL ?

Lecture de 7 minute(s)
0

Je souhaite gérer la complexité et l'expiration des mots de passe pour les connexions à un cluster de bases de données (DB) Amazon Aurora édition compatible avec PostgreSQL.

Brève description

Pour gérer les mots de passe de votre cluster de bases de données Aurora compatible avec PostgreSQL, vous pouvez utiliser les méthodes suivantes :

Résolution

Utiliser un hook de vérification de mot de passe avec une TLE

Pour utiliser un hook de vérification de mot de passe avec une TLE, vous devez d'abord configurer la TLE dans votre cluster de bases de données Aurora compatible avec PostgreSQL. Puis, créez le hook de vérification du mot de passe.

Remarque : lorsque vous nommez le hook, vous ne pouvez pas utiliser user-password-check-rules.

Exemple de code de hook de vérification de mot de passe :

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_$
);

Remarque : modifiez le code en fonction de vos besoins. Par exemple, vous pouvez ajouter des mots de passe supplémentaires à la table bad_passwords, modifier la longueur de mot de passe requise ou vérifier la complexité du mot de passe.

Pour vérifier si un mot de passe répond aux exigences de longueur, exécutez la commande suivante :

CREATE ROLE user1 PASSWORD '123456';

Sortie attendue :

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)"

Remarque : l'exemple précédent présente une erreur, car le mot de passe doit comporter au moins 8 caractères.

Pour vérifier si un mot de passe est trop courant, exécutez la commande suivante :

CREATE ROLE user1 PASSWORD 'password';

Sortie attendue :

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)"

Remarque : l'exemple précédent présente une erreur, car vous ne pouvez pas utiliser les mots de passe du dictionnaire de mots de passe communs.

Pour vérifier l'expiration du mot de passe, procédez comme suit :

  1. Exécutez la commande suivante pour vérifier à quelle date un utilisateur a modifié son mot de passe pour la dernière fois :

    SELECT * FROM password_check.usertime WHERE user_name = 'user1';

    Sortie attendue :

    user_name | lasttime
    ----------+----------------------------
    user1     | 2025-10-01 18:48:07.319908
    (1 row)
  2. Exécutez la commande suivante pour définir la dernière fois à 91 jours :

    UPDATE password_check.usertime
    SET lasttime = CURRENT_TIMESTAMP - INTERVAL '91 days'
    WHERE user_name = 'user1';

    Sortie attendue :

    UPDATE 1
  3. Exécutez la commande suivante pour vérifier que la dernière date remonte à 91 jours :

    SELECT * FROM password_check.usertime WHERE user_name = 'user1';

    Sortie attendue :

    user_name | lasttime
    ----------+----------------------------
    user1     | 2025-07-02 18:55:36.248913
    (1 row)
  4. Exécutez la commande suivante pour tester la fonction d'expiration du mot de passe :

    ALTER USER user1 WITH PASSWORD 'NewTestPass786!';

    Sortie attendue :

    NOTICE: Password has expired. It must be changed every 90 days. Last change was on 2025-07-02 18:55:36.248913
    ALTER ROLE
  5. Exécutez la commande suivante pour vérifier que le mot de passe utilisateur a changé et la date de dernière mise à jour :

    SELECT * FROM password_check.usertime WHERE user_name = 'user1';

    Sortie attendue :

    user_name | lasttime
    ----------+----------------------------
    user1     | 2025-10-01 19:18:42.028533
    (1 row)

Activez la fonction de gestion des mots de passe restreints

Définissez le paramètre rds.restrict_password_commands sur 1 afin que seuls les utilisateurs de la base de données auxquels vous accordez le rôle rds_password puissent gérer les mots de passe.

Procédez comme suit :

  1. Créez un groupe de paramètres de cluster de bases de données.
  2. Associez le groupe de paramètres du cluster de bases de données à votre cluster de bases de données.
  3. Modifiez le groupe de paramètres du cluster de bases de données pour définir rds.restrict_password_commands sur 1.

Remarque : pour appliquer la modification, vous devez redémarrer votre instance de base de données principale Aurora compatible avec PostgreSQL.

Utiliser l’authentification de base de données IAM

Avec l'authentification de base de données IAM, vous utilisez un jeton d'authentification pour vous connecter à votre cluster de bases de données plutôt qu'un mot de passe.

Pour utiliser l'authentification de base de données IAM, procédez comme suit :

  1. Utilisez l’authentification de base de données IAM.
  2. Créez une politique IAM pour l'accès à la base de données IAM.
  3. Connectez-vous au cluster de base de données en tant qu'utilisateur principal ou en tant qu'utilisateur habilité à créer et à accorder des autorisations.
  4. Accordez le rôle rds_iam à vos utilisateurs.
  5. Utilisez l'authentification IAM pour vous connecter à votre cluster de bases de données.

Créer une politique de mot de passe personnalisée pour les utilisateurs IAM

Pour plus d'informations, consultez la section Définir une politique de mot de passe de compte pour les utilisateurs IAM.

Utiliser Secrets Manager

Utilisez AWS Secrets Manager pour gérer les mots de passe des utilisateurs principaux. Utilisez les clés de condition IAM pour appliquer la gestion par Aurora des mots de passe des utilisateurs principaux.

Pour plus d'informations, consultez la section Gestion des mots de passe avec Amazon Aurora et AWS Secrets Manager.

Informations connexes

Comprendre les rôles et les autorisations de PostgreSQL

Nouveau — Extensions de langage sécurisé pour PostgreSQL sur Amazon Aurora et Amazon RDS

AWS OFFICIELA mis à jour il y a 5 mois