¿Cómo puedo implementar ansible con contraseñas por host de forma segura?

108

Me gustaría usar ansible para administrar un grupo de servidores existentes. Creé un ansible_hostsarchivo y probé con éxito (con la -Kopción) con comandos que solo se dirigen a un solo host

ansible -i ansible_hosts host1 --sudo -K # + commands ...

Mi problema ahora es que las contraseñas de usuario en cada host son diferentes, pero no puedo encontrar una manera de manejar esto en Ansible.

Utilizando -K, solo se me solicita una contraseña de sudo única por adelantado, que luego parece intentarse para todos los hosts posteriores sin preguntar:

host1 | ...
host2 | FAILED => Incorrect sudo password
host3 | FAILED => Incorrect sudo password
host4 | FAILED => Incorrect sudo password
host5 | FAILED => Incorrect sudo password

Investigación hasta ahora:

  • una pregunta de StackOverflow con una respuesta incorrecta ("uso -K") y una respuesta del autor diciendo "Descubrí que necesitaba sudo sin contraseña"

  • los documentos de Ansible , que dicen "El uso de sudo sin contraseña hace que las cosas sean más fáciles de automatizar, pero no es obligatorio ". (énfasis mío)

  • esta pregunta de seguridad de StackExchange que lo toma como leído y que NOPASSWDes obligatorio

  • artículo "Aprovisionamiento escalable y comprensible ..." que dice:

    "ejecutar sudo puede requerir escribir una contraseña, que es una forma segura de bloquear Ansible para siempre. Una solución simple es ejecutar visudo en el host de destino y asegurarse de que el usuario que Ansible usará para iniciar sesión no tenga que escribir una contraseña"

  • artículo "Cuadernos de juego básicos y accesibles" , que dice

    "Ansible podría iniciar sesión en el servidor de destino como root y evitar la necesidad de sudo, o dejar que el usuario ansible tenga sudo sin contraseña, pero la idea de hacerlo hace que mi bazo amenace con saltarme la garganta y bloquear la tráquea, así que no "

    Mis pensamientos exactamente, pero ¿cómo extenderse más allá de un solo servidor?

  • problema ansible # 1227 , "Ansible debe solicitar la contraseña de sudo para todos los usuarios en un libro de jugadas", que fue cerrado hace un año por mpdehaan con el comentario "No he visto mucha demanda de esto, creo que la mayoría de las personas están sudo de solo uno cuenta de usuario o usando claves la mayor parte del tiempo ".

Entonces ... ¿cómo usan las personas Ansible en situaciones como estas? Ajuste NOPASSWDde /etc/sudoers, la reutilización de contraseña a través de anfitriones o habilitación de inicio de sesión SSH raíz todos parecen reducciones más drásticas de seguridad.

supervacuo
fuente
2
¿Hay alguna razón por la que no estás usando claves SSH?
Trondh
22
Ya estoy usando claves SSH; no afectan sudo(lo que aún debería requerir una contraseña).
supervacuo
1
Puede que esto no sea exactamente lo que está buscando, pero en los cuadros de Ubuntu sigo usando claves, es decir, poner mi clave pública en / root / certified_keys para ingresar directamente como root. El inconveniente obvio es permitir los inicios de sesión de raíz sobre ssh ... También rechazo los inicios de sesión de contraseña sobre ssh y ejecuto fail2ban para mayor seguridad.
senorsmile
27
@senorsmile gracias por la respuesta! ¿Te importaría convertirlo en una respuesta para que yo pueda rechazarte por no leer la pregunta?
supervacuo
44
es decir, la ansible_ssh_passwordconfiguración solo se aplica a la contraseña SSH (la pista está en el nombre ...). & Ya estoy usando el inicio de sesión SSH basado en claves.
supervacuo

Respuestas:

53

Ciertamente has investigado ...

Por toda mi experiencia con ansible, lo que está buscando lograr no es compatible. Como mencionó, ansible afirma que no requiere sudo sin contraseña, y está en lo correcto, no lo hace. Pero aún no he visto ningún método para usar múltiples contraseñas sudo dentro de ansible, sin, por supuesto, ejecutar múltiples configuraciones.

Por lo tanto, no puedo ofrecer la solución exacta que está buscando, pero me preguntó ...

"Entonces ... ¿cómo están las personas que usan Ansible en situaciones como estas? Configurar NOPASSWD en / etc / sudoers, reutilizar la contraseña en todos los hosts o habilitar el inicio de sesión SSH raíz parece una reducción drástica de la seguridad".

Puedo darte una opinión sobre eso. Mi caso de uso es 1k nodos en múltiples centros de datos que admiten una empresa global de SaaS en la que tengo que diseñar / implementar algunos controles de seguridad increíblemente estrictos debido a la naturaleza de nuestro negocio. La seguridad siempre es un acto de equilibrio, más usabilidad menos seguridad, este proceso no es diferente si está ejecutando 10 servidores o 1,000 o 100,000.

Tiene toda la razón de no utilizar los inicios de sesión raíz, ya sea mediante contraseña o claves ssh. De hecho, el inicio de sesión raíz debe deshabilitarse por completo si los servidores tienen un cable de red conectado a ellos.

Hablemos de la reutilización de contraseñas, en una gran empresa, ¿es razonable pedirles a los administradores de sistemas que tengan contraseñas diferentes en cada nodo? para un par de nodos, tal vez, pero mis administradores / ingenieros se amotinarían si tuvieran que tener contraseñas diferentes en 1000 nodos. Implementar eso sería casi imposible también, cada usuario tendría que almacenar sus propias contraseñas en algún lugar, con suerte un keypass, no una hoja de cálculo. Y cada vez que coloca una contraseña en un lugar donde se puede extraer en texto plano, ha disminuido considerablemente su seguridad. Prefiero que sepan, de memoria, una o dos contraseñas realmente fuertes que tener que consultar un archivo de contraseña cada vez que necesitan iniciar sesión o invocar sudo en una máquina.

Por lo tanto, la reutilización de contraseña y la estandarización es algo completamente aceptable y estándar incluso en un entorno seguro. De lo contrario, ldap, keystone y otros servicios de directorio no tendrían que existir.

Cuando pasamos a usuarios automatizados, las teclas ssh funcionan muy bien para entrar, pero aún necesita superar sudo. Sus opciones son una contraseña estandarizada para el usuario automatizado (que es aceptable en muchos casos) o para habilitar NOPASSWD como ha señalado. La mayoría de los usuarios automatizados solo ejecutan unos pocos comandos, por lo que es bastante posible y ciertamente deseable habilitar NOPASSWD, pero solo para comandos preaprobados. Sugeriría usar su administración de configuración (ansible en este caso) para administrar su archivo sudoers para que pueda actualizar fácilmente la lista de comandos sin contraseña.

Ahora, hay algunos pasos que puede seguir una vez que comience a escalar para aislar aún más el riesgo. Si bien tenemos más o menos 1000 nodos, no todos son servidores de 'producción', algunos son entornos de prueba, etc. No todos los administradores pueden acceder a los servidores de producción, aquellos que sí pueden usar su misma clave / contraseña | . Pero los usuarios automatizados son un poco más seguros, por ejemplo, una herramienta automatizada a la que pueden acceder los administradores que no son de producción tiene un usuario y credenciales que no se pueden usar en la producción. Si desea iniciar ansible en todos los nodos, deberá hacerlo en dos lotes, uno para no producción y otro para producción.

Sin embargo, también utilizamos Puppet, ya que es una herramienta de gestión de configuración obligatoria, por lo que la mayoría de los cambios en todos los entornos se llevarían a cabo a través de ella.

Obviamente, si esa solicitud de función que citó se vuelve a abrir / completar, lo que está buscando hacer sería totalmente compatible. Aun así, la seguridad es un proceso de evaluación de riesgos y compromiso. Si solo tiene unos pocos nodos para los que puede recordar las contraseñas sin recurrir a una nota post-it, las contraseñas separadas serían un poco más seguras. Pero para la mayoría de nosotros, no es una opción factible.

