No es desesperación, la desesperación es sólo para los que ven el final más allá de toda duda. Nosotros no lo hacemos…

Gandalf [J.R.R. TolkienLa Comunidad del Anillo]

Hace unos días, el buen Rod me comentó que tenía algunos problemas creando relaciones de confianza entre servidores utilizando llaves de SSH. La referencia obligada fueron dos posts anteriores: Mecanismos de confianza con llaves de SSH, donde compartí el procedimiento básico para generarlos, y Que hacer cuando algo falla, en caso de necesitar algún análisis de falla y poder encontrar la causa raíz de la misma, para solucionarla.

Sin embargo, después de varios días, el mecanismo seguía sin funcionar correctamente, por lo que hubo que analizar más a fondo el caso.

Escenario

El userA desde el serverA se debe conectar al serverB como el userB de forma automática sin contraseña.

Ambos servidores están instalados igual, en el mismo segmento. La única diferencia entre ellos, era que el home de userB en serverB se encontraba bajo /opt.

Primer Análisis

De inicio, no obviamos nada y revisamos lo básico:

En serverA

  • Que exista la llave privada
  • El contenido de la llave pública sea una sola línea y sea el mismo en el serverB
[userA@serverA ~]$ ls -la .ssh/
total 20
drwx------. 2 userA userA 4096 Dec 11 10:32 .
drwx------. 3 userA userA 4096 Dec 11 11:08 ..
-rw-------. 1 userA userA 1675 Dec 11 10:32 id_rsa
-rw-r--r--. 1 userA userA 410 Dec 11 10:32 id_rsa.pub
-rw-r--r--. 1 userA userA 796 Dec 11 19:24 known_hosts
[userA@serverA ~]$ wc -l .ssh/id_rsa.pub
1 .ssh/id_rsa.pub
[userA@serverA ~]$ cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAz59j3eSrdkgnQPvYpiFXL3EVqdgCE8Q7v4hFfCzORxXxSprXNpZW18L2BkEfo5P/JO//qGTyFSMrZbqRHAm6s7PR/idWbSGtZfXLt3ri5Rw4OUyLcDrXVqzhbBo3bvSADksXXYVcjDu2h0P8p70EOc1mouRsOph5bE0l4Yk2/RYZ6JfMI8DDbtpU/nKfPfdsysjeLQwOJ7XiXrKWwnqSZ+rP3Irol336RkPrgMpoQDzenkoMiAkc68cUYy1K85k1kv34gxWLFYK9riiXp4OriUFm62z7Fx2jaeDNPbLndDOBzCcm65P4b2j8K5vv8MshJtddWUypen+cB34lH7rjbw== userA@serverA.example-rh.com

En serverB

  • Que los permisos del home de userB sean 700 y exclusivos del dueño
  • La llave pública se llame authorized_keys, en una sola línea y  con el mismo contenido que en el serverA
[userB@clientB ~]$ ls -ld ~/
drwx------. 3 userB userB 4096 Dec 11 19:20 /opt/userB/
[userB@clientB ~]$ ls -la .ssh/
total 16
drwx------. 2 userB userB 4096 Dec 11 19:20 .
drwx------. 3 userB userB 4096 Dec 11 19:20 ..
-rw-------. 1 userB userB 410 Dec 11 19:20 authorized_keys
-rw-r--r--. 1 userB userB 391 Dec 11 19:18 known_hosts
[userB@clientB ~]$ wc -l .ssh/authorized_keys 
1 .ssh/authorized_keys
[userB@clientB ~]$ cat .ssh/authorized_keys 
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAz59j3eSrdkgnQPvYpiFXL3EVqdgCE8Q7v4hFfCzORxXxSprXNpZW18L2BkEfo5P/JO//qGTyFSMrZbqRHAm6s7PR/idWbSGtZfXLt3ri5Rw4OUyLcDrXVqzhbBo3bvSADksXXYVcjDu2h0P8p70EOc1mouRsOph5bE0l4Yk2/RYZ6JfMI8DDbtpU/nKfPfdsysjeLQwOJ7XiXrKWwnqSZ+rP3Irol336RkPrgMpoQDzenkoMiAkc68cUYy1K85k1kv34gxWLFYK9riiXp4OriUFm62z7Fx2jaeDNPbLndDOBzCcm65P4b2j8K5vv8MshJtddWUypen+cB34lH7rjbw== userA@serverA.example-rh.com

