GNU/Linux >> Tutoriales Linux >  >> Linux

Manejo de secretos en sus playbooks de Ansible

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.


Linux
  1. Guía de Ansible:Administrar archivos usando Ansible

  2. Ocho formas de proteger el acceso SSH en su sistema

  3. Configure su demonio Chrony con un libro de jugadas de Ansible

  4. Cómo editar su archivo de hosts en Windows 10

  5. Cómo crear un pem para su SSL existente

Introducción a los comandos ad hoc de Ansible

Archivos de inventario y configuración de Ansible

Una breve introducción a Ansible Vault

Elija el mejor sistema de archivos para su Linux

Serie RHCE Ansible n.º 3:Manuales de Ansible

Serie RHCE Ansible n.º 12:solución de problemas de Ansible