Source: https://moss.sh/es/configuracion-problematica-systemd-resolved/
Timestamp: 2019-06-18 17:10:57+00:00

Document:
Una configuración problemática con systemd-resolved
20/06/2018 - Francisco Ros - Artículos
Probablemente sepas que puedes conectar Moss con tu nuevo servidor Ubuntu 18.04 o 16.04 – independientemente del proveedor donde esté alojado dicho servidor. Moss también implementa integraciones nativas con algunos proveedores (Amazon, DigitalOcean, Google y Vultr en el momento de escribir estas líneas), pero puedes usar Moss con cualquier vps, instancia cloud, o incluso servidor físico – el último no es un caso de uso común, pero es factible.
Hace unos días un cliente tuvo problemas intentando conectar con Moss un servidor Ubuntu 18.04 (alojado en el proveedor de su elección), por lo que decidí crear una cuenta en dicho proveedor e investigar el problema. Resulta que la imagen del proveedor tenía algunas configuraciones «extrañas», además de que la solución por defecto para resolución de nombres en Ubuntu 18.04 (bionic) tiene algunos bugs relacionados. Creo que el problema es lo suficientemente interesante como para compartirlo aquí, y además nos va a permitir hablar un poco sobre systemd y, de forma más específica, sobre systemd-resolved.
systemd es un proyecto de software libre que proporciona bloques en espacio de usuario para construir un sistema Linux. El componente más conocido es su proceso init, capaz de iniciar múltiples servicios en paralelo y reducir así el tiempo de arranque de tu máquina Linux. Si tienes servidores con Ubuntu (Xenial o Bionic) ya estás usando systemd como proceso init – PID 1.
A pesar de que lo anterior suena muy bien, una buena parte de la comunidad open source ha criticado duramente a systemd durante años. No voy a profundizar en dichas críticas, pero sí que me gustaría resaltar una de ellas: que systemd reinventa muchos subsistemas que no estaban rotos, creando incompatibilidades sutiles con infraestructura existente.
Uno de estos subsistemas es el de resolución de nombres, es decir, cómo tu servidor traduce nombres de dominio en direcciones de red. systemd tiene su propia implementación: systemd-resolved. Ubuntu incluyó systemd-resolved en la versión 16.10 y ahora está presente en la versión LTS actual – 18.04.
systemd-resolved proporciona a las aplicaciones locales una interfaz con el DNS. Además de implementar un resolver añade características adicionales, tales como caché DNS y validación DNSSEC. Las aplicaciones pueden usar systemd-resolved de tres formas distintas:
Usando su API D-Bus. D-Bus es un bus de mensajes para comunicación entre procesos. Es parte del proyecto freedesktop.org y systemd hace un uso extensivo del mismo. Por lo que en general, los clientes más probables de esta interfaz son las aplicaciones de escritorio y los servicios de systemd.
Usando su implementación del API de glibc – getaddrinfo(3) y funciones relacionadas. Esta interfaz no soporta actualmente todas las capacidades de systemd-resolved, y además se requiere configuración adicional para que systemd-resolved se encargue de la resolución de nombres en este caso. Si se configura para que lo haga, diría que la mayoría de software que se ejecuta en tu servidor usaría este interfaz con systemd-resolved.
Usando el DNS local de systemd-resolved que escucha en la interfaz de loopback en la dirección 127.0.0.53. Si una aplicación construye consultas DNS directamente, ésta es la única forma de que systemd-resolved pueda resolver dichas consultas.
Umm, esto empieza a complicarse… ¿verdad? En un mismo servidor, el modo en que la resolución de nombres se comporta realmente depende de la aplicación y de la configuración. Y como veremos las cosas se pueden volver más complejas aún.
Repasemos rápidamente cómo ha funcionado la resolución de nombres en Linux tradicionalmente.
/etc/resolv.conf y amigos
Si alguna vez has hecho algo de configuración de sistemas en Linux, sabrás que el «resolver» de nombres se configura en /etc/resolv.conf. Normalmente consiste en una lista de nameservers que se consultan en orden. Esto es todo. En los viejos tiempos el administrador de sistemas configuraba este fichero y a otra cosa.
Pero entonces llegaron entornos más dinámicos y se convirtieron en el caso común. En particular los escritorios Linux y los proveedores de cloud computing requieren entornos de red dinámicos, por lo que un archivo de configuración estático para la resolución de nombres no era la mejor solución en esos casos. Por tanto, se empezaron a usar (y se siguen usando) aplicaciones como resolvconf para actualizar dinámicamente /etc/resolv.conf en base a información externa. resolvconf no está pensado para usarse a mano, sino desde otro software de configuración como ifup, ifdown, dhclient, o dnsmasq.
¿Cómo se relaciona todo esto con systemd-resolved? Pues bien, volvemos a encontrar más complejidad. systemd-resolved podría ser el proveedor de /etc/resolv.conf o bien un consumidor más de ese fichero. Depende del modo de compatibilidad que el administrador de sistemas haya determinado. Básicamente, puedes delegar en 127.0.0.53 para la resolución de nombres, usar systemd-resolved para que las aplicaciones se salten systemd-resolved, o dejar que otros paquetes administren /etc/resolv.conf.
Ok, supongo que en estos momentos estarás algo confuso… Permíteme que explique el problema que motivó esta entrada en el blog y lo usaré como ejemplo para navegar por algunas de estas configuraciones.
El problema de resolución de nombres
El problema que nuestro cliente estaba teniendo en el servidor Ubuntu 18.04 de su proveedor cloud era éste:
root@systemd-00:~# gpg --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 14AA40EC0831756756D7F66C4F4EA0AAE5267A6C
gpg delega en dirmngr (ambos parte del proyecto GNU Privacy Guard) el manejo de certificados y listas de revocación. Al buscar en los logs apropiados, encontré un fallo de resolución para el nombre de host keyserver.ubuntu.com:
root@systemd-00:~# cat /var/log/syslog | grep dirmngr
Jun  5 09:13:44 ubuntu-1804-image dirmngr[3005]: resolving 'keyserver.ubuntu.com' failed: Invalid argument
Jun  5 09:13:44 ubuntu-1804-image dirmngr[3005]: can't connect to 'keyserver.ubuntu.com': host not found
Ok, el host no se podía encontrar. Pues tratemos de resolver el nombre de dominio:
root@systemd-00:~# host keyserver.ubuntu.com
keyserver.ubuntu.com has address 91.189.89.49
keyserver.ubuntu.com has address 91.189.90.55
Umm… funciona – algo extraño está ocurriendo. ¿Qué servidores de nombres se están usando?
root@systemd-00:~# cat /etc/resolv.conf
127.0.0.53: el «resolver» local de systemd-resolved.
1.1.1.1 and 1.0.0.1: resolver de Clouflare.
Dado que 127.0.0.53 es el primer servidor de nombres en /etc/resolv.conf, debería ser el que está procesando las consultas DNS en primer lugar. ¿Cómo está configurado systemd-resolved?
root@systemd-00:~# cat /etc/systemd/resolved.conf
Parece que todo es correcto. Por la última línea sabemos que el «resolver» local (127.0.0.53) está habilitado y debería responder a las peticiones de resolución de nombre. Comprobemos si se está ejecutando realmente:
root@systemd-00:~# systemctl status systemd-resolved.service
Active: active (running) since Tue 2018-06-05 08:04:10 UTC; 12min ago
root@systemd-00:~# netstat -nlutp
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      1753/systemd-resolv
udp    18432      0 127.0.0.53:53           0.0.0.0:*                           1753/systemd-resolv
Sí, se está ejecutando y escucha en los puertos apropiados – udp/53 y tcp/53. Pero espera, vimos antes que las aplicaciones también pueden interactuar con systemd-resolved por medio de las API de D-Bus o de la glibc. Si dirmngr y host usasen interfaces distintas, podríamos inferir que una de ellas expone un problema pero la otra no.
De hecho, dirmngr utiliza la llamada getaddrinfo() de la glibc mientras que host es parte de BIND y maneja las peticiones DNS directamente. Esto lo comprobé desensamblando los binarios con objdump (paquete binutils), pero podría haber revisado el código fuente en su lugar. Entonces, ¿está atendiendo systemd-resolved las llamadas de dirmngr de forma directa? Para contestar esto, tenemos que comprobar si la directiva hosts: en /etc/nsswitch.conf contiene la palabra clave «resolve». No es el caso en el servidor objeto de estudio.
root@systemd-00:~# cat /etc/nsswitch.conf
Así que, aparentemente, podemos asumir quesystemd-resolved procesa las solicitudes de dirmngr cuando llegan a 127.0.0.53. En caso de que el servidor de nombres local fallase, se le preguntaría a los servidores de Cloudflare en su lugar.
Entonces, ¿por qué el comando gpg no puede resolver el nombre de host? ¿Qué está pasando realmente por debajo? El tráfico de red nos lo dirá. Capturemos las consultas y respuestas DNS con tcpdump mientras ejecutamos gpg.
En esta captura de pantalla podemos observar varias fases diferentes.
La aplicacion busca las direcciones IPv4 (registros Tipo A) de keyserver.ubuntu.com. La consulta llega al resolver local de systemd-resolved, que emite tres consultas en paralelo – una para Cloudflare y dos para los servidores DNS de Google. La primera respuesta se reenvía a la aplicación.
La aplicacion busca las direcciones IPv6 (registros Tipo AAAA) de keyserver.ubuntu.com. Mismo comportamiento que antes.
La aplicación busca un registro Tipo 0 (Clase 7168) y el resolver local de systemd-resolved contesta con un Error de Formato.
Las consultas expiran 5 segundos más tarde y el proceso se inicia de nuevo.
El registro de la fase 3 resulta ser RRSIG – almacena firmas digitales de recursos que se usan durante el proceso de autenticación de DNSSEC. En estos momentos, systemd-resolved no soporta consultas para estos registros (y otros similares) bajo ciertas condiciones. Podemos comprobarlo de forma sencilla forzando a 127.0.0.53 que resuelva una consulta RRSIG (falla). Si la misma consulta la dirigimos a los servidores de nombres de Cloudflare, ésta funciona sin problema:
root@systemd-00:~# host -t RRSIG keyserver.ubuntu.com 127.0.0.53
Host keyserver.ubuntu.com not found: 1(FORMERR)
root@systemd-00:~# host -t RRSIG keyserver.ubuntu.com 1.1.1.1
keyserver.ubuntu.com has no RRSIG record
Por fin tenemos algo que explica por qué gpg fallaba. Sin embargo aún no está claro por qué todas las consultas expiran, ya que los registros A y AAAA se pudieron resolver de forma satisfactoria. Sigamos investigándolo…
¿Poe qué systemd-resolved lanza 3 consultas en paralelo? Comprobemos su estado:
root@systemd-00:~# systemd-resolve --status
1.0.0.1 y 1.1.1.1: Los servidores de nombres de Cloudflare como servidores DNS globales. Aparecen en /etc/resolv.conf, tal y como vimos antes.
8.8.8.8 y 8.8.4.4: Los servidores de nombres de Google para consultas que salen por la interfaz eth0. Esta lista de servidores se especifica mediante una fuente externa, en este caso a través de un servidor DHCP.
8.8.8.8 y 8.8.4.4: Igual que arriba pero para la interfaz eth1.
Las tres consultas en paralelo se corresponden con el comportamiento esperado de systemd-resolved: una para el servidor de nombres global y otra por cada interfaz de red. ¿Quién está estableciendo Cloudflare como proveedor de nombres global? Veamos de nuevo /etc/resolv.conf:
root@systemd-00:~# ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 29 May  7 12:36 /etc/resolv.conf -> ../run/resolvconf/resolv.conf
¡Extraña configuración! ¿No te parece? Fíjate en las siguientes contradicciones:
Estás usando systemd-resolved, que utiliza para cada interfaz de red la configuración DNS que le indica el servidor DHCP. Y el servidor DHCP proporciona servidores DNS externos – los de Google.
Pero /etc/resolv.conf lo está gestionando resolvconf, no systemd-resolved. Esto debería seignificar que el administrador de sistemas quiere usar el último modo de compatibilidad de systemd-resolved respecto a /etc/resolv.conf. Sin embargo, como 127.0.0.53 aparece listado como servidor de nombres, systemd-resolved acaba tomando el control de la resolución.
Pero resolvconf incluye servidores DNS externos adicionales (y diferentes a los anteriores) – los de Cloudflare – para tu configuración de resolución de nombres global.
Esta compleja configuración junto al bug de RRSIG que vimos antes provocan que tu sistema se rompa de una forma muy sutil, difícil de depurar, y difícil de entender. En particular, cuando algunas consultas están esperando una respuesta de algunos de los servidores upstream, pero systemd-resolved recibe una consulta que no soporta (como la del registro RRSIG), el proceso de resolución de nombres falla completamente.
En mi opinión, la configuración que ha realizado el proveedor cloud en este caso es incorrecta (desde el punto de vista de la mantenibilidad) y deberían corregirla. Aunque funcionase, tiene poco sentido y añade complejidad a un asunto que ya es de por sí bastante complejo. El proveedor debería elegir una política clara – bien usar 127.0.0.53 como único servidor de nombres o eliminar por completo systemd-resolved.
El DNS es un componente crítico de Internet, y es más complejo de lo que podría parecer a simple vista. En aras de proporcionar más funcionalidad, systemd-resolved añade más complejidad al asunto. Según el autor de systemd-resolved:
resolved is not supposed to be a DNS server, it’s supposed to be exactly good enough so that libc-like DNS clients can resolve their stuff
Por tanto, no parece muy afortunado que distribuciones como Ubuntu Server (entre otras) y proveedores cloud lo incluyan como solución de resolución de nombres por defecto sin una configuración muy cuidada.
En este artículo he tratado de mostrarte el doloroso camino para seguirle la pista a un problema real en un proveedor real. Si crees que hay algo incorrecto en lo que he expuesto aquí, mándame un mensaje y estaré encantado de corregirlo. ¡Ah!, y no olvides registrate abajo si quieres que te enviemos un email cuando publiquemos nuevos artículos 😀
bug-hunting, ubuntu-18.04

References: resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución