3 Power Tips + Power Link I14

En los tres casos de este issue hay una respuesta válida que no le sirve a quien la pidió: el DNS contesta sin el registro pedido, el servidor TLS presenta certificados que Java no logra encadenar hasta una raíz en la que confíe, Microsoft Entra ID emite un token que Azure API Management (APIM) rechaza. Cada herramienta muestra una sola capa, y ninguna dice por sí sola dónde está la configuración que no coincide. Al final, un calendario que va a llevar a cada mes y medio una tarea que, donde todavía es manual, hoy se hace una vez por año.

Power Tip #1 El nombre existe; el registro, no

La aplicación dice que no puede resolver el nombre, pero el nombre existe.

  • El DNS tiene dos maneras de decir que no: el nombre no existe (NXDOMAIN), o el nombre existe pero no tiene registros del tipo pedido (NODATA).
  • NODATA no tiene código propio: llega como NOERROR, sin ningún registro del tipo pedido en la respuesta (puede venir un CNAME, pero no el A). Por eso en dig parece un éxito y en la aplicación, una falla.
  • getaddrinfo(), la función de glibc que usan las aplicaciones para resolver nombres, suele reflejar la diferencia: "Name or service not known" cuando el nombre no existe, "No address associated with hostname" cuando existe sin el registro pedido.
  • Esa función trabaja por encima del DNS: pasa por NSS, cuya configuración (/etc/nsswitch.conf) puede involucrar /etc/hosts, módulos como nss-resolve o cachés como nscd. dig consulta por defecto a los servidores de /etc/resolv.conf y muestra qué contestó el DNS, que no siempre es lo que recibió la aplicación.
dig NOMBRE A +noall +comments +answer

Un NOERROR sin el registro pedido dice lo que sabe el servidor consultado, no lo que existe en todos lados: con split-horizon, otra vista puede tener el registro que esta no tiene. La pregunta pasa a ser qué tipos publica ese nombre en el servidor que consulta la aplicación, por ejemplo un nombre que solo tiene AAAA consultado desde una aplicación que pide A.

Power Tip #2 Lo que envía el servidor no es en lo que confía Java

openssl s_client -showcerts muestra los certificados que envía el servidor, y la aplicación Java falla con PKIX path building failed.

  • La cadena la valida el cliente, contra su propio almacén de raíces de confianza (truststore). El servidor normalmente no envía la raíz: el cliente tiene que tenerla.
  • Java no usa necesariamente el del sistema. En Fedora y RHEL, el OpenJDK de los paquetes de la distro enlaza su cacerts al almacén que mantiene update-ca-trust. Un JDK descomprimido de un tarball, en un servidor o dentro de una imagen de contenedor, usa el archivo que trajo, con las raíces que había cuando se empaquetó. Y cualquiera de los dos puede recibir otro almacén con -Djavax.net.ssl.trustStore.
  • Cuando una CA cambia de raíz, la nueva puede estar en el sistema y faltar en ese archivo.
JAVA_TOOL_OPTIONS='-Djavax.net.debug=ssl:trustmanager' COMANDO_DE_LA_APP 2>&1 | grep 'trustStore is'
readlink -f RUTA_QUE_IMPRIMIO

trust list describe el almacén del sistema. Si la aplicación lo usa, lo confirma la propia JVM con las opciones con que arrancó, salvo que el código arme su propio contexto TLS; no conviene suponerlo.

Power Tip #3 Válido no es lo mismo que aceptado

El token es válido, está vigente, lo firmó el emisor correcto, y la API responde 401.

  • Un token de acceso dice para quién se emitió en el claim aud (audience, audiencia). La API lo compara con su lista de audiencias aceptadas; en APIM, eso lo hace la política validate-azure-ad-token para tokens de Entra ID, o validate-jwt donde se siga usando.
  • En Entra ID, con tokens v1, el aud depende de cómo se pidió el token: puede ser cualquiera de los Application ID URI registrados para la API, con o sin barra final, o su client ID a secas. Un cliente que pide api://GUID/.default y otro que pide GUID/.default (el GUID es el client ID de la API) pueden recibir aud distintos para el mismo recurso, y si la API acepta uno solo, el otro se rechaza.
  • La versión del token no depende del endpoint que usa el cliente: la fija el registro de la API, en requestedAccessTokenVersion (null o 1 dan v1). En v2, el aud es siempre el client ID; en v1, la API puede fijarlo igual con la propiedad use_guid del claim opcional aud.
jq -R 'split(".")[1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson | {aud, ver}' <<<"$TOKEN"

Para que los valores coincidan hay tres lugares donde tocar, y no alcanzan a lo mismo. El scope es de un cliente. La lista de audiencias que acepta la política de APIM y el formato del aud que emite Entra ID son de la API, y cambian lo que reciben o aceptan todos sus clientes.

En marzo de 2026 empezó a correr un calendario que el CA/Browser Forum votó en abril de 2025: la duración máxima de un certificado TLS público baja por tramos de 398 días a 47, hasta marzo de 2029, y la reutilización de los datos de validación del dominio baja, también por tramos, de 398 a 10 días. Donde la renovación todavía es manual, una tarea de una vez por año pasa a hacerse como mínimo cada mes y medio: Ballot SC081v3: Introduce Schedule of Reducing Validity and Data Reuse Periods

Comentarios

Comments powered by Disqus