Ce texte ne traite pas des clés et salts de sécurité WordPress, un sujet déjà couvert côté sécurité. Il s’agit ici spécifiquement du mot de passe de connexion à la base de données MySQL ou MariaDB, celui que WordPress utilise via wp-config.php pour dialoguer avec ses tables. Sur un parc de sites gérés depuis plusieurs années, ce mot de passe reste souvent identique depuis la création initiale du site, une pratique que l’agence a décidé de corriger avec une rotation automatisée tous les trois mois.
Le défi technique n’est pas de changer un mot de passe MySQL, une opération triviale en soi, mais de le faire sans interrompre le service : entre le moment où le mot de passe change côté base de données et le moment où wp-config.php est mis à jour avec la nouvelle valeur, le site ne doit jamais se retrouver dans un état où l’ancien mot de passe ne fonctionne plus alors que le nouveau n’est pas encore appliqué.
Le principe du compte transitoire
Plutôt que de changer directement le mot de passe du compte utilisé en production, ce qui créerait fatalement une fenêtre d’indisponibilité même brève, la rotation crée un second compte MySQL avec les mêmes droits, active la bascule de WordPress vers ce nouveau compte, vérifie que tout fonctionne, puis supprime l’ancien compte. À aucun moment les deux comptes ne cessent tous les deux de fonctionner simultanément.
Le script de rotation
#!/usr/bin/env bash
set -euo pipefail
SITE=$1
DB_NAME="wp_${SITE}"
NOUVEAU_USER="wp_${SITE}_$(date +%Y%m%d)"
NOUVEAU_MDP=$(openssl rand -base64 24)
ANCIEN_USER=$(grep DB_USER "/var/www/${SITE}/wp-config.php" | cut -d"'" -f4)
echo "Création du nouveau compte ${NOUVEAU_USER}..."
mysql -e "
CREATE USER '${NOUVEAU_USER}'@'localhost' IDENTIFIED BY '${NOUVEAU_MDP}';
GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${NOUVEAU_USER}'@'localhost';
FLUSH PRIVILEGES;
"
echo "Mise à jour de wp-config.php..."
wp config set DB_USER "${NOUVEAU_USER}" --path="/var/www/${SITE}" --allow-root
wp config set DB_PASSWORD "${NOUVEAU_MDP}" --path="/var/www/${SITE}" --allow-root
echo "Vérification de la connexion..."
if wp db check --path="/var/www/${SITE}" --allow-root; then
echo "Connexion validée avec le nouveau compte."
else
echo "ÉCHEC : rollback vers l'ancien compte."
wp config set DB_USER "${ANCIEN_USER}" --path="/var/www/${SITE}" --allow-root
exit 1
fi

Supprimer l’ancien compte après un délai de sécurité
Le script ci-dessus s’arrête volontairement après la vérification, sans supprimer immédiatement l’ancien compte. Un second script, exécuté vingt-quatre heures plus tard via une entrée cron distincte, supprime l’ancien compte seulement si le site répond toujours correctement dans l’intervalle :
#!/usr/bin/env bash
set -euo pipefail
SITE=$1
ANCIEN_USER=$2
STATUT=$(curl -s -o /dev/null -w "%{http_code}" "https://${SITE}/")
if [ "$STATUT" = "200" ]; then
mysql -e "DROP USER IF EXISTS '${ANCIEN_USER}'@'localhost';"
echo "Ancien compte ${ANCIEN_USER} supprimé."
else
echo "Site en erreur (${STATUT}), suppression de l'ancien compte reportée."
exit 1
fi
Pourquoi ce délai de vingt-quatre heures
Ce délai laisse le temps à un job planifié ou un script tiers, oublié dans la documentation d’un ancien prestataire et exécuté seulement une fois par jour, de révéler qu’il utilisait encore l’ancien compte directement plutôt que de lire wp-config.php. Sur un parc de sites hérités, ce genre de script orphelin existe plus souvent qu’on ne le pense.
Faire tourner la rotation sur tout le parc, un site à la fois
Un script orchestrateur appelle la rotation site par site, avec une pause entre chaque exécution, pour ne jamais avoir plusieurs sites en cours de bascule simultanée, ce qui limiterait l’exposition en cas de bug non détecté dans le script lui-même :
while IFS= read -r site; do
echo "=== Rotation pour ${site} ==="
./rotation-identifiants.sh "$site" || {
echo "Échec sur ${site}, passage au suivant."
continue
}
sleep 60
done < /opt/scripts/liste-sites.txt
Enregistrer le nouveau mot de passe dans le coffre de secrets
Une fois la rotation confirmée réussie, le script met également à jour la valeur correspondante dans le coffre de secrets de l'équipe, pour que toute personne devant se connecter manuellement à la base retrouve toujours l'identifiant courant sans avoir à lire wp-config.php directement sur le serveur :
op item edit "${SITE}-db-production" password="${NOUVEAU_MDP}" --vault=deploiement-production
Fréquence retenue et ses limites
Un intervalle de quatre-vingt-dix jours a été retenu comme compromis entre la fréquence recommandée par les référentiels de sécurité classiques et la charge opérationnelle de surveillance de chaque rotation. Une rotation plus fréquente, par exemple mensuelle, multiplierait les fenêtres à surveiller sans bénéfice de sécurité proportionnel pour la majorité des sites du parc, qui ne traitent pas de données à très haute sensibilité.
Un mot de passe de base de données qui n'a jamais changé depuis la création du site n'est pas un secret, c'est une information publique qui attend simplement d'être découverte.
En résumé
Cette rotation automatisée, construite autour d'un compte transitoire et d'une vérification avant suppression de l'ancien compte, tourne désormais sans incident depuis plusieurs cycles sur le parc de l'agence. Le principal bénéfice ne se mesure pas en incidents évités visibles, mais en réduction de la fenêtre d'exploitation possible d'un identifiant qui aurait fuité sans que personne ne s'en aperçoive.