Al comparar el md5 de ambos archivos de llave pública daba el mismo hash:

b02e3cc11c58c8ba36677316bf52ed74  .ssh/id_rsa.pub
b02e3cc11c58c8ba36677316bf52ed74  .ssh/authorized_keys

Sin embargo, al hacer pruebas, el mecanismo de confianza no funcionaba:

[userA@serverA ~]$ ssh userB@serverB hostname
userB@serverb's password:

[userA@serverA ~]$ ssh -v userB@serverB hostname
OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013
...
debug1: Next authentication method: publickey
debug1: Trying private key: /home/userA/.ssh/identity
debug1: Offering public key: /home/userA/.ssh/id_rsa
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Trying private key: /home/userA/.ssh/id_dsa
debug1: Trying private key: /home/userA/.ssh/id_ecdsa
debug1: Next authentication method: password
userB@serverb's password:

[userA@serverA ~]$

Al revisar /var/log/messages y /var/log/secure no se encontraba evidencia alguna de la falla:

[root@clientB ~]# tail -f /var/log/messages /var/log/secure
==> /var/log/messages <==
Dec 12 12:33:30 clientB kernel: type=1305 audit(1418409210.149:4): audit_pid=952 old=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:auditd_t:s0 res=1
Dec 12 12:33:30 clientB kdump: No crashkernel parameter specified for running kernel

==> /var/log/secure <==
Dec 12 12:33:31 clientB sshd[1050]: Server listening on 0.0.0.0 port 22.
Dec 12 12:33:31 clientB sshd[1050]: Server listening on :: port 22.
Dec 12 12:33:40 clientB sshd[1192]: Accepted password for root from 192.168.122.1 port 40110 ssh2
Dec 12 12:33:41 clientB sshd[1192]: pam_unix(sshd:session): session opened for user root by (uid=0)
Dec 12 12:54:30 clientB sshd[1212]: Connection closed by 192.168.122.110
Dec 12 12:54:38 clientB sshd[1214]: Connection closed by 192.168.122.110
^C
[root@clientB ~]#

Segundo Análisis

Entonces revisamos la configuración de ssh, /etc/ssh/sshd_config, y lo modificamos para que sólo permita autenticación por llave y amarramos el nombre de la misma como authorized_keys2, para tratar de delimitar la falla:

[root@clientB ~]# cat /etc/ssh/sshd_config | grep ^[A-Z]
Protocol 2
SyslogFacility AUTHPRIV
AuthorizedKeysFile %h/.ssh/authorized_keys2
PasswordAuthentication no
ChallengeResponseAuthentication no
GSSAPIAuthentication no
GSSAPICleanupCredentials yes
UsePAM yes
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
X11Forwarding yes
Subsystem sftp /usr/libexec/openssh/sftp-server
[root@clientB ~]#

Generamos otra llave, de tipo dsa, y la copiamos en el serverB como authorized_keys2:

[userA@serverA ~]$ ssh-keygen -t dsa -b 1024
[userA@serverA ~]$ cat .ssh/id_dsa.pub
ssh-dss AAAAB3NzaC1kc3MAAACBAOpcPejQC+G/jRz3v9gUhaJy/CogjtOmXQG9zoL69pIOhKcMfjJy21GED49tS9kAw857WTpjEVzF3ssLJlS2LMqxIervQ/bsaH8WKSqUvueTMOw/4+fiwECbllCPE/g/ULozqJFssDUJlNdTAc+yA6qVbldqT69HVbNjyWeZc3dbAAAAFQDKiDJ5GwkZLiuXbYcJaElS881GtQAAAIEApXBcAfXHfewuQiHLHrBvnd0SePgjJmU8bUgfjWjwu4yoT4Z1aWy+FmtYoQGfc9SUHq4/u6EhwVUz9i7UXLW+WrEA+OtsAftEo0TjKjG8OeH4igcqsoSkosrj2QxLrf6I8l6YQnVIt5ufVtLoE4ZqCVrLtTnsS4elFeaR56hKKT8AAACAA83nEJaqK9tWm3k8RJQJZB5sEY/DAI0ZYd/TTtCKWIOXACz+G0iK+jj1JZtV40gZyJKzIFoD89FJh3RV8PZp1+UosK4kBYsxtP4WXvUjkhwVzh6PPu8A1/BJeEq/RvCqwBPinCY0rnAQrGwLCocMNkpnJxyqjg6ZLu2bsQo1HvE= userA@serverA.example-rh.com
[userA@serverA ~]$ 

