Masquage des secrets dans Ansible

Les playbooks Ansible ont souvent besoin de mots de passe et de jetons d’API pour se connecter aux serveurs et déployer des applications. Ces valeurs peuvent aussi apparaître dans la sortie des tâches, par exemple lorsqu’une commande renvoie une erreur contenant un mot de passe.

Ansible ajoute le masquage des secrets pour répondre à ce problème. Il remplace les valeurs secrètes connues par $REDACTED$ dans la sortie, tout en laissant le reste du message lisible. Les tâches continuent d’utiliser les valeurs d’origine.

Cette fonctionnalité a été ajoutée par la pull request Secret Masking API, fusionnée le 10 septembre 2026. Au moment de la rédaction de cet article, elle est disponible dans les versions de développement d’ansible-core 2.22. Elle ne fait pas encore partie d’une version stable.

Voyons un playbook simple, puis comment nous prévoyons d’utiliser cette fonctionnalité dans Semaphore UI.

Commençons par enregistrer un secret

Ansible doit savoir quelles valeurs masquer. La nouvelle API enregistre les valeurs provenant de sources de secrets connues, comme les variables chiffrées avec Vault et les paramètres de modules marqués no_log.

Pour une variable ordinaire, nous pouvons utiliser le filtre register_secret. Une variable transmise via --extra-vars doit elle aussi être enregistrée ; l’appeler db_password ne suffit pas.

Pour cet exemple, nous utiliserons un mot de passe de base de données fictif. Créez un playbook nommé masking.yml :

- name: Try secret masking
  hosts: localhost
  gather_facts: false
  vars:
    db_password: "example-db-password-123456"

  tasks:
    - name: Register the password before using it
      ansible.builtin.set_fact:
        db_password: "{{ db_password | ansible.builtin.register_secret }}"

    - name: Show a message containing the password
      ansible.builtin.debug:
        msg: "Connecting to db.internal with password={{ db_password }}"

La première tâche enregistre le mot de passe. Le filtre renvoie la valeur d’origine : le playbook peut donc toujours l’utiliser pour se connecter à la base de données. L’enregistrement doit avoir lieu avant qu’une tâche n’affiche cette valeur.

Exécutez le playbook avec une version de développement d’ansible-core 2.22 :

ansible-playbook -i localhost, -c local masking.yml

La deuxième tâche affichera ce message :

Connecting to db.internal with password=$REDACTED$

Nous affichons ici le mot de passe uniquement pour illustrer le masquage. Dans un véritable playbook, récupérez-le depuis votre source de secrets et évitez d’afficher volontairement les identifiants.

Intégration avec Semaphore UI

Semaphore UI sait déjà quelles variables vous avez marquées comme secrètes. Nous prévoyons d’utiliser cette information dans les futures versions pour enregistrer automatiquement ces valeurs auprès d’Ansible.

Pour cela, nous utiliserons l’option _SECRETS_INPUT_FILES d’Ansible. Elle se configure via la variable d’environnement _ANSIBLE_SECRETS_INPUT_FILES et permet à Ansible de lire une liste de secrets avant le démarrage d’un playbook.

L’entrée peut être au format YAML ou JSON. Un document contenant le mot de passe de notre exemple ressemble à ceci :

version: 1
secrets:
  - example-db-password-123456

Cette liste indique à Ansible ce qu’il doit masquer. Les variables elles-mêmes sont toujours transmises séparément au playbook.

L’intégration prévue couvrira les valeurs secrètes provenant des éléments suivants :

  • Groupes de variables (Variable Groups) — secrets enregistrés pour être utilisés par vos tâches.
  • Questionnaires (Surveys) — réponses secrètes saisies au lancement d’une tâche.

Pour ces valeurs, vous n’aurez pas besoin d’ajouter une tâche register_secret à chaque playbook.

Intégration prévue de Semaphore UI : le secret est transmis au playbook et enregistré séparément via _SECRETS_INPUT_FILES. Les tâches utilisent la valeur réelle, tandis qu’Ansible la remplace par $REDACTED$ dans le journal de la tâche.

Nous avons testé cette approche sur une version de développement d’ansible-core 2.22. Les valeurs enregistrées étaient masquées dans les messages debug, les résultats des commandes, les messages d’erreur, la sortie détaillée et le fichier journal d’Ansible. La transmission de la liste par un tube a également fonctionné, sans écrire de fichier de secrets distinct sur le disque.

Cette option est actuellement interne et peut changer. Sa prise en charge dans Semaphore UI est prévue pour une future version et nécessitera une version compatible d’Ansible.

Exemple : déployer une application

Supposons que nous ayons un modèle de tâche (Task Template) qui déploie une application. Le script de déploiement utilise un jeton d’API enregistré comme secret dans un groupe de variables.

Avec l’intégration prévue, la tâche fonctionnera ainsi :

  1. Semaphore UI transmet le jeton au playbook.
  2. Avant l’exécution, il fournit également le jeton à la liste de masquage d’Ansible via _SECRETS_INPUT_FILES.
  3. Le playbook exécute le script de déploiement avec le véritable jeton.
  4. Si le script inclut ce jeton dans sa sortie, Ansible le masque dans le résultat affiché.

Par exemple, un jeton expiré pourrait produire ce message dans le journal de la tâche :

Deployment rejected: service=payments environment=staging token=$REDACTED$ reason=token expired

Nous pouvons voir quel déploiement a échoué et pourquoi, sans montrer le jeton à toutes les personnes qui lisent le journal. Le même fonctionnement s’appliquera à un jeton temporaire saisi dans un champ secret d’un questionnaire.

Limites

Le masquage fonctionne avec les valeurs enregistrées. L’implémentation en développement ignore les secrets de moins de quatre caractères, et une valeur encodée ou transformée d’une autre manière peut nécessiter un enregistrement distinct.

Le masquage ne protège pas non plus les identifiants dans les arguments des processus, les fichiers écrits par un playbook ou les journaux produits en dehors d’Ansible. Continuez à utiliser no_log: true pour les tâches dont l’intégralité de la sortie doit rester privée.

Avec cette intégration, les secrets marqués dans Semaphore UI seront également connus du système de masquage d’Ansible. Cela aidera à garder les identifiants hors des journaux de tâches tout en conservant des informations utiles pour le diagnostic.