Permitir que los usuarios regulares usen SSH usando una clave privada que no pueden leer

8

Digamos que tengo un conjunto de máquinas (llamadas aquí máquinas de los clientes) en las que solo una pequeña lista de personas (llamada personal de soporte) puede ingresar a SSH, utilizando solo una cuenta por máquina (la cuenta de acceso de soporte).

Se supone que el personal de soporte solo debe iniciar sesión en las máquinas de los clientes utilizando claves. Además, el personal de soporte puede evolucionar, por lo que alguien que deja el personal de soporte no puede iniciar sesión en ninguna máquina del cliente. Por lo tanto, el personal tiene prohibido leer las claves privadas utilizadas para iniciar sesión en las máquinas de los clientes. Además, está prohibido modificar el authorized_keysarchivo en las máquinas de los clientes.

Para darme cuenta de esa configuración, tuve la idea de usar un proxy SSH en el que el personal de soporte iniciará sesión (con autenticación LDAP, pero ese es otro problema) y que contiene las claves privadas.

La pregunta es: ¿cómo permito que el personal de soporte utilice la clave privada SSH sin poder leerla?

Creo que tengo que hacer que un demonio se ejecute como root en la máquina proxy que acepte la solicitud de un usuario y abra una sesión SSH para ellos, pero no tengo idea de cómo hacerlo. ¿Algunas ideas?

Raspbeguy
fuente
Editó la pregunta porque las "máquinas clientes" pueden ser difíciles de entender (no significa lo contrario del servidor).
Raspbeguy
Eso es muy audaz, y la mayoría parece extraño. Es una distracción ¿Crees que en el futuro podrías usar mucho menos audaz? Gracias.
DW
Supongo que la restricción autorizada_claves solo se refiere a cambios dinámicos (por ejemplo, cuando un nuevo miembro de soporte se une / abandona), ya que necesita una configuración inicial en la máquina del cliente.
Ángel

Respuestas:

6

Sugeriría un par de opciones.

  1. Proteja la clave ssh y requiera el uso del lado sudode su equipo de soporte. Podrías hacer esto de forma transparente con un envoltorio. Llame al contenedor, digamos, /usr/local/bin/ssh-supporty haga que contenga algo como esto (no probado):

    #!/bin/bash
    export PATH=/usr/local/bin:/usr/bin:/bin
    export IFS=$' \t\n'
    export SUSER=ssupport
    
    # Restart if not running under sudo
    test "X$1" != 'X-S' && exec sudo -u "$SUSER" /usr/local/bin/ssh-support -S "$@"
    shift
    export SHOME="$(getent passwd "$SUSER" | cut -d: -f6)"
    
    # Extract single argument as hostname LABEL and validate that we have
    # an RSA private key for it. The target username, real hostname, port,
    # etc. can be defined in ~/.ssh/config for the user $SUSER (ssupport)
    label="$1"
    idfile="$SUSER/.ssh/id_rsa_for_$label"
    cgfile="$SUSER/.ssh/config"
    
    ok=true
    [[ "$label" =~ '/' ]] && { echo "Invalid label: $label" >&2; ok=; }
    [[ ! -s "$idfile" ]] && { echo "Missing identity file: $idfile" >&2; ok=; }
    [[ ! -s "$cgfile" ]] && { echo "Missing configuration file: $cgfile" >&2; ok=; }
    
    if test -n "$ok"
    then
        logger -t ssh-support "$SUDO_USER requested ssh to $label"
        exec ssh -i "$idfile" -F "$cgfile" "$label"
    fi
    exit 1

    Esto requeriría una entrada en el sudoersarchivo que permitiera a los usuarios del supportgrupo usar la herramienta. Este comando les permite ejecutar la ssh-supportherramienta como el ssupportusuario, que debe crear. Que no confiere ningún privilegio raíz.

    %support ALL = (ssupport) /usr/local/bin/ssh-support

    Si está satisfecho de que los usuarios de soporte no necesiten proporcionar su propia contraseña para ejecutar la herramienta (como lo solicitó la sudoinvocación dentro del script), puede modificar la sudoersdefinición de la siguiente manera:

    %support ALL = (ssupport) NOPASSWD: /usr/local/bin/ssh-support

    Suponiendo PATHcontenido /usr/local/bin/, entonces lo llamarías con ssh-support clientname. También suponiendo que había creado el ssupportusuario como /home/ssupportse crearía /home/ssupport/.ssh/id_rsa_clientnamey /home/ssupport/.ssh/id_rsa_clientname.pubcomo el par de certificados, y tienen una entrada de host en /home/ssupport/.ssh/configpara clientnameque definió el usuario, host, puerto, etc., para el equipo de destino. Probablemente deshabilitaría explícitamente el reenvío X11, el reenvío de puertos, etc. Como de costumbre, el /home/ssupport/.sshdirectorio necesitaría estar protegido con permisos 0700.

  2. Proporcione a cada miembro de soporte su propia cuenta de usuario local y haga que cada persona use su propia clave ssh privada para acceder a los servidores del cliente. Cuando una persona abandona el grupo de soporte, elimina su clave ssh de los servidores del cliente. Esto significa que ya no necesita preocuparse por evitar que su personal conozca la clave ssh privada.