[userB@clientB ~]$ cat .ssh/authorized_keys2 
ssh-dss AAAAB3NzaC1kc3MAAACBAOpcPejQC+G/jRz3v9gUhaJy/CogjtOmXQG9zoL69pIOhKcMfjJy21GED49tS9kAw857WTpjEVzF3ssLJlS2LMqxIervQ/bsaH8WKSqUvueTMOw/4+fiwECbllCPE/g/ULozqJFssDUJlNdTAc+yA6qVbldqT69HVbNjyWeZc3dbAAAAFQDKiDJ5GwkZLiuXbYcJaElS881GtQAAAIEApXBcAfXHfewuQiHLHrBvnd0SePgjJmU8bUgfjWjwu4yoT4Z1aWy+FmtYoQGfc9SUHq4/u6EhwVUz9i7UXLW+WrEA+OtsAftEo0TjKjG8OeH4igcqsoSkosrj2QxLrf6I8l6YQnVIt5ufVtLoE4ZqCVrLtTnsS4elFeaR56hKKT8AAACAA83nEJaqK9tWm3k8RJQJZB5sEY/DAI0ZYd/TTtCKWIOXACz+G0iK+jj1JZtV40gZyJKzIFoD89FJh3RV8PZp1+UosK4kBYsxtP4WXvUjkhwVzh6PPu8A1/BJeEq/RvCqwBPinCY0rnAQrGwLCocMNkpnJxyqjg6ZLu2bsQo1HvE= userA@serverA.example-rh.com
[userB@clientB ~]$ 

Sin embargo, la falla seguía presentándose:

[userA@serverA ~]$ ssh  -v userB@serverB hostname
...
debug1: Offering public key: /home/userA/.ssh/id_rsa
debug1: Authentications that can continue: publickey
debug1: Offering public key: /home/userA/.ssh/id_dsa
debug1: Authentications that can continue: publickey
debug1: Trying private key: /home/userA/.ssh/id_ecdsa
debug1: No more authentication methods to try.
Permission denied (publickey).
[userA@serverA ~]$ 

Aumentamos el nivel de log de sshd:

[root@clientB ~]# grep LogLevel /etc/ssh/sshd_config
LogLevel DEBUG
[root@clientB ~]#

Al hacer pruebas, continúa la falla, pero el /var/log/secure ya nos daba indicios de lo que estaba sucediendo:

[userA@serverA ~]$ ssh userB@serverB hostname
Permission denied (publickey).
[userA@serverA ~]$

[root@clientB ~]# tail /var/log/secure 
Dec 12 15:40:29 clientB sshd[1432]: debug1: trying public key file /opt/userB/.ssh/authorized_keys2
Dec 12 15:40:29 clientB sshd[1432]: debug1: Could not open authorized keys '/opt/userB/.ssh/authorized_keys2': Permission denied
Dec 12 15:40:29 clientB sshd[1432]: Failed publickey for userB from 192.168.122.1 port 40376 ssh2
Dec 12 15:40:29 clientB sshd[1433]: Connection closed by 192.168.122.1
Dec 12 15:40:29 clientB sshd[1433]: debug1: do_cleanup
Dec 12 15:40:29 clientB sshd[1432]: debug1: PAM: cleanup
[root@clientB ~]# 

Revisamos los permisos especiales, y validamos las opciones de montado del filesystem:

[root@clientB ~]# lsattr /opt/userB/
[root@clientB ~]#
[root@clientB ~]# getfacl /opt/userB/
getfacl: Removing leading '/' from absolute path names
# file: opt/userB/
# owner: userB
# group: userB
user::rwx
group::---
other::---

[root@clientB ~]# df -hP /opt/userB
Filesystem                    Size Used Avail Use% Mounted on
/dev/mapper/vg_opt-userB_home 988M 1.3M 936M    1% /opt/userB
[root@clientB ~]#
[root@clientB ~]# tune2fs -l /dev/mapper/vg_opt-userB_home | grep -i options
Default mount options: (none)
[root@clientB ~]#