Zeb
fuente
Gracias, @Zeb: había imaginado que los usuarios con decenas a miles de servidores usarían NOPASSWDpor razones de cordura de todos modos (probablemente respaldado por reglas de firewall más estrictas, etc. ), pero es bueno leer su caso de uso y sus pensamientos sobre la amenaza modelo.
supervacuo
16
Sin embargo, un comentario sobre su sugerencia sobre restringir a los sudocomandos "preaprobados" (que se me ocurrió cuando descubrí que NOPASSWDes bastante necesario). Desafortunadamente, esto también parece completamente incompatible . Ansible no hace ninguna promesa sobre llamar directamente, por ejemplo, chown o mkdirbinarios, y necesita poder sudo /bin/shpara que la mayoría de los módulos funcionen.
supervacuo
Me parece recordar que uno de mis ingenieros se quejó hace un tiempo, eso es molesto.
Zeb
36

Desde Ansible 1.5 en adelante, es posible usar una bóveda encriptada para host_vars y otras variables. Esto al menos le permite almacenar una ansible_sudo_passvariable por host (o por grupo) de forma segura. Desafortunadamente, --ask-vault-passsolo solicitará una contraseña de bóveda única por invocación ansible, por lo que todavía está limitado a una contraseña de bóveda única para todos los hosts que usarán juntos.

Sin embargo, para algunos usos, esto puede ser una mejora con respecto a tener una sola contraseña de sudo en varios hosts, ya que un atacante sin acceso a sus host_vars encriptados aún necesitaría una contraseña de sudo separada para cada máquina (o grupo de máquinas) que él o ella ataque.

Daniel Neades
fuente
3
La ansible_sudo_passopción también parece nueva, y parece hacer lo que estaba pidiendo. Una contraseña de bóveda única también es ideal para mis propósitos. ¡Gracias!
supervacuo
¿Hay alguna manera de evitar cifrar todo host_vars usando este método? (una posible limitación observada por Alex Dupuy)
supervacuo
1
@supervacuo: para evitar cifrar todos los vars de host, solo use un directorio var de host que contenga main.yml (sin cifrar) y secret.yml (cifrado): consulte la última parte de esta sección de documentos donde se habla sobre el grupo "raleigh" - misma técnica funciona para host vars y group vars. Lo uso mucho, la única variación es que si solo se necesita un secreto para algunos libros de jugadas, puede ser útil almacenarlo en un árbol completamente diferente e incluirlo a través de una ruta que incluya el nombre de host o var.
RichVel
1
Si he cifrado el valor 'ansible_ssh_pass' en la bóveda, ¿entonces también necesito duplicar el valor 'ansible_sudo_pass'? ¿Hay alguna manera para que el segundo valor sudo_pass refuerce el primer valor 'ssh_pass'?
emeraldjava
Puede encontrar una buena cobertura sobre el uso de contraseñas
almacenadas
22

Con Ansible 1.5, es posible establecer la variable ansible_sudo_pass usando lookup('password', …):

ansible_sudo_pass: "{{ lookup('password', 'passwords/' + inventory_hostname) }}"

Esto me parece más conveniente que usar archivos host_vars/por varias razones:

  • De hecho, utilizo with_password: "passwords/{{ inventory_hostname}} encrypt=sha256_crypt" para aprovisionar las contraseñas para el usuario remoto de implementación (que luego se necesita para sudo ), por lo que ya están presentes en los archivos (aunque al realizar estas búsquedas de texto sin formato se pierde el valor de sal almacenado en el archivo cuando se genera el valor hash) .

  • Esto mantiene solo las contraseñas en el archivo (sin ansible_sudo_pass:texto plano conocido) para un aumento de epsilon en la seguridad criptográfica. Más significativamente, significa que no está encriptando todas las demás variables específicas del host, por lo que se pueden leer sin la contraseña de la bóveda.

  • Poner las contraseñas en un directorio separado hace que sea más fácil mantener los archivos fuera del control de la fuente, o usar una herramienta como git-crypt para almacenarlos en forma cifrada (puede usar esto con Ansible anterior que carece de la función de bóveda). Uso git-crypt y como solo reviso el repositorio en forma descifrada en sistemas de archivos cifrados, no me molesto con la bóveda y, por lo tanto, no necesito escribir una contraseña de bóveda. (Por supuesto, usar ambos sería más seguro).

