Finalmente sucedió. Ha apostado todo con Ansible. Ha leído todos los excelentes artículos, visto los casos de uso y está emocionado de comenzar a construir una infraestructura repetible y administrar su configuración como código. Solo hay un problema:tiene un archivo de configuración o una tarea que requiere una contraseña u otra información de misión crítica. Sabe que no debe almacenar la contraseña en sus archivos de texto sin formato, por lo que no está muy seguro de dónde debe ir.
No tema, este artículo lo guía a través de las diferentes opciones para manejar información confidencial en sus libros de jugadas. Ya sea que esté buscando soluciones simples, como pedirle a un administrador que ingrese una contraseña, u opciones más complejas, como la integración con un entorno de administración de secretos existente, Ansible lo tiene cubierto.
[ También puede disfrutar: Desmitificando Ansible para administradores de sistemas Linux]
Avisos
Si acaba de comenzar su viaje a Ansible y ejecuta todos sus libros de jugadas manualmente, usar un mensaje interactivo directamente en su libro de jugadas es una solución fácil. Un mensaje hace que Ansible solicite al usuario las variables deseadas y las almacene cada vez que se ejecuta un libro de jugadas. Considere el siguiente libro de jugadas, que garantiza que exista una clave API en un archivo de configuración:
---
- hosts: all
gather_facts: false
vars_prompt:
- name: api_key
prompt: Enter the API key
tasks:
- name: Ensure API key is present in config file
ansible.builtin.lineinfile:
path: /etc/app/configuration.ini
line: "API_KEY={{ api_key }}"
Cuando ejecuto este libro de jugadas, Ansible me solicita en la línea de comando usando el mensaje en el parámetro de solicitud:
# ansible-playbook -i inventory.ini main.yml
Enter the API key:
La entrada proporcionada en la línea de comando se almacenará en la api_key variable, que luego se puede usar en el juego como cualquier variable normal.
Si bien las indicaciones variables son fáciles de implementar, las superará si está interesado en usar Ansible para la administración completa de la configuración. A medida que madure su gestión de configuración, comenzará a ejecutar playbooks de forma no interactiva y no habrá nadie frente a la terminal para ingresar contraseñas. Ahí es donde entra en juego Ansible Vault.
Bóveda de Ansible
Una de mis capacidades favoritas personales de Ansible es Ansible Vault, que proporciona capacidades de cifrado de contenido nativo. Ansible Vault puede cifrar y descifrar variables y archivos arbitrarios, lo que significa que puede usarlo para proteger archivos variables que contienen secretos o incluso cifrar archivos de configuración confidenciales completos. Ansible Vaults tiene muchas funciones avanzadas, pero este artículo se centrará en lo básico.
Los archivos YAML estándar que contienen secretos de texto sin formato se pueden cifrar fácilmente con ansible-vault encrypt
comando:
# Plaintext YAML file
$ cat secrets_file.enc
api_key: SuperSecretPassword
# Encrypt the file with ansible-vault
$ ansible-vault encrypt secrets_file.enc
New Vault password:
Confirm New Vault password:
Encryption successful
# Confirm that the file now contains encrypted content
$ cat secrets_file.enc
$ANSIBLE_VAULT;1.1;AES256
38396162626134393935663839666463306231653861336630613938303662633538633836656465
3637353766613339663032363538626430316135623665340a653961303730353962386134393162
62343936366265353935346336643865643833353737613962643539373230616239346133653464
6435353361373263640a376632613336366430663761363339333737386637383961363833303830
34336535623736313031313162353831666139343662653665366134633832646661
Cuando ejecuto mi libro de jugadas, puedo pasar el archivo de variables cifradas y decirle a Ansible que me solicite la contraseña. Ansible descifrará el archivo y usará las variables que definí, como si hubiera pasado un archivo de variables normal:
$ cat main.yml
---
- hosts: all
gather_facts: false
tasks:
- name: Ensure API key is present in config file
ansible.builtin.lineinfile:
path: /etc/app/configuration.ini
line: "API_KEY={{ api_key }}"
$ ansible-playbook -i inventory.ini -e @secrets_file.enc --ask-vault-pass main.yml
Vault password:
PLAY [all] ***********************************************************************************
TASK [Ensure API key is present in config file] **********************************************
changed: [localhost]
PLAY RECAP ***********************************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ cat /etc/app/configuration.ini
API_KEY=SuperSecretPassword
Anteriormente describí por qué usar un vars_prompt no es ideal en un entorno automatizado porque requiere la intervención manual del usuario. Entonces, ¿en qué se diferencia un Ansible Vault? Ansible Vault le permite especificar un archivo de contraseña que contiene la contraseña de descifrado para la bóveda:
$ cat password_file
password
$ ansible-playbook -i inventory.ini -e @secrets_file.enc --vault-password-file password_file main.yml
PLAY [all] ***********************************************************************************
TASK [Ensure API key is present in config file] **********************************************
changed: [localhost]
PLAY RECAP ***********************************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Asegúrese de establecer los permisos apropiados en el archivo de contraseña de descifrado para que solo el usuario que ejecuta el libro de jugadas pueda acceder a él. Alternativamente, considere usar un script para acceder a la contraseña en tiempo de ejecución desde un sistema externo de almacenamiento de contraseñas.
Ahora que mi archivo de variables está encriptado, necesito una forma de editarlo. Hay dos formas de editar un Ansible Vault cifrado. Puede editar el archivo en el lugar o puede descifrarlo por completo, editarlo y luego volver a cifrarlo. Ambos métodos se muestran a continuación.
# The edit command will launch a text editor, such as vim
$ ansible-vault edit secrets_file.enc
Vault password:
# The decrypt command will fully decrypt the file, allowing you to manipulate it how you see fit.
$ ansible-vault decrypt secrets_file.enc
Vault password:
Decryption successful
# Notice that the file has been decrypted
$ cat secrets_file.enc
api_key: SuperSecretPassword
# Don't forget to re-encrypt the file when you're done!
$ ansible-vault encrypt secrets_file.enc
New Vault password:
Confirm New Vault password:
Encryption successful
$ cat secrets_file.enc
$ANSIBLE_VAULT;1.1;AES256
33373832393864613335393836616538373639353538306462366464303939303838316337336662
6235303936636465366363643761383462356335336239640a356161653166643134663762323136
34616431303434646338343265666135666263633162383662323164396266616638313936303863
3337626365313666630a326465663239653731613637303437666164346531636361653837326166
34396232623138616364393130303036653564643435636639316264636531336161
El uso de Ansible Vault para los secretos es uno de mis métodos favoritos para almacenar datos confidenciales. El beneficio de este enfoque es que en realidad puede almacenar sus datos confidenciales en el control de fuente, junto con sus libros de jugadas regulares. Dado que estos archivos están encriptados, hay poco riesgo en este enfoque siempre que elija una contraseña segura. Como cualquier secreto compartido, es una buena idea rotar la contraseña de cifrado con frecuencia. Ansible también ofrece varias funciones avanzadas para Vaults, como la capacidad de tener diferentes contraseñas para diferentes Vaults. Asegúrese de revisar la documentación para obtener excelentes formas de proteger sus secretos utilizando las capacidades nativas de Ansible.
Usar un administrador de contraseñas existente
Los dos enfoques anteriores son enfoques puramente de Ansible para abordar la gestión de secretos. Sin embargo, muchas organizaciones ya cuentan con herramientas, como HashiCorp Vault o Thycotic Secret Server. La comunidad de Ansible ha escrito varios módulos personalizados para interactuar con este tipo de sistemas.
El siguiente libro de jugadas usa una búsqueda para obtener un secreto de HashiCorp Vault y luego usa ese secreto en una tarea:
---
- hosts: all
gather_facts: false
tasks:
- name: Ensure API key is present in config file
ansible.builtin.lineinfile:
path: /etc/app/configuration.ini
line: "API_KEY={{ lookup('hashi_vault', 'secret=config-secrets/data/app/api-key:data token=s.FOmpGEHjzSdxGixLNi0AkdA7 url=http://localhost:8201')['key'] }}"
Puede encontrar una variedad de complementos para diferentes herramientas de administración de secretos en Ansible Galaxy. Al igual que con cualquier proyecto respaldado por la comunidad, es una buena idea auditar el código para que comprenda cómo maneja sus datos y secretos. Es posible que incluso desee escribir el suyo propio.
El uso de un complemento o módulo de búsqueda es una buena opción para las organizaciones que ya cuentan con una herramienta de gestión de secretos madura y simplemente quieren que Ansible consuma secretos de este sistema existente. La compensación obvia es la reducción de la simplicidad:las ejecuciones de Playbook ahora dependen de la disponibilidad de un sistema externo, y depender de un módulo compatible con la comunidad (o escribir uno propio) puede llevar mucho tiempo.
Una nota sobre el registro
Es importante recordar que cifrar los datos en reposo (por ejemplo, en un Ansible Vault o en un sistema de secretos externos) no significa que los datos estén protegidos contra la salida accidental de un archivo de registro de Ansible. Si el módulo al que llama registra su secreto durante sus operaciones normales o cuando ocurre un error, ese secreto puede quedar expuesto en sus archivos de registro. Ya sea que almacene estos registros en un sistema central o simplemente use la vista de salida estándar predeterminada, es importante proteger sus secretos de la exposición accidental.
El siguiente resultado es del mismo libro de jugadas de Ansible que he estado usando para este tutorial. Sin embargo, aumenté el nivel de depuración de Ansible con -vvv
. Tenga en cuenta que mi secreto (API_KEY=SuperSecretPassword ) se expone directamente en la salida de depuración. He limpiado un poco este fragmento, así que no te preocupes si intentas esto y tu salida se ve ligeramente diferente.
TASK [Ensure API key is present in config file] ***********************************************************************************************************************************************
fatal: [localhost]: FAILED! => changed=false
ansible_facts:
discovered_interpreter_python: /usr/bin/python
invocation:
module_args:
attributes: null
backrefs: false
backup: false
content: null
create: false
delimiter: null
directory_mode: null
firstmatch: false
follow: false
force: null
group: null
insertafter: null
insertbefore: null
line: API_KEY=SuperSecretPassword
mode: null
owner: null
path: /etc/app/configuration.ini
regexp: null
remote_src: null
selevel: null
serole: null
setype: null
seuser: null
src: null
state: present
unsafe_writes: null
validate: null
msg: Destination /etc/app/configuration.ini does not exist !
rc: 257
Esto definitivamente no es ideal:mi secreto está justo ahí, a la vista. Afortunadamente, Ansible proporciona un parámetro no_log para tareas que protegen datos confidenciales:
---
- hosts: all
gather_facts: false
tasks:
- name: Ensure API key is present in config file
ansible.builtin.lineinfile:
path: /etc/app/configuration.ini
line: "API_KEY={{ api_key }}"
no_log: True
Al agregar este parámetro a la tarea que interactúa con datos confidenciales, se suprime la salida de la tarea fallida y se preserva la confidencialidad de mi secreto:
TASK [Ensure API key is present in config file] ***********************************************************************************************************************************************
fatal: [localhost]: FAILED! => changed=false
censored: 'the output has been hidden due to the fact that ''no_log: true'' was specified for this result'
Es una buena idea usar no_log en cualquier tarea que interactúe con datos confidenciales. También debe tener en cuenta sus limitaciones:no impedirá el registro si la depuración de Ansible está activada.
[ ¿Busca más información sobre la automatización de sistemas? Comience con The Automated Enterprise, un libro gratuito de Red Hat. ]
Reflexiones finales
La gestión adecuada de los secretos es un desafío temprano común al que se enfrentan muchos administradores de sistemas cuando trabajan en la implementación de la automatización. En este artículo, describí y demostré tres métodos diferentes que puede usar para proteger datos confidenciales cuando usa Ansible en su entorno. Este artículo solo rascó la superficie de las posibilidades, así que asegúrese de revisar la documentación que vinculé a lo largo de esta discusión. La seguridad es tarea de todos. Puede hacer su parte como administrador de sistemas asegurándose de que está tratando los datos privados con la confidencialidad que merece en sus canalizaciones de automatización.