Tercer Análisis

Al no encontrar indicios en los permisos básicos y extendidos, procedimos a revisar los permisos desde el punto de vista de seguridad:

[root@serverA ~]# getenforce
Enforcing
[root@serverA ~]# ls -lZd /home/userA/
drwx------. userA userA unconfined_u:object_r:user_home_dir_t:s0 /home/userA/
[root@serverA ~]#

[root@clientB ~]# getenforce
Enforcing
[root@clientB ~]# ls -lZd /opt/userB/
drwx------. userB userB system_u:object_r:file_t:s0 /opt/userB/
[root@clientB ~]#

Al parecer, teníamos diferencia en los contextos de SELinux; entonces realizamos una prueba, deshabilitando momentáneamente la seguridad:

[root@clientB ~]# setenforce 0
[root@clientB ~]#
[root@clientB ~]# getenforce
Permissive
[root@clientB ~]#

[userA@serverA ~]$ ssh userB@serverB hostname
clientB.example-rh.com
[userA@serverA ~]$

Al deshabilitar SELinux la conexión se realizaba de forma exitosa; sin embargo, era un requisito del cliente tenerlo habilitado.

Para conocer exactamente el comando a ejecutar y restablecer el contexto correctamente; instalamos setroubleshoot, esta herramienta nos ayuda a diagnosticar los problemas con SELinux a partir de las alertas AVC generadas en el log de audit y las parsea para entregarnos información legible en /var/log/messages. Al hacer pruebas, encontramos dicho mensaje:

[root@clientB ~]# yum -y install setroubleshoot
...
[root@clientB ~]#
[root@clientB ~]# setenforce 1
[root@clientB ~]#
[root@clientB ~]# getenforce
Enforcing
[root@clientB ~]#

[userA@serverA ~]$ ssh userB@serverB hostname
Permission denied (publickey).
[userA@serverA ~]$ 

[root@clientB ~]# tail /var/log/messages 
Dec 12 16:56:32 clientB kernel: type=1305 audit(1418424992.590:4): audit_pid=952 old=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:auditd_t:s0 res=1
Dec 12 16:58:26 clientB setroubleshoot: SELinux is preventing /usr/sbin/sshd from search access on the directory /opt/userB. For complete SELinux messages. run sealert -l f963dd2e-ab81-4c3a-99ad-4d4d1e6736d5
[root@clientB ~]# 

Al ejecutar el comando recomendado, éste nos decía:

[root@clientB ~]# sealert -l f963dd2e-ab81-4c3a-99ad-4d4d1e6736d5
SELinux is preventing /usr/sbin/sshd from search access on the directory /opt/userB.

***** Plugin restorecon (82.4 confidence) suggests *************************

If you want to fix the label.
/opt/userB default label should be usr_t.
Then you can run restorecon.
Do
# /sbin/restorecon -v /opt/userB
...
[root@clientB ~]#

Ejecutamos la recomendación:

[root@clientB ~]# ls -lZd /opt/userB/
drwx------. userB userB system_u:object_r:file_t:s0 /opt/userB/
[root@clientB ~]#
[root@clientB ~]# restorecon -v /opt/userB
restorecon reset /opt/userB context system_u:object_r:file_t:s0->system_u:object_r:usr_t:s0
[root@clientB ~]#
[root@clientB ~]# ls -lZd /opt/userB/
drwx------. userB userB system_u:object_r:usr_t:s0 /opt/userB/
[root@clientB ~]#

Y al hacer pruebas:

[userA@serverA ~]$ ssh userB@serverB hostname
clientB.example-rh.com
[userA@serverA ~]$ 

Causa Raíz

El home del usuario esta montado en un volumen sobre /opt, realizamos una prueba, desmontando el volumen y revisando el contexto del directorio y encontramos:

[root@clientB ~]# umount /opt/userB/
[root@clientB ~]#
[root@clientB ~]# ls -lZd /opt/userB/
drwx------. userB userB system_u:object_r:usr_t:s0 /opt/userB/
[root@clientB ~]#

Lo que nos indica que, cuando el usuario fue creado, al montar el volumen no se restablecieron los contextos de su home.

Gracias Rod por la confianza! fue un gusto apoyarte a resolver este caso y poder compartir la experiencia.

Espero les sirva…