roaima
fuente
La segunda opción no es válida. Como dije, solo hay una cuenta de soporte en los servidores de los clientes y no puede agregar claves públicas a la configuración de ssh, esas son las reglas. De hecho, no puede modificar nada sobre la configuración de ssh en las máquinas de los clientes.
Raspbeguy
44
Por cierto, esta respuesta es un ejemplo típico de (ab) usando sudo. Escribí un artículo sobre el tema ( dmitry.khlebnikov.net/2015/07/… ), parece que hay una tendencia a tratar de resolver cualquier cosa usando sudo. Sin embargo, esto solo debilita la seguridad de sus sistemas y no la mejora.
galaxia
1
@Raspbeguy, por supuesto, no lo harán. La sudoerslínea limita el acceso al comando único
roaima
1
¡ Pasa opciones no marcadas a ssh con "$ @" que se ejecuta como root! No puedo pensar en diferentes maneras a los archivos del sistema corruptos éter (uso -Ede append), avance puertos privilegiados ( -L,-R,-D) o simplemente la raíz de ganancia ( -o PermitLocalCommand=yes -o 'LocalCommand=/bin/bash'El comentario de la galaxia sobre el abuso sudo está en el lugar correcto.!
nkms
1
@roaima: De todos modos, su idea de sudo a raíz tiene problemas, pero son problemas diferentes de los que se mencionó en la publicación del blog de galaxy. Él está hablando ssh root@somewherecon llaves, vs. ssh user@somewhereluego sudo. En realidad es un muy buen punto. Sin embargo, la única forma en que es aplicable a este caso es que ssh keyowner@localhost ssh_to_client client.example.org es una alternativa a sudo -u keyowner ssh_to_client client.example.org. Similar a sudo, SSH puede limitar los comandos que un usuario puede ejecutar. Estamos hablando de sudo sin contraseña para no root, no del caso de uso de Galaxy.
Peter Cordes
11

Lo que realmente desea hacer es utilizar SSH CA y las claves de firma utilizadas por cada persona de soporte (deben tener sus propias claves ssh, como pasaportes) y configurar los servidores de sus clientes para usarlos TrustedUserCAKeys /etc/ssh/users_ca.puben / etc / ssh / sshd_config. De esta manera, el servidor aceptará cualquier clave firmada por la clave CA (a la que tiene acceso) y podrá revocar las claves de las personas que ya no están en soporte sin siquiera tocar autorizadas_claves.

Una búsqueda rápida de "ssh ca" señaló este tutorial: https://www.digitalocean.com/community/tutorials/how-to-create-an-ssh-ca-to-validate-hosts-and-clients-with -ubuntu (desplácese hacia abajo hasta "Cómo configurar las claves de usuario"), aunque el tutorial menciona que Ubuntu es independiente de la distribución, pero necesita una versión nueva de OpenSSH que admita SSH CA

Otra buena entrada de blog sobre el tema es https://ef.gy/hardening-ssh (desplácese hacia abajo hasta "certificados SSH").

¡Preste especial atención en que puede firmar la clave para que sea válida por un tiempo limitado, para que caduquen automáticamente!

galaxia
fuente
Sería una buena idea si las máquinas de los clientes tuvieran acceso a Internet (para actualizar la validez de una firma), lo cual no siempre es el caso. Nos conectamos a estas máquinas a través de una VPN proporcionada por el cliente.
Raspbeguy
Bueno, esto es lo más cerca que puede llegar sin filtrar una llave con una persona que abandona su empresa. Le proporcioné el mecanismo, puede automatizarlo, por ejemplo, puede tener un oficial de servicio que respalde su RRHH cuando las personas abandonen la empresa y puede definir un procedimiento sobre cómo revocar las llaves.
galaxia
1
Además, puede firmar una clave (la de la persona de soporte) por un tiempo limitado, por ejemplo, puede firmarla solo durante 8 horas (para su turno), después de 8 horas caducará y el servidor no las dejará entrar.
galaxy
3
Con respecto a su parte de LDAP: actualmente estoy trabajando en una empresa que administra cientos de instancias y estamos trabajando en una solución de código abierto para integrar SAML 2.0 y SSH CA. La idea es que una persona se autentique usando SSO y, si está autorizada, firma sus claves por un período de tiempo definido (por ejemplo, 5 minutos). Todo esto es bastante transparente para el usuario y se implementa usando el ProxyCommand de ~ / .ssh / config.
galaxia
2

Hay un par de respuestas diferentes que involucran un script de envoltura para ssh invocado a través de sudo o setuid-ejecutable (para alguna cuenta no root de propósito especial ). Como dice nkms , pasar todos los argumentos a ssh le permite al usuario hacer cosas arbitrarias con las teclas ssh que estamos tratando de proteger. El otro extremo que se les ocurrió es permitir solo un nombre de host.

El OP dice que los administradores deben poder cargar cosas.

Podría tener dos envoltorios diferentes de args fijos a ssh. Uno para un shell de inicio de sesión, otro para scp. No hay argumentos proporcionados por el usuario que no sean el nombre de host (y el nombre de archivo para cargar).

O un script de contenedor que se utiliza getoptpara analizar opciones muy limitadas y conectar cosas a un comando ssh mayormente fijo. Ignorar (o error) en opciones no reconocidas sería el camino a seguir.

No intente filtrar las opciones ssh "peligrosas", solo escriba un contenedor que pueda hacer dos cosas: inicio de sesión interactivo o subir un archivo (nombres de archivo locales y remotos). Supongo que todavía necesitas desinfectar allí.

En realidad, todavía es fácil equivocarse. Debe encontrar una manera de evitar que el usuario entregue el archivo que contiene las teclas ssh como el archivo local. Entonces todavía estás tratando de pensar en todo lo que necesita ser rechazado, en lugar de comenzar a no permitir nada. Sería un comienzo para asegurarse de que los nombres de los archivos no contengan ninguno @o :.

Peter Cordes
fuente
La idea de envoltorio es la solución, pero eso implica una violación de seguridad que necesita ser completada.
Raspbeguy
Me sorprende cómo la gente está reinventando la rueda cuando no hay necesidad de hacerlo. La funcionalidad SSH CA se introdujo en OpenSSH exactamente por las razones y la situación como la pregunta original. Mi solución no usó ningún envoltorio y logró exactamente lo que se pidió, sin embargo, por alguna razón, @Raspbeguy decidió seguir el camino del bricolaje con implicaciones de seguridad cuestionables. :)
galaxy
@galaxy: sí, su solución SSH CA es la mejor, con seguridad, a menos que tenga un requisito absoluto de que no pueda hacer un cambio único en los sistemas remotos para configurar su sshd para usar eso. Suena perfecto y fácil de entender.
Peter Cordes
@galaxy: tu solución es realmente elegante, pero no aplicable en mi caso como te dije anteriormente. Realmente me gusta la idea, le hablé de eso a mi jefe pero aún es imposible. No hay necesidad de enojarse.
Raspbeguy
1
@Raspbeguy, no estoy molesto, simplemente no entiendo por qué su empresa quiere sacrificar su seguridad e implementar algo usando "cinta adhesiva" cuando hay una manera adecuada de hacerlo. Y su comentario fue que sería una buena solución, pero no le gustó que no pudiera automatizar la revocación, y yo también le proporcioné la solución a esto (firmando las claves solo para el turno). De todos modos, elegiste tu respuesta, sigamos :)
galaxy
1

