Enmascaramiento de secretos en Ansible

Los playbooks de Ansible suelen necesitar contraseñas y tokens de API para conectarse a servidores y desplegar aplicaciones. Estos valores también pueden aparecer en la salida de las tareas, por ejemplo, cuando un comando devuelve un error que contiene una contraseña.

Ansible está incorporando el enmascaramiento de secretos para ayudar a resolver este problema. Sustituye los valores secretos conocidos por $REDACTED$ en la salida y mantiene legible el resto del mensaje. Las tareas siguen utilizando los valores originales.

Esta función se añadió mediante la pull request de Secret Masking API, integrada el 10 de septiembre de 2026. En el momento de escribir este artículo, está disponible en las versiones de desarrollo de ansible-core 2.22. Todavía no forma parte de una versión estable.

Veamos un playbook sencillo y, después, cómo planeamos utilizar esta función en Semaphore UI.

Primero, registra un secreto

Ansible necesita saber qué valores debe enmascarar. La nueva API registra valores de fuentes de secretos conocidas, como variables cifradas con Vault y parámetros de módulos marcados con no_log.

Para una variable normal, podemos utilizar el filtro register_secret. Una variable pasada mediante --extra-vars también necesita registrarse; no basta con llamarla db_password.

Para este ejemplo, utilizaremos una contraseña de base de datos ficticia. Crea un playbook llamado 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 primera tarea registra la contraseña. El filtro devuelve el valor original, así que el playbook puede seguir utilizándolo para conectarse a la base de datos. El registro debe realizarse antes de que cualquier tarea muestre el valor.

Ejecuta el playbook con una versión de desarrollo de ansible-core 2.22:

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

La segunda tarea mostrará este mensaje:

Connecting to db.internal with password=$REDACTED$

Aquí mostramos la contraseña únicamente para demostrar el enmascaramiento. En un playbook real, obtén la contraseña de tu fuente de secretos y evita mostrar credenciales deliberadamente.

Integración con Semaphore UI

Semaphore UI ya sabe qué variables has marcado como secretas. Planeamos utilizar esta información en futuras versiones para registrar esos valores en Ansible automáticamente.

Para ello, utilizaremos la opción _SECRETS_INPUT_FILES de Ansible. Se configura mediante la variable de entorno _ANSIBLE_SECRETS_INPUT_FILES y permite a Ansible leer una lista de secretos antes de iniciar el playbook.

La entrada puede estar en YAML o JSON. Un documento con la contraseña de nuestro ejemplo tendría este aspecto:

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

Esta lista indica a Ansible qué debe enmascarar. Las variables se siguen pasando al playbook por separado.

La integración prevista cubrirá los valores secretos de:

  • Grupos de variables (Variable Groups): secretos guardados para utilizarlos en tus tareas.
  • Encuestas (Surveys): respuestas secretas introducidas al iniciar una tarea.

Para estos valores, no será necesario añadir una tarea con register_secret a cada playbook.

Integración prevista de Semaphore UI: el secreto se pasa al playbook y se registra por separado mediante _SECRETS_INPUT_FILES. Las tareas utilizan el valor real, mientras Ansible lo sustituye por $REDACTED$ en el registro de la tarea.

Probamos este enfoque con una versión de desarrollo de ansible-core 2.22. Los valores registrados se enmascararon en mensajes de debug, resultados de comandos, mensajes de error, salida detallada y el archivo de registro de Ansible. También funcionó el envío de la lista a través de una tubería, sin escribir un archivo de secretos separado en disco.

Actualmente, la opción es interna y puede cambiar. La compatibilidad con Semaphore UI está prevista para una versión futura y requerirá una versión compatible de Ansible.

Ejemplo: desplegar una aplicación

Supongamos que tenemos una plantilla de tarea (Task Template) que despliega una aplicación. El script de despliegue utiliza un token de API guardado como secreto en un grupo de variables.

Con la integración prevista, la tarea funcionará así:

  1. Semaphore UI pasa el token al playbook.
  2. Antes de la ejecución, también proporciona el token a la lista de enmascaramiento de Ansible mediante _SECRETS_INPUT_FILES.
  3. El playbook ejecuta el script de despliegue con el token real.
  4. Si el script incluye ese token en su salida, Ansible lo enmascara en el resultado que se muestra.

Por ejemplo, un token caducado podría generar este mensaje en el registro de la tarea:

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

Podemos ver qué despliegue falló y por qué, sin mostrar el token a todos los que lean el registro. El mismo flujo se aplicará a un token temporal introducido en un campo secreto de una encuesta.

Limitaciones

El enmascaramiento funciona con valores registrados. La implementación de desarrollo omite los secretos de menos de cuatro caracteres, y un valor codificado o transformado de otra forma puede necesitar un registro independiente.

Tampoco protege las credenciales en los argumentos de procesos, en archivos escritos por un playbook ni en registros generados fuera de Ansible. Sigue utilizando no_log: true para las tareas cuya salida completa deba permanecer privada.

Con esta integración, el sistema de enmascaramiento de Ansible también conocerá los secretos marcados en Semaphore UI. Esto ayudará a mantener las credenciales fuera de los registros de tareas, conservando información útil para resolver problemas.