También puede usar la función de búsqueda con ansible_ssh_pass ; Esto incluso puede ser posible con versiones anteriores de Ansible que no tienen ansible_sudo_pass .

Alex Dupuy
fuente
2
I finalmente llegué a probar esto, pero no puedo ver cómo funcionaría sin (¡gracias!) git-crypt; por lo que puedo ver. Parece que Ansible aún no tiene soporte para usar lookupen una bóveda encriptada. Los passworddocumentos del módulo dicen que hay un soporte todavía indocumentado para el almacenamiento encriptado, pero aún no he encontrado detalles. ¿Alguna pista?
supervacuo
19

Usar pass es un método simple para proporcionar ansible con contraseñas sudo. pass almacena una contraseña por archivo, lo que facilita compartir contraseñas a través de git u otros métodos. También es seguro (usando GnuPG) y si está usando gpg-agent, le permite usar ansible sin ingresar una contraseña en cada uso.

Para proporcionar la contraseña almacenada servers/foopara que el servidor fooresponda, úsela en un archivo de inventario como este:

[servers]
foo ansible_sudo=True \
    ansible_sudo_pass="{{ lookup('pipe', 'pass servers/foo') }}"

Dado que desbloqueó la clave para gpg-agent anteriormente, se ejecutará ansible sin la necesidad de ingresar ninguna contraseña.

fqxp
fuente
3

Este es un hilo bastante antiguo, sin embargo:

  • Utilizamos dos sistemas diferentes de autenticación internamente, la administración de máquinas se realiza desde estaciones de trabajo locales en mi equipo.
  • Escribí un vars_pluginpara Ansible (se puede encontrar una implementación bastante completa en https://gist.github.com/mfriedenhagen/e488235d732b7becda81 ) que diferencia varios sistemas de autenticación:
  • El nombre del sistema de autenticación es específico del grupo.
  • El usuario de inicio de sesión / sudo utilizado es específico de grupo y administrador.
  • Así que saco al usuario del entorno del administrador y la contraseña correspondiente a través de la biblioteca python-keyring de una contraseña segura (utilizamos el llavero de Mac OS X, pero de la documentación también se admiten kwallet Gnome y _win_crypto).
  • Establecí permisos en las contraseñas en el llavero de Mac OS X para notificarme sobre el hecho de que la seguridad del programa de línea de comandos solicita acceso a una contraseña para cada sistema de autenticación utilizado por los hosts, por lo que ejecuto "ansible -s all -m ping" y obtengo dos mensajes (uno para cada sistema de autenticación) donde presiono la barra espaciadora y ansible recoge las contraseñas.
Mirko Friedenhagen
fuente
Esto se ve muy bien, gracias. Me gusta la idea de no tener que almacenar contraseñas en dos lugares. Por el momento estoy atascado utilizando KeePassX (porque el anillo de claves de GNOME no parece muy portátil) pero tal vez puede hacer python-keepassel trabajo?
supervacuo
Por lo que yo entiendo, python-keyring es una abstracción para esto, por lo que sus colegas pueden usar otros sistemas operativos. ¿O almacena su keepassx db en una memoria USB y tiene que administrar desde estaciones de trabajo con diferentes sistemas operativos?
Mirko Friedenhagen
entendido; Quise decir que ya tengo que usar KeepassX para tener acceso a las contraseñas en sistemas que no son GNOME, por lo que almacenarlas gnome-keyringsignificaría mantener registros duplicados. Aún así es mucho más agradable que usar NOPASSWD, sin embargo ...
supervacuo
0

Una posible forma de hacerlo es utilizando variables ambientales.

p.ej

pass1=foo pass2=bar ansible-playbook -i production servers.xml

Luego, en las jugadas, puedes buscar la contraseña de sudo usando:

lookup('env', 'pass1') 
lookup('env', 'pass2') 
Paul Calabro
fuente