Si configura un servidor proxy SSH, puede organizar que el shell (in /etc/passwd) de los usuarios de su personal no esté configurado en un shell como bash, sino en un script simple que no permita el acceso al shell. En su lugar, pediría un nombre de host de destino ( read target), entonces exec ssh "support@$target".

Tenga en cuenta que el uso de un proxy como este podría dificultar el uso de herramientas como la scptransferencia de archivos a / desde las máquinas del cliente. ¡Esto puede ser un problema o una ventaja!

Toby Speight
fuente
Esta es una idea de script de envoltura similar a la idea de @ roaima. Estás dando acceso a él con ssh, pero sudotambién funciona. Su respuesta sugiere usar el usuario root local, pero un usuario no root también funcionaría. Vea mis comentarios sobre su respuesta para discutir eso. (Mi ssh keyowner@localhostidea es la misma que tu idea.)
Peter Cordes
@ Peter - muy bien: ¡root es absolutamente el usuario equivocado para esto!
Toby Speight
Admite que los chicos tengan que cargar cosas, por lo que esta solución puede no funcionar.
Raspbeguy
@Raspbeguy: publicó una respuesta que aborda esto. Úselo en combinación con la configuración no root de roaima sudo.
Peter Cordes
0

Su personal de soporte siempre se conecta a través de esa máquina proxy, y solo desde ella, para que los clientes simplemente puedan autenticar la máquina proxy utilizando la autenticación basada en host .

