Cómo usar Ansible Vault para proteger datos confidenciales de Playbook

Introducción
Ansible Vault es una función que permite a los usuarios cifrar valores y estructuras de datos dentro de proyectos de Ansible. Esto brinda la capacidad de proteger cualquier dato confidencial que sea necesario para ejecutar correctamente las tareas de Ansible, pero que no debería ser visible públicamente, como contraseñas o claves privadas. Ansible descifra automáticamente el contenido cifrado en el almacén en tiempo de ejecución cuando se proporciona la clave.
En esta guía, demostraremos cómo usar Ansible Vault y exploraremos algunas prácticas recomendadas para simplificar su uso. Usaremos un servidor Ubuntu 20.04 para la máquina de control de Ansible. No se necesitan hosts remotos.
Prerrequisitos
Para continuar, necesitará un servidor Ubuntu 20.04 con un usuario no root con sudo
privilegios. Puede seguir nuestra guía de configuración inicial del servidor Ubuntu 20.04 para crear un usuario con los permisos adecuados.
En el servidor, deberá instalar y configurar Ansible. Puede seguir nuestro tutorial sobre cómo instalar Ansible en Ubuntu 20.04 para instalar los paquetes adecuados.
Continúe con esta guía cuando su servidor esté configurado con los requisitos anteriores.
¿Qué es Ansible Vault?
Ansible Vault es un mecanismo que permite incorporar contenido cifrado de forma transparente en los flujos de trabajo de Ansible. Una utilidad llamada ansible-vault
protege los datos confidenciales, denominados secretos , cifrándolos en el disco. Para integrar estos secretos con los datos regulares de Ansible, tanto los ansible
comandos ansible-playbook
como para ejecutar tareas ad hoc y playbook estructurado respectivamente, tienen soporte para descifrar contenido cifrado en el almacén en tiempo de ejecución.
Vault se implementa con granularidad a nivel de archivo, lo que significa que los archivos individuales están cifrados o no. Utiliza el AES256
algoritmo para proporcionar un cifrado simétrico vinculado a una contraseña proporcionada por el usuario. Esto significa que se utiliza la misma contraseña para cifrar y descifrar el contenido, lo que resulta útil desde el punto de vista de la usabilidad. Ansible puede identificar y descifrar cualquier archivo cifrado en Vault que encuentre mientras ejecuta un playbook o una tarea.
Ahora que comprende un poco sobre qué es Vault, podemos comenzar a analizar las herramientas que proporciona Ansible y cómo usar Vault con flujos de trabajo existentes.
Configuración del editor de Ansible Vault
Antes de usar el ansible-vault
comando, es una buena idea especificar el editor de texto que prefiera. Algunos de los comandos de Vault implican abrir un editor para manipular el contenido de un archivo cifrado. Ansible buscará en la EDITOR
variable de entorno su editor preferido. Si no está configurado, se establecerá como predeterminado vi
.
Si no desea editar con vi
el editor, debe configurar la EDITOR
variable en su entorno.
Nota: Si se encuentra dentro de una vi
sesión accidentalmente, puede salir presionando la tecla Esc:q!
, escribiendo y luego presionando Enter . Si no está familiarizado con el vi
editor, es probable que los cambios que realice no sean intencionales, por lo que este comando sale sin guardar.
Para configurar el editor para un comando individual, anteponga el comando con la asignación de la variable de entorno, de la siguiente manera:
- EDITOR=nano ansible-vault . . .
Para que esto sea persistente, abra su ~/.bashrc
archivo:
- nano ~/.bashrc
Especifique su editor preferido agregando una EDITOR
tarea al final del archivo:
~/.bashrc
export EDITOR=nano
Guarde y cierre el archivo cuando haya terminado.
Vuelva a obtener el archivo para leer el cambio en la sesión actual:
- . ~/.bashrc
Muestra la EDITOR
variable para verificar que se aplicó tu configuración:
- echo $EDITOR
Outputnano
Ahora que ha establecido su editor preferido, podemos analizar las operaciones disponibles con el ansible-vault
comando.
Cómo gestionar archivos confidenciales con ansible-vault
El ansible-vault
comando es la interfaz principal para administrar contenido cifrado dentro de Ansible. Este comando se utiliza para cifrar archivos inicialmente y, posteriormente, para ver, editar o descifrar los datos.
Creación de nuevos archivos cifrados
Para crear un nuevo archivo cifrado con Vault, utilice el ansible-vault create
comando. Introduzca el nombre del archivo que desea crear. Por ejemplo, para crear un archivo YAML cifrado que vault.yml
almacene variables confidenciales, puede escribir:
- ansible-vault create vault.yml
Se le pedirá que ingrese y confirme una contraseña:
OutputNew Vault password: Confirm New Vault password:
Cuando haya confirmado su contraseña, Ansible abrirá inmediatamente una ventana de edición donde podrá ingresar el contenido deseado.
Para probar la función de cifrado, ingrese un texto de prueba:
bóveda.yml
Secret information
Ansible cifrará el contenido cuando cierres el archivo. Si revisas el archivo, en lugar de ver las palabras que escribiste, verás un bloque cifrado:
- cat vault.yml
Output$ANSIBLE_VAULT;1.1;AES256653163323935323130306361346432353164393361333635313038383762353766353734303363333963353630373161356638376361646338353763363434360a363138376163666265336433633664303362333236643064346263636437316265366438333366383566613963643136663662316162613764656365313263620a38366638323362666537636432306239346237326666306636653630616331643731343666353761633563633634326139396230313734333034653238303166
Podemos ver información del encabezado que Ansible usa para saber cómo manejar el archivo, seguido del contenido cifrado, que se muestra como números.
Cifrado de archivos existentes
Si ya tiene un archivo que desea cifrar con Vault, utilice el ansible-vault encrypt
comando en su lugar.
Para probar, podemos crear un archivo de ejemplo escribiendo:
- echo 'unencrypted stuff' encrypt_me.txt
Ahora, puedes cifrar el archivo existente escribiendo:
- ansible-vault encrypt encrypt_me.txt
Nuevamente se le solicitará que proporcione y confirme una contraseña. Luego, un mensaje confirmará el cifrado:
OutputNew Vault password: Confirm New Vault password:Encryption successful
En lugar de abrir una ventana de edición, ansible-vault
cifrará el contenido del archivo y lo escribirá nuevamente en el disco, reemplazando la versión no cifrada.
Si revisamos el archivo, deberíamos ver un patrón cifrado similar:
- cat encrypt_me.txt
Output$ANSIBLE_VAULT;1.1;AES256666339366538346161303464363538653036653964303834303533666162633231613936393931363737316539353434666438373035653132383434303338640a396635313062386464306132313834343133363133386235373333323562313864386665656165376165386534653334313066386439613636663633363562320a61366131396637636139633638386465663237613435303966366266643739393639343966363565636161316339643033393132626639303332373339376664
Como puede ver, Ansible cifra el contenido existente de la misma manera que cifra los archivos nuevos.
Visualización de archivos cifrados
A veces, puede que necesites hacer referencia al contenido de un archivo cifrado en el almacén sin necesidad de editarlo o escribirlo en el sistema de archivos sin cifrarlo. El ansible-vault view
comando envía el contenido de un archivo a la salida estándar. De forma predeterminada, esto significa que el contenido se muestra en la terminal.
Pase el archivo cifrado de la bóveda al comando:
- ansible-vault view vault.yml
Se le solicitará la contraseña del archivo. Luego de ingresarla correctamente, se mostrará el contenido:
OutputVault password:Secret information
Como puede ver, la solicitud de contraseña se mezcla con la salida del contenido del archivo. Tenga esto en cuenta al utilizarlo ansible-vault view
en procesos automatizados.
Edición de archivos cifrados
Cuando necesite editar un archivo cifrado, utilice el ansible-vault edit
comando:
- ansible-vault edit vault.yml
Se le solicitará la contraseña del archivo. Después de ingresarla, Ansible abrirá una ventana de edición del archivo, donde podrá realizar los cambios necesarios.
Al guardar, el nuevo contenido se cifrará nuevamente utilizando la contraseña de cifrado del archivo y se escribirá en el disco.
Descifrado manual de archivos cifrados
Para descifrar un archivo cifrado de bóveda, utilice el ansible-vault decrypt
comando.
Nota: Debido a la mayor probabilidad de enviar accidentalmente datos confidenciales al repositorio de su proyecto, el ansible-vault decrypt
comando solo se sugiere cuando desea eliminar el cifrado de un archivo de forma permanente. Si necesita ver o editar un archivo cifrado en el almacén, generalmente es mejor usar los comandos ansible-vault view
o ansible-vault edit
, respectivamente.
Pase el nombre del archivo cifrado:
- ansible-vault decrypt vault.yml
Se le solicitará la contraseña de cifrado del archivo. Una vez que ingrese la contraseña correcta, se descifrará el archivo:
OutputVault password:Decryption successful
Si vuelve a ver el archivo, en lugar del cifrado de la bóveda, debería ver el contenido real del archivo:
- cat vault.yml
OutputSecret information
Ahora el archivo no está cifrado en el disco. Asegúrese de eliminar toda la información confidencial o volver a cifrar el archivo cuando haya terminado.
Cambiar la contraseña de los archivos cifrados
Si necesita cambiar la contraseña de un archivo cifrado, utilice el ansible-vault rekey
comando:
- ansible-vault rekey encrypt_me.txt
Cuando ingrese el comando, primero se le solicitará la contraseña actual del archivo:
OutputVault password:
Después de ingresarlo, se le pedirá que seleccione y confirme una nueva contraseña de bóveda:
OutputVault password:New Vault password:Confirm New Vault password:
Cuando haya confirmado con éxito una nueva contraseña, recibirá un mensaje indicando que el proceso de re-encriptación se realizó con éxito:
OutputRekey successful
Ahora debería ser posible acceder al archivo con la nueva contraseña. La contraseña anterior ya no funcionará.
Ejecución de Ansible con archivos cifrados en Vault
Una vez que haya cifrado su información confidencial con Vault, puede comenzar a usar los archivos con las herramientas convencionales de Ansible. Los comandos ansible
y ansible-playbook
saben cómo descifrar archivos protegidos por Vault si se les proporciona la contraseña correcta. Hay algunas formas diferentes de proporcionar contraseñas a estos comandos según sus necesidades.
Para continuar, necesitará un archivo cifrado en la bóveda. Puede crear uno escribiendo lo siguiente:
- ansible-vault create secret_key
Seleccione y confirme una contraseña. Complete el contenido ficticio que desee:
clave secreta
confidential data
Guarde y cierre el archivo.
También podemos crear un hosts
archivo temporal a modo de inventario:
- nano hosts
Solo le agregaremos el host local de Ansible. Para prepararnos para un paso posterior, lo colocaremos en el [database]
grupo:
anfitriones
[database]localhost ansible_connection=local
Guarde y cierre el archivo cuando haya terminado.
A continuación, cree un ansible.cfg
archivo en el directorio actual si aún no existe uno:
- nano ansible.cfg
Por ahora, solo agregue una [defaults]
sección y apunte Ansible al inventario que acabamos de crear:
ansible.cfg
[defaults]inventory = ./hosts
Cuando estés listo, continúa.
Uso de un mensaje interactivo
La forma más sencilla de descifrar contenido en tiempo de ejecución es que Ansible le solicite las credenciales adecuadas. Puede hacerlo agregando el --ask-vault-pass
a cualquier comando ansible
o ansible-playbook
. Ansible le solicitará una contraseña que utilizará para intentar descifrar cualquier contenido protegido por bóveda que encuentre.
Por ejemplo, si necesitáramos copiar el contenido de un archivo cifrado en una bóveda a un host, podríamos hacerlo con el copy
módulo y la --ask-vault-pass
bandera. Si el archivo contiene datos confidenciales, lo más probable es que desee bloquear el acceso en el host remoto con restricciones de permisos y propiedad.
Nota: En este ejemplo usamos localhost
como host de destino para minimizar la cantidad de servidores necesarios, pero los resultados deberían ser los mismos que si el host fuera realmente remoto:
- ansible --ask-vault-pass -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost
Nuestra tarea especifica que la propiedad del archivo debe cambiarse a root
, por lo que se requieren privilegios administrativos. La -bK
bandera le indica a Ansible que solicite la sudo
contraseña para el host de destino, por lo que se le solicitará su sudo
contraseña. Luego se le solicitará la contraseña de Vault:
OutputBECOME password:Vault password:
Cuando se proporciona la contraseña, Ansible intentará ejecutar la tarea y usará la contraseña de Vault para todos los archivos cifrados que encuentre. Tenga en cuenta que todos los archivos a los que se hace referencia durante la ejecución deben usar la misma contraseña:
Outputlocalhost | SUCCESS = { "changed": true, "checksum": "7a2eb5528c44877da9b0250710cba321bc6dac2d", "dest": "/tmp/secret_key", "gid": 0, "group": "root", "md5sum": "270ac7da333dd1db7d5f7d8307bd6b41", "mode": "0600", "owner": "root", "size": 18, "src": "/home/sammy/.ansible/tmp/ansible-tmp-1480978964.81-196645606972905/source", "state": "file", "uid": 0}
Solicitar una contraseña es seguro, pero puede resultar tedioso, especialmente si se ejecuta repetidamente, y también dificulta la automatización. Afortunadamente, existen algunas alternativas para estas situaciones.
Cómo usar Ansible Vault con un archivo de contraseñas
Si no desea escribir la contraseña de Vault cada vez que ejecuta una tarea, puede agregar su contraseña de Vault a un archivo y hacer referencia al archivo durante la ejecución.
Por ejemplo, podrías poner tu contraseña en un .vault_pass
archivo como este:
- echo 'my_vault_password' .vault_pass
Si está utilizando el control de versiones, asegúrese de agregar el archivo de contraseña al archivo de ignorados de su software de control de versiones para evitar confirmarlo accidentalmente:
- echo '.vault_pass' .gitignore
Ahora, puedes hacer referencia al archivo. La --vault-password-file
bandera está disponible en la línea de comandos. Podríamos completar la misma tarea de la última sección escribiendo:
- ansible --vault-password-file=.vault_pass -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost
Esta vez no se le solicitará la contraseña de la bóveda.
Outputlocalhost | SUCCESS = { "changed": false, "checksum": "52d7a243aea83e6b0e478db55a2554a8530358b0", "dest": "/tmp/secret_key", "gid": 80, "group": "root", "mode": "0600", "owner": "root", "path": "/tmp/secret_key", "size": 8, "state": "file", "uid": 0}
Lectura automática del archivo de contraseñas
Para evitar tener que proporcionar una bandera, puede configurar la ANSIBLE_VAULT_PASSWORD_FILE
variable de entorno con la ruta al archivo de contraseña:
- export ANSIBLE_VAULT_PASSWORD_FILE=./.vault_pass
Ahora debería poder ejecutar el comando sin la --vault-password-file
bandera para la sesión actual:
- ansible -bK -m copy -a 'src=secret_key dest=/tmp/secret_key mode=0600 owner=root group=root' localhost
Para que Ansible conozca la ubicación del archivo de contraseña en todas las sesiones, puede editar su ansible.cfg
archivo.
Abra el archivo local ansible.cfg
que creamos anteriormente:
- nano ansible.cfg
En la [defaults]
sección, configure la vault_password_file
configuración. Señale la ubicación de su archivo de contraseñas. Puede ser una ruta relativa o absoluta, según lo que le resulte más útil:
ansible.cfg
[defaults]. . .vault_password_file = ./.vault_pass
Ahora, cuando ejecute comandos que requieran descifrado, ya no se le solicitará la contraseña de la bóveda. Como beneficio adicional, ansible-vault
no solo usará la contraseña en el archivo para descifrar cualquier archivo, sino que también aplicará la contraseña al crear archivos nuevos con ansible-vault create
y ansible-vault encrypt
.
Lectura de la contraseña desde una variable de entorno
Es posible que le preocupe enviar accidentalmente su archivo de contraseñas a su repositorio. Si bien Ansible tiene una variable de entorno para indicar la ubicación de un archivo de contraseñas, no tiene una para configurar la contraseña en sí.
Sin embargo, si el archivo de contraseña es ejecutable, Ansible lo ejecutará como un script y utilizará el resultado como contraseña. En un problema de GitHub , Brian Schwind sugiere que se puede utilizar el siguiente script para extraer la contraseña de una variable de entorno.
Abra su .vault_pass
archivo en su editor:
- nano .vault_pass
Reemplace el contenido con el siguiente script:
.contraseña de bóveda
#!/usr/bin/env python3import osprint os.environ['VAULT_PASSWORD']
Haga que el archivo sea ejecutable escribiendo:
- chmod +x .vault_pass
Luego puede configurar y exportar la VAULT_PASSWORD
variable de entorno, que estará disponible para su sesión actual:
export VAULT_PASSWORD=my_vault_password
Tendrás que hacer esto al comienzo de cada sesión de Ansible, lo que puede parecer un inconveniente. Sin embargo, esto protege de manera efectiva contra el envío accidental de la contraseña de cifrado de Vault, lo que podría tener graves inconvenientes.
Uso de variables cifradas en Vault con variables regulares
Si bien Ansible Vault se puede utilizar con archivos arbitrarios, se utiliza con mayor frecuencia para proteger variables confidenciales. Trabajaremos con un ejemplo para mostrarle cómo transformar un archivo de variables normal en una configuración que equilibre la seguridad y la facilidad de uso.
Estableciendo el ejemplo
Para este ejemplo, simularemos que estamos configurando un servidor de base de datos, sin necesidad de instalar una base de datos como requisito previo.
Cuando creó el hosts
archivo anteriormente, colocó la localhost
entrada en un grupo llamado database
preparación para este paso. Las bases de datos suelen requerir una combinación de variables confidenciales y no confidenciales. Estas se pueden asignar en un group_vars
directorio en un archivo que lleva el nombre del grupo:
- mkdir -p group_vars
- nano group_vars/database
Dentro del group_vars/database
archivo, agregaremos algunas variables típicas. Algunas variables, como el número de puerto MySQL, no son secretas y se pueden compartir libremente. Otras variables, como la contraseña de la base de datos, serán confidenciales:
grupo_vars/base de datos
---# nonsensitive datamysql_port: 3306mysql_host: 10.0.0.3mysql_user: fred# sensitive datamysql_password: supersecretpassword
Podemos probar que todas las variables estén disponibles para nuestro host con debug
el módulo de Ansible y la hostvars
variable:
- ansible -m debug -a 'var=hostvars[inventory_hostname]' database
Outputlocalhost | SUCCESS = { "hostvars[inventory_hostname]": { "ansible_check_mode": false, "ansible_version": { "full": "2.2.0.0", "major": 2, "minor": 2, "revision": 0, "string": "2.2.0.0" }, "group_names": [ "database" ], "groups": { "all": [ "localhost" ], "database": [ "localhost" ], "ungrouped": [] }, "inventory_dir": "/home/sammy", "inventory_file": "hosts", "inventory_hostname": "localhost", "inventory_hostname_short": "localhost", "mysql_host": "10.0.0.3", "mysql_password": "supersecretpassword", "mysql_port": 3306, "mysql_user": "fred", "omit": "__omit_place_holder__1c934a5a224ca1d235ff05eb9bda22044a6fb400", "playbook_dir": "." }}
The output confirms that all of the variables we set up are applied to the host. However, our group_vars/database
file currently holds all of our variables. This means we can either leave it unencrypted, which is a security concern because of the database password variable, or we encrypt all of the variables, which creates usability and collaboration issues.
Moving Sensitive Variables into Ansible Vault
To solve this issue, we need to make a distinction between sensitive and nonsensitive variables. We should be able to encrypt confidential values and at the same time easily share our nonsensitive variables. To do so, we will split our variables between two files.
It is possible to use a variable directory in place of an Ansible variable file in order to apply variables from more than one file. We can refactor our configuration to take advantage of that ability. First, rename the existing file from database
to vars
. This will be our unencrypted variable file:
- mv group_vars/database group_vars/vars
Next, create a directory with the same name as the old variable file. Move the vars
file inside:
- mkdir group_vars/database
- mv group_vars/vars group_vars/database/
We now have a variable directory for the database
group instead of a single file and we have a single unencrypted variable file. Since we will be encrypting our sensitive variables, we should remove them from our unencrypted file. Edit the group_vars/database/vars
file to remove the confidential data:
- nano group_vars/database/vars
In this case, we want to remove the mysql_password
variable. The file should now look like this:
group_vars/database/vars
---# nonsensitive datamysql_port: 3306mysql_host: 10.0.0.3mysql_user: fred
Next, create a vault-encrypted file within the directory that will live alongside the unencrypted vars
file:
- ansible-vault create group_vars/database/vault
In this file, define the sensitive variables that used to be in the vars
file. Use the same variable names, but prepend the string vault_
to indicate that these variables are defined in the vault-protected file:
group_vars/database/vault
---vault_mysql_password: supersecretpassword
Save and close the file when you are finished.
The resulting directory structure looks this:
.├── . . .├── group_vars/│ └── database/│ ├── vars│ └── vault└── . . .
At this point, the variables are separate and only the confidential data is encrypted. This is secure, but our implementation has affected our usability. While our goal was to protect sensitive values, we’ve also unintentionally reduced visibility into the actual variable names. It is not clear which variables are assigned without referencing more than one file, and while you may wish to restrict access to confidential data while collaborating, you still probably want to share the variable names.
To address this, the Ansible project generally recommends a slightly different approach.
Referencing Vault Variables from Unencrypted Variables
Cuando trasladamos nuestros datos confidenciales al archivo protegido por la bóveda, antepusimos los nombres de las variables con vault_
( mysql_password
se convirtió vault_mysql_password
en ). Podemos agregar los nombres de las variables originales ( mysql_password
) nuevamente al archivo sin cifrar. En lugar de configurarlos directamente con valores confidenciales, podemos usar las instrucciones de plantilla de Jinja2 para hacer referencia a los nombres de las variables cifradas desde nuestro archivo de variables sin cifrar. De esta manera, puede ver todas las variables definidas haciendo referencia a un solo archivo, pero los valores confidenciales permanecerán en el archivo cifrado.
Para demostrarlo, abra nuevamente el archivo de variables sin cifrar:
- nano group_vars/database/vars
Agregue la mysql_password
variable nuevamente. Esta vez, use la plantilla Jinja2 para hacer referencia a la variable definida en el archivo protegido por el almacén:
grupo_vars/base_de_datos/vars
---# nonsensitive datamysql_port: 3306mysql_host: 10.0.0.3mysql_user: fred# sensitive datamysql_password: "{{ vault_mysql_password }}"
La mysql_password
variable se establecerá en el valor de la vault_mysql_password
variable, que está definida en el archivo de bóveda.
Con este método, puede comprender todas las variables que se aplicarán a los hosts del database
grupo al ver el group_vars/database/vars
archivo. Las partes confidenciales quedarán ocultas por la plantilla Jinja2. group_vars/database/vault
Solo es necesario abrir el archivo cuando sea necesario ver o cambiar los valores.
Puedes verificar que todas las mysql_*
variables todavía se apliquen correctamente utilizando el mismo método que la última vez.
Nota: Si su contraseña de Vault no se aplica automáticamente con un archivo de contraseña, agregue la --ask-vault-pass
bandera al comando a continuación.
- ansible -m debug -a 'var=hostvars[inventory_hostname]' database
Outputlocalhost | SUCCESS = { "hostvars[inventory_hostname]": { "ansible_check_mode": false, "ansible_version": { "full": "2.2.0.0", "major": 2, "minor": 2, "revision": 0, "string": "2.2.0.0" }, "group_names": [ "database" ], "groups": { "all": [ "localhost" ], "database": [ "localhost" ], "ungrouped": [] }, "inventory_dir": "/home/sammy/vault", "inventory_file": "./hosts", "inventory_hostname": "localhost", "inventory_hostname_short": "localhost", "mysql_host": "10.0.0.3", "mysql_password": "supersecretpassword", "mysql_port": 3306, "mysql_user": "fred", "omit": "__omit_place_holder__6dd15dda7eddafe98b6226226c7298934f666fc8", "playbook_dir": ".", "vault_mysql_password": "supersecretpassword" }}
Tanto el vault_mysql_password
como el mysql_password
son accesibles. Esta duplicación es inofensiva y no afectará el uso que usted haga de este sistema.
Conclusión
Sus proyectos deben tener toda la información necesaria para instalar y configurar correctamente sistemas complejos. Sin embargo, algunos datos de configuración son, por definición, confidenciales y no deben exponerse públicamente. En esta guía, demostramos cómo Ansible Vault puede cifrar información confidencial para que pueda mantener todos sus datos de configuración en un solo lugar sin comprometer la seguridad.
Deja una respuesta