Digamos que la máquina proxy es supporters.pcy usted brinda soporte acustomer.pc

customer.pc tendrá HostbasedAuthentication yes in /etc/ssh/ssd_config, supporters.pc en la lista /etc/ssh/shosts.equivy su clave pública en /etc/ssh/ssh_known_hosts.

Cuando su personal de soporte inicie sesión en [email protected] y realice ssh customer.pc, generará ssh-keysign (8) (que debe configurarse), que manejará la firma de la clave con el archivo que no puede leer y proporcionar pruebas a supporters.pc de que la conexión realmente proviene de supporters.pc . Como customer.pc confía en supporters.pc , su miembro del personal se conecta como soporte .

Ángel
fuente
Esta es una solución terrible desde el punto de vista de la seguridad, ya que si está otorgando acceso a una máquina como un todo y pierde la responsabilidad de quién hizo qué. La confianza de máquina a máquina debería prohibirse en el mundo moderno, donde la seguridad de TI comenzó a surgir como un tema bastante candente.
galaxia
@galaxy, desde el OP, entiendo que ya están haciendo básicamente eso. La confianza en esa máquina está en la especificación . Tenga en cuenta específicamente que están "usando solo una cuenta por máquina (la cuenta de acceso de soporte)" es posible que estén usando una cuenta compartida en customer.pc, pero se conectan al servidor como su propio usuario. Cambiar los permisos de ssh y ssh-keygen para forzar un sudo -u support ssh ... resolvería eso y también agregaría una entrada de registro.
Ángel
0

Use un contenedor binario

Para este caso de uso en particular (vea la nota importante a continuación), una posibilidad es crear un usuario (digamos support-ssh) específicamente para estas conexiones SSH salientes, luego instalar un pequeño contenedor binario que se ejecute /usr/bin/ssh.

  • No copie + chmod el sshbinario en sí, porque no recordará volver a copiarlo cada vez que aplique actualizaciones de seguridad.
  • Y no lo use rootcomo el usuario más privilegiado, por razones en las que confío son obvias.

Esta es una alternativa funcionalmente equivalente al uso sudopara elevar los privilegios al de la support-sshcuenta con las siguientes compensaciones:

  • Esto es más pequeño y delgado que sudo, por lo que hay menos riesgo de que el error de configuración se abra más de lo previsto.
  • Es su responsabilidad codificarlo correctamente; solo haga esto si es extremadamente cuidadoso y (idealmente) tiene experiencia en codificación crítica para la seguridad.
  • Se puede adaptar para que sea más específico que sudo(pero cuanto más código escriba, más necesitará auditar por seguridad).

El contenedor binario debe establecerse HOMEen el support-sshdirectorio de inicio del usuario, de modo que sshrecoja la ssh_configclave apropiada y privada. Pero el usuario que invoca no debe poder leer ~support-ssh/.ssh/ni sus contenidos.

El contenedor podría ser tan simple como:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    setenv("HOME", "/home/support-ssh", 1);
    /* allow only a single, non-option argument */
    if (argc!=2 || *argv[1]=='-') {
        fprintf(stderr, "Usage: %s <hostname>", argv[0]);
        exit(EXIT_FAILURE);
    }
    execv("/usr/bin/ssh", argv);
    return EXIT_FAILURE;
}

Es posible que desee ser más restrictivo y verificar que el argumento argv[1]esté en un conjunto de nombres de host permitidos. O menos restrictivo, y permite (un subconjunto de) argumentos de opción. Es posible que desee sustituir por completo las variables de entorno (pero mantener las importantes tales como TERM, LC_*, etc.); Tenga en cuenta que LD_LIBRARY_PATHy LD_PRELOADson particularmente peligrosos.

Se podría proporcionar un programa contenedor similar scpsi fuera necesario.

Una nota sobre aplicabilidad

Esta respuesta aborda las circunstancias específicas de la pregunta, donde los usuarios están obligados contractualmente a seguir los procedimientos, y existen sanciones (por ejemplo, despido) por violarlos. Supone que desea evitar que los empleados copien casualmente claves privadas, en lugar de evitar que un atacante determinado obtenga acceso no autorizado.

Considero que la seguridad se logra a través de defensas técnicas y no técnicas, y que el equilibrio logrado aquí o mediante el uso sudoes apropiado para la situación presentada.

Toby Speight
fuente
Pasa argumentos no verificados a ssh ejecutándose como otro usuario, vea mi comentario en la respuesta anterior. Todavía puedo leer la clave ... y no contaría con verificaciones estrictas de argumentos, ssh no debe ejecutarse de esa manera.
nkms
@nkms: he hecho que el contenedor sea más restrictivo. Se puede hacer más abierto si es necesario, pero tiene derecho a bloquear las cosas, salvo que se requiera lo contrario, en lugar de viceversa.
Toby Speight
@TobySpeight: sí, se ve bien. Puse la mayor parte de lo que dije en los comentarios en mi propia respuesta de todos modos.
Peter Cordes
1
Sería mejor usar sudo que un contenedor binario. Al contrario de lo que afirmas, usar sudo es mucho menos riesgoso que rodar el tuyo. Sudo tiene valores predeterminados seguros. ¿Qué tan seguro está de que no ha olvidado eliminar una variable de entorno que influiría en ssh?
Gilles 'SO- deja de ser malvado'