<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Sso on lo0 — Blog Técnico</title><link>https://blog.lo0.es/tags/sso/</link><description>Recent content in Sso on lo0 — Blog Técnico</description><generator>Hugo -- gohugo.io</generator><language>es</language><lastBuildDate>Sat, 12 Sep 2026 07:30:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/tags/sso/index.xml" rel="self" type="application/rss+xml"/><item><title>Keycloak en una plataforma de IA: dónde encaja, qué resuelve y los dos estándares que MCP exige y no implementa</title><link>https://blog.lo0.es/posts/keycloak-plano-identidad-plataforma-ia/</link><pubDate>Sat, 12 Sep 2026 07:30:00 +0200</pubDate><guid>https://blog.lo0.es/posts/keycloak-plano-identidad-plataforma-ia/</guid><description>&lt;blockquote>
&lt;p>Este artículo abre el bloque de identidad del track operativo. &lt;a href="https://blog.lo0.es/posts/litellm-identidad-trazas-costuras/">El anterior&lt;/a> trató el lado del gateway: el JWT que no valida audiencia, el usuario que no llega a la traza. Este trata la pieza que hay al otro lado. Verificado contra Keycloak 26.7.3, la revisión 2026-07-28 de la especificación de MCP y el texto del Real Decreto 311/2022 en el BOE.&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>&lt;strong>Keycloak 26.7.3 se publicó el 31 de agosto de 2026&lt;/strong> y sigue en incubación en la CNCF, donde entró en abril de 2023. La cadencia es de cuatro versiones menores al año y el soporte cubre en la práctica una sola rama: los veinte fallos de seguridad corregidos en la 26.7.3 no se trasladaron a las ramas 26.4, 26.5 ni 26.6 en el momento de publicarse.&lt;/p>
&lt;p>&lt;strong>La distribución sobre Quarkus separa configuración de compilación y de ejecución.&lt;/strong> Lo que se fija en la fase de compilación queda congelado en la imagen, y cambiarlo al arrancar obliga a reconstruir. En contenedores, el patrón es compilar en la imagen y arrancar con la bandera de optimizado.&lt;/p>
&lt;p>&lt;strong>El almacenamiento es relacional y solo relacional.&lt;/strong> El motor alternativo que estuvo en desarrollo se retiró en la versión 25.0. Desde la 26.0 las sesiones se persisten en base de datos por defecto, lo que cambia el perfil de carga: el coste dominante en los bancos de pruebas oficiales es la CPU de la base de datos.&lt;/p>
&lt;p>&lt;strong>Organizaciones resuelve el multi-inquilino dentro de un realm&lt;/strong>, con soporte pleno desde la 26.0. Agrupa miembros, asocia dominios de correo y vincula proveedores de identidad por organización. Es la alternativa a replicar realms por cliente.&lt;/p>
&lt;p>&lt;strong>El cuello de botella medido es el hash de contraseña.&lt;/strong> Desde la 25.0 el algoritmo por defecto fuera de entornos FIPS es Argon2, con unos 7 MB de memoria por operación. La guía oficial de dimensionado da un vCPU por cada 15 inicios de sesión con contraseña por segundo, frente a 120 por segundo para credenciales de cliente y para refrescos.&lt;/p>
&lt;p>&lt;strong>Keycloak no implementa dos estándares que la especificación de MCP marca como obligatorios.&lt;/strong> Los metadatos de recurso protegido corresponden al servidor MCP, no al servidor de autorización, así que ahí no hay nada que reprochar. Los indicadores de recurso sí le corresponden y &lt;strong>no están soportados&lt;/strong>. La propia documentación de Keycloak declara conformidad parcial con las tres últimas revisiones de MCP por ese motivo. El sustituto práctico son los ámbitos y un mapeador de audiencia.&lt;/p>
&lt;p>&lt;strong>Hay un fallo crítico reciente que conviene mirar hoy mismo.&lt;/strong> &lt;code>CVE-2026-18963&lt;/code>, con puntuación 9,1, permitía restablecer la contraseña de cualquier usuario sin autenticarse, administradores incluidos. Corregido en 26.7.2, publicada el 19 de agosto de 2026.&lt;/p>
&lt;h2 id="estás-aquí-la-capa-transversal">Estás aquí: la capa transversal&lt;/h2>
&lt;p>La identidad no es una etapa del pipeline, es una capa que las cruza todas. Aparece en el &lt;a href="https://blog.lo0.es/posts/hardening-secretos-stack-llm-soberano/">hardening del stack&lt;/a> como una de las siete capas de defensa, en &lt;a href="https://blog.lo0.es/posts/identidad-aislamiento-spiffe-confidential-containers/">la cadena de confianza del modelo&lt;/a> como identidad de carga, en &lt;a href="https://blog.lo0.es/posts/litellm-identidad-trazas-costuras/">el gateway&lt;/a> como validación de token, y en &lt;a href="https://blog.lo0.es/posts/mcp-crece-autenticacion-keycloak/">el artículo sobre autenticar servidores MCP&lt;/a> como servidor de autorización.&lt;/p>
&lt;p>Lo que faltaba era el artículo de la pieza en sí, y sobre todo la decisión de dónde ponerla y qué esperar de ella.&lt;/p>
&lt;h2 id="la-analogía-el-registro-civil-y-los-permisos-de-obra">La analogía: el registro civil y los permisos de obra&lt;/h2>
&lt;p>Un ayuntamiento pequeño tiene un padrón, que dice quién vive allí, y tiene licencias, que dicen quién puede hacer qué. Son dos cosas distintas y conviene no confundirlas, porque el padrón vale para toda la ciudad mientras que una licencia vale para una obra concreta en una calle concreta.&lt;/p>
&lt;p>Keycloak es el padrón. Sabe quién es cada persona, la identifica de forma fiable, sabe a qué colectivos pertenece y emite un documento acreditativo que caduca. Lo que no hace es decidir si esta persona puede modificar este fichero concreto: eso es la licencia, y vive en cada servicio.&lt;/p>
&lt;p>La confusión entre las dos cosas produce el error de diseño más caro en plataformas de este tipo, que consiste en meter en el token todo lo que hará falta decidir después. El documento del padrón crece, se reparte por todas partes, y cuando cambia un permiso hay que esperar a que caduque el documento de todo el mundo.&lt;/p>
&lt;p>Hay un tercer elemento que la analogía recoge bien. Un documento acreditativo emitido para presentar en Hacienda no debería servir para entrar en el depósito municipal. Eso es la audiencia del token, y es el asunto central de la segunda mitad del artículo.&lt;/p>
&lt;h2 id="parte-1-qué-es-keycloak-hoy">Parte 1. Qué es Keycloak hoy&lt;/h2>
&lt;h3 id="estado-del-proyecto">Estado del proyecto&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Dato&lt;/th>
&lt;th>Valor&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Última versión estable&lt;/td>
&lt;td>26.7.3, publicada el 31 de agosto de 2026&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Anteriores&lt;/td>
&lt;td>26.7.2 (19 de agosto), 26.7.0 (9 de julio), 26.6.0 (8 de abril)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Cadencia&lt;/td>
&lt;td>cuatro versiones menores al año&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CNCF&lt;/td>
&lt;td>incubación desde el 10 de abril de 2023, sin graduar&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Soporte&lt;/td>
&lt;td>la rama actual; las anteriores no reciben correcciones de forma fiable&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Ese último punto merece subrayarse porque condiciona la política de actualización. El análisis de la 26.7.3 muestra que sus veinte correcciones de seguridad no se trasladaron a las ramas anteriores al publicarse. Operar Keycloak significa ir al día de la rama vigente, no quedarse en una versión &amp;ldquo;estable&amp;rdquo; durante un año.&lt;/p>
&lt;p>Desde la 26.0 hay garantía de compatibilidad hacia atrás en versiones menores para las funciones marcadas como plenamente soportadas, y los cambios que rompen son opcionales.&lt;/p>
&lt;h3 id="la-arquitectura-interna-en-cinco-piezas">La arquitectura interna en cinco piezas&lt;/h3>
&lt;p>&lt;strong>Dos modos de arranque.&lt;/strong> El de desarrollo habilita HTTP, no resuelve el nombre de host de forma estricta y desactiva la caché de temas. El de producción exige nombre de host y TLS, o no arranca. Confundirlos en producción es el primer antipatrón de la lista final.&lt;/p>
&lt;p>&lt;strong>La fase de compilación.&lt;/strong> El comando de construcción materializa las optimizaciones en la imagen. Las opciones de compilación, como el motor de base de datos, las funciones habilitadas o las métricas, quedan congeladas. Las de ejecución, como la contraseña de la base de datos o el nombre de host, se aplican al arrancar. Cambiar una opción de compilación al arrancar fuerza una reconstrucción con el coste de latencia correspondiente. El patrón correcto en contenedores es construir en la imagen y arrancar con la bandera de optimizado.&lt;/p>
&lt;p>&lt;strong>Extensiones por SPI.&lt;/strong> Autenticadores, mapeadores de protocolo, almacenamiento de usuarios, escuchas de eventos, algoritmos de hash y bóvedas de secretos. Se empaquetan como JAR y se resuelven en la fase de compilación.&lt;/p>
&lt;p>&lt;strong>Caché Infinispan.&lt;/strong> Embebida por defecto, con descubrimiento por base de datos como mecanismo recomendado. Las alternativas de descubrimiento por DNS de Kubernetes, TCP y UDP están obsoletas. Hay cachés locales, con capacidades por defecto de 10.000 entradas en varias de ellas, y cachés replicadas para sesiones, sesiones de cliente, sesiones sin conexión, sesiones de autenticación, fallos de inicio de sesión y tokens de acción. El modo remoto, con un Infinispan externo, hace falta para el despliegue multi-sitio de primera generación.&lt;/p>
&lt;p>&lt;strong>Almacenamiento relacional.&lt;/strong> JPA sobre base de datos. El motor alternativo se eliminó con la versión 25.0. Las bases soportadas hoy incluyen PostgreSQL de la 14 a la 18, MariaDB y MySQL en sus versiones de soporte extendido, SQL Server 2019 y 2022, Oracle 19c y 23.x, y las variantes gestionadas de Aurora PostgreSQL y Azure SQL.&lt;/p>
&lt;h3 id="el-modelo-conceptual-mínimo">El modelo conceptual mínimo&lt;/h3>
&lt;p>Antes de tocar nada hay que tener claros ocho conceptos, y el orden en que se relacionan:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Realm&lt;/strong>: la frontera de aislamiento. Usuarios propios, claves de firma propias, políticas propias. Dos realms no comparten nada.&lt;/li>
&lt;li>&lt;strong>Cliente&lt;/strong>: una aplicación que pide tokens. Público si no puede guardar un secreto, como una aplicación de navegador; confidencial si sí puede, como un servicio; y de solo portador si únicamente valida tokens sin pedirlos.&lt;/li>
&lt;li>&lt;strong>Ámbito de cliente&lt;/strong>: un paquete reutilizable de ámbitos y mapeadores, que se asigna a clientes como predeterminado o como opcional. Es la unidad con la que se acota lo que lleva un token.&lt;/li>
&lt;li>&lt;strong>Mapeador de protocolo&lt;/strong>: lo que proyecta un atributo, un rol o una audiencia dentro del token. El mapeador de audiencia es el que resuelve el problema central de este artículo.&lt;/li>
&lt;li>&lt;strong>Rol&lt;/strong>, de realm o de cliente, y &lt;strong>rol compuesto&lt;/strong>, que agrega otros.&lt;/li>
&lt;li>&lt;strong>Grupo&lt;/strong>, jerárquico, con roles y atributos heredados.&lt;/li>
&lt;li>&lt;strong>Proveedor de identidad&lt;/strong>: federación hacia otro OIDC o SAML externo. &lt;strong>Federación de usuarios&lt;/strong>: LDAP, Active Directory y Kerberos, con sincronización y mapeo de atributos.&lt;/li>
&lt;li>&lt;strong>Flujo de autenticación&lt;/strong>: una secuencia de ejecuciones con requisitos de obligatorio, alternativo, condicional o desactivado, y subflujos. Es donde se monta un segundo factor o una comprobación propia.&lt;/li>
&lt;/ul>
&lt;p>Y una función que cambia arquitecturas: &lt;strong>organizaciones&lt;/strong>, plenamente soportada desde la 26.0. Resuelve el multi-inquilino dentro de un mismo realm, agrupando miembros, asociando dominios de correo y vinculando proveedores de identidad por organización, de forma que el descubrimiento del proveedor se hace por el dominio del correo del usuario. La alternativa clásica, un realm por cliente, multiplica la administración y no comparte configuración.&lt;/p>
&lt;h2 id="parte-2-quién-puede-autenticarse-contra-él">Parte 2. Quién puede autenticarse contra él&lt;/h2>
&lt;p>Esta es la tabla que hay que tener antes de dibujar nada. La columna de la derecha es la que suele decidir.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Pieza&lt;/th>
&lt;th>Protocolo&lt;/th>
&lt;th>Coste&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>API de Kubernetes&lt;/td>
&lt;td>OIDC nativo, o el fichero de configuración estructurada de autenticación&lt;/td>
&lt;td>Libre&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>LiteLLM&lt;/td>
&lt;td>OIDC y JWT, más SSO de la interfaz&lt;/td>
&lt;td>&lt;strong>JWT y SSO por encima de cinco usuarios: Enterprise&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>vLLM&lt;/td>
&lt;td>solo clave estática&lt;/td>
&lt;td>No hay OIDC&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Langfuse&lt;/td>
&lt;td>OIDC genérico y proveedor Keycloak&lt;/td>
&lt;td>SSO libre; control de acceso por proyecto: Enterprise&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Grafana&lt;/td>
&lt;td>OAuth genérico &lt;strong>sí en la edición abierta&lt;/strong>&lt;/td>
&lt;td>Sincronización de equipos: Enterprise&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Backstage&lt;/td>
&lt;td>OIDC genérico y proveedor Keycloak mantenido por la comunidad&lt;/td>
&lt;td>Libre&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Open WebUI&lt;/td>
&lt;td>OIDC, con gestión de roles por claim&lt;/td>
&lt;td>Libre&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>LibreChat&lt;/td>
&lt;td>OIDC genérico, con Keycloak documentado&lt;/td>
&lt;td>Libre&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Argo CD&lt;/td>
&lt;td>OIDC nativo o Dex, con grupos hacia su fichero de RBAC&lt;/td>
&lt;td>Libre&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>MinIO&lt;/td>
&lt;td>OIDC con asunción de rol mediante identidad web&lt;/td>
&lt;td>Ver la nota de abajo&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Dos precisiones que cambian decisiones.&lt;/p>
&lt;p>&lt;strong>Kubernetes.&lt;/strong> El mecanismo moderno es la configuración estructurada de autenticación, que permite varios emisores JWT y validaciones y mapeos con expresiones CEL. La propuesta correspondiente, KEP-3331, pasó a alfa en la 1.29, a beta en la 1.30 y es &lt;strong>estable desde la 1.34&lt;/strong>. Es la vía a usar hoy, y sustituye a las banderas sueltas del API server.&lt;/p>
&lt;p>&lt;strong>vLLM no tiene identidad.&lt;/strong> Lo único que hay es una clave estática por variable de entorno. Esto no es un defecto a corregir, es un hecho de arquitectura: el motor va detrás del gateway y su control de acceso es de red, no de identidad. Cualquier diseño que exponga vLLM directamente a usuarios está renunciando a la trazabilidad por persona.&lt;/p>
&lt;p>Sobre MinIO conviene una advertencia de honestidad: la documentación pública redirige hoy a la edición comercial, así que el detalle de cómo mapea políticas desde un claim está verificado ahí y no en la edición abierta. Quien dependa de ese mecanismo debería confirmarlo contra su propia versión antes de diseñar sobre él.&lt;/p>
&lt;h2 id="parte-3-humanos-y-máquinas">Parte 3. Humanos y máquinas&lt;/h2>
&lt;p>Son dos problemas distintos y conviene resolverlos por separado.&lt;/p>
&lt;h3 id="personas">Personas&lt;/h3>
&lt;p>Código de autorización con PKCE, con método S256. La especificación de MCP lo exige cuando el cliente sea técnicamente capaz, y va más allá: obliga a &lt;strong>rechazar el flujo&lt;/strong> si los metadatos del servidor de autorización no publican los métodos de desafío soportados.&lt;/p>
&lt;h3 id="cargas-sin-persona-detrás">Cargas sin persona detrás&lt;/h3>
&lt;p>Aquí la opción obvia son las credenciales de cliente con una cuenta de servicio de Keycloak, autenticada con secreto o, mejor, con JWT firmado por clave privada.&lt;/p>
&lt;p>Pero hay una opción menos conocida y mejor para cargas dentro del cluster: la &lt;strong>autenticación federada de clientes&lt;/strong>, presentada en enero de 2026 con el lema de acabar con los secretos. Permite que un cliente se autentique con un token emitido por un proveedor externo, y uno de esos proveedores es Kubernetes. El anuncio situaba el soporte pleno de la variante de cuentas de servicio de Kubernetes y de OIDC en la versión 26.6; la variante SPIFFE, en cambio, dice expresamente que seguirá en vista previa hasta que se cierre el estándar de autenticación de cliente SPIFFE en el IETF.&lt;/p>
&lt;p>Eso significa que un pod puede autenticarse contra Keycloak con el token que el kubelet ya le proyecta, sin ningún secreto adicional que rotar. Conviene confirmar el estado exacto y el nombre de la bandera contra las notas de la versión que se tenga desplegada, porque la función es reciente y ha cambiado de estado entre la 26.5 y la 26.6. Es preferible al intercambio de tokens, cuya versión estándar está soportada pero es solo interno hacia interno, mientras que la antigua, la que cubría externo hacia interno y la suplantación, está obsoleta y en vista previa.&lt;/p>
&lt;h3 id="keycloak-frente-a-spiffe">Keycloak frente a SPIFFE&lt;/h3>
&lt;p>La pregunta aparece siempre y la respuesta es que resuelven cosas distintas con un solapamiento pequeño.&lt;/p>
&lt;p>SPIRE atesta el nodo y el proceso, y emite documentos de identidad de vida corta sin ningún secreto previo. Keycloak no atesta cargas: confía en una credencial que alguien tuvo que colocar, salvo en el caso de la autenticación federada que se acaba de mencionar, donde quien atesta es Kubernetes. A cambio, Keycloak federa personas, emite tokens con datos de negocio y gobierna el consentimiento, cosas que SPIFFE no hace.&lt;/p>
&lt;p>La regla práctica: SPIFFE para identidad entre servicios dentro del perímetro, Keycloak para todo lo que tenga una persona detrás o cruce el perímetro. El detalle de SPIFFE está en &lt;a href="https://blog.lo0.es/posts/identidad-aislamiento-spiffe-confidential-containers/">el cierre de la serie de la cadena de confianza&lt;/a>.&lt;/p>
&lt;h2 id="parte-4-mcp-y-los-dos-estándares-que-faltan">Parte 4. MCP, y los dos estándares que faltan&lt;/h2>
&lt;p>Esta parte es la que más consecuencias tiene y la que peor documentada está fuera de las fuentes primarias.&lt;/p>
&lt;h3 id="lo-que-exige-la-especificación">Lo que exige la especificación&lt;/h3>
&lt;p>De la revisión 2026-07-28, con las palabras normativas tal como aparecen:&lt;/p>
&lt;ul>
&lt;li>El servidor MCP &lt;strong>debe&lt;/strong> implementar los metadatos de recurso protegido del RFC 9728, y el cliente &lt;strong>debe&lt;/strong> usarlos para descubrir el servidor de autorización.&lt;/li>
&lt;li>El cliente &lt;strong>debe&lt;/strong> implementar los indicadores de recurso del RFC 8707, incluyendo el parámetro &lt;code>resource&lt;/code> &lt;strong>tanto en la petición de autorización como en la de token&lt;/strong>, y &lt;strong>debe&lt;/strong> mandarlo con independencia de que el servidor de autorización lo soporte.&lt;/li>
&lt;li>El servidor MCP &lt;strong>debe&lt;/strong> validar que el token de acceso se emitió específicamente para él como audiencia, y &lt;strong>no debe&lt;/strong> aceptar ni retransmitir ningún otro token.&lt;/li>
&lt;li>Los servidores de autorización y los clientes &lt;strong>deberían&lt;/strong> soportar documentos de metadatos de identificador de cliente. El registro dinámico del RFC 7591 pasa a ser opcional y queda declarado obsoleto, retenido por compatibilidad.&lt;/li>
&lt;/ul>
&lt;p>La revisión añade además el emisor en la respuesta de autorización, del RFC 9207, y un modelo sin estado con manejadores de estado donde se dice expresamente que poseer un manejador de estado no equivale a estar autenticado.&lt;/p>
&lt;h3 id="lo-que-soporta-keycloak">Lo que soporta Keycloak&lt;/h3>
&lt;p>De su propia guía de integración con MCP:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Estándar&lt;/th>
&lt;th>Keycloak&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>OAuth 2.1 y metadatos de servidor de autorización&lt;/td>
&lt;td>Soportado&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>RFC 9207, emisor en la respuesta&lt;/td>
&lt;td>Soportado&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>RFC 7591, registro dinámico&lt;/td>
&lt;td>Soportado&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Documento de metadatos de identificador de cliente&lt;/td>
&lt;td>Soportado, &lt;strong>experimental&lt;/strong>, tras activar la función&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>RFC 8707, indicadores de recurso&lt;/strong>&lt;/td>
&lt;td>&lt;strong>No soportado&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>RFC 9728, metadatos de recurso protegido&lt;/strong>&lt;/td>
&lt;td>Fuera de alcance, es del servidor MCP&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>La conformidad declarada por el propio proyecto es &amp;ldquo;parcialmente soportado, sin indicadores de recurso&amp;rdquo; para las tres últimas revisiones de MCP.&lt;/p>
&lt;p>Dos conclusiones prácticas:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>El documento de metadatos de recurso protegido lo publica el servidor MCP o un proxy delante de él&lt;/strong>, nunca Keycloak. Es correcto y no hay nada que arreglar, pero hay que acordarse de implementarlo, porque el cliente lo necesita para descubrir a dónde ir.&lt;/li>
&lt;li>&lt;strong>Sin indicadores de recurso, la audiencia se acota con ámbitos.&lt;/strong> El camino oficial es usar el parámetro &lt;code>scope&lt;/code> en lugar de &lt;code>resource&lt;/code>, y colgar de ese ámbito de cliente un mapeador de audiencia con la URL del servidor MCP como audiencia personalizada incluida.&lt;/li>
&lt;/ol>
&lt;p>Es un rodeo, funciona, y hay que documentarlo en el diseño porque cualquiera que venga detrás buscará el parámetro estándar y no lo encontrará.&lt;/p>
&lt;h2 id="parte-5-el-delegado-confuso">Parte 5. El delegado confuso&lt;/h2>
&lt;p>Con lo anterior encima de la mesa, el error clásico se ve solo. Un token con audiencia genérica convierte cualquier servicio comprometido en una llave maestra: quien obtiene el token que un usuario presentó al panel puede presentarlo al gateway, y de ahí al servidor MCP.&lt;/p>
&lt;p>La especificación de MCP es explícita en tres frases que conviene citar tal cual en cualquier documento de arquitectura:&lt;/p>
&lt;ul>
&lt;li>Los servidores MCP &lt;strong>no deben&lt;/strong> aceptar tokens que no se emitieran explícitamente para ellos.&lt;/li>
&lt;li>Si el servidor MCP llama a APIs de más arriba, &lt;strong>no debe&lt;/strong> reenviar el token que recibió del cliente.&lt;/li>
&lt;li>Los proxies MCP que usen identificadores de cliente estáticos &lt;strong>deben&lt;/strong> obtener consentimiento del usuario por cada cliente registrado dinámicamente antes de reenviar a servidores de autorización de terceros.&lt;/li>
&lt;/ul>
&lt;p>Traducido a la figura concreta que se viene tratando en este track: &lt;strong>el gateway no debe reenviar el JWT del usuario a servidores MCP de terceros&lt;/strong>. Tiene que obtener un token distinto con la audiencia correcta, o actuar como cliente OAuth propio. Por defecto, como ya se documentó &lt;a href="https://blog.lo0.es/posts/litellm-gateway-mcp-segunda-puerta/">en el artículo del gateway MCP&lt;/a>, el comportamiento es usar la credencial propia del servidor, que es el correcto; hay dos modos que reenvían el token del llamante y ambos tienen nombre en la especificación.&lt;/p>
&lt;h2 id="parte-6-dos-horas-de-tarea-contra-cinco-minutos-de-token">Parte 6. Dos horas de tarea contra cinco minutos de token&lt;/h2>
&lt;p>La especificación empuja hacia tokens de vida corta y rotación obligatoria del token de refresco en clientes públicos. Una tarea agéntica de dos horas excede con holgura la vida de un token de acceso y puede exceder también la inactividad de la sesión si nadie refresca.&lt;/p>
&lt;p>Tres opciones reales, con su coste:&lt;/p>
&lt;p>&lt;strong>Tokens sin conexión.&lt;/strong> Sobreviven a la expiración de la sesión, y caducan por inactividad propia o por un máximo si se activa esa limitación. El riesgo es evidente: una credencial casi permanente, difícil de inventariar. Y la especificación de MCP añade que los servidores MCP &lt;strong>no deberían&lt;/strong> incluir ese ámbito ni en la cabecera de autenticación ni en los ámbitos soportados de sus metadatos.&lt;/p>
&lt;p>&lt;strong>Refresco automático en el cliente.&lt;/strong> Es la respuesta correcta cuando hay cliente que la pueda implementar, con rotación del token de refresco y almacenamiento seguro. Para un agente sin persona detrás, es mejor renovar por credenciales de cliente.&lt;/p>
&lt;p>&lt;strong>Claves virtuales de larga vida en el gateway.&lt;/strong> Funciona, y es lo que la mayoría acaba haciendo. El precio hay que escribirlo en el análisis de riesgos: la identidad queda desacoplada del proveedor, de modo que dar de baja a alguien en Keycloak no invalida su clave, y la trazabilidad hacia la persona real depende de la disciplina con que se hayan creado las claves. Las palancas que compensan son la caducidad, la rotación automática y el alias obligatorio, tratadas &lt;a href="https://blog.lo0.es/posts/litellm-limites-presupuestos-claves-virtuales/">en el artículo de las claves virtuales&lt;/a>.&lt;/p>
&lt;p>Una nota de honestidad sobre los valores por defecto. Los números que circulan (cinco minutos de token de acceso, treinta de inactividad de sesión, diez horas de máximo) no aparecen publicados en la guía de administración ni los localicé en el código. Trátense como observación de consola y confírmense en el realm propio antes de citarlos en un documento.&lt;/p>
&lt;h2 id="parte-7-dimensionar-y-operar">Parte 7. Dimensionar y operar&lt;/h2>
&lt;h3 id="en-kubernetes">En Kubernetes&lt;/h3>
&lt;p>El operador expone tres recursos personalizados: el servidor, la importación de realm y el cliente OIDC. Las sondas y las métricas viven en el &lt;strong>puerto de gestión 9000&lt;/strong>, con las rutas de salud y preparación, y las métricas en formato Prometheus siempre que se haya habilitado la opción correspondiente en la fase de compilación. Ese puerto no se expone públicamente.&lt;/p>
&lt;p>Para alta disponibilidad hay tres figuras. Un solo cluster repartido entre zonas, sin infraestructura adicional. Multi-cluster de primera generación, con balanceador externo e Infinispan externo en cada sitio. Y multi-cluster de segunda generación, introducido en la 26.7.0 y todavía en vista previa, que conecta clusters &lt;strong>sin Infinispan externo&lt;/strong>, usando la base replicada de forma síncrona como fuente de verdad, con menos caché y más carga de base de datos.&lt;/p>
&lt;h3 id="las-cifras-oficiales-de-dimensionado">Las cifras oficiales de dimensionado&lt;/h3>
&lt;p>De la guía de conceptos de dimensionado de CPU y memoria, que sigue publicada:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>1 vCPU por cada 15 inicios de sesión con contraseña por segundo&lt;/strong>, probado hasta 300 por segundo.&lt;/li>
&lt;li>&lt;strong>1 vCPU por cada 120 concesiones de credenciales de cliente por segundo&lt;/strong>, probado hasta 2.000.&lt;/li>
&lt;li>&lt;strong>1 vCPU por cada 120 peticiones de refresco de token por segundo&lt;/strong>, probado hasta 435.&lt;/li>
&lt;li>Dejar un &lt;strong>150 % de margen&lt;/strong> de CPU para picos, arranque y conmutación.&lt;/li>
&lt;li>&lt;strong>1.250 MB de memoria por pod&lt;/strong> con datos de realm y 10.000 sesiones en caché. Keycloak asigna el 70 % del límite al heap y unos 300 MB fuera de él, así que el límite sale de restar esos 300 MB al uso esperado y dividir entre 0,7.&lt;/li>
&lt;/ul>
&lt;p>Los supuestos declarados de esas cifras incluyen Argon2 con cinco iteraciones, sesiones en base de datos y la caché por defecto de 10.000 entradas.&lt;/p>
&lt;p>La diferencia entre 15 y 120 es toda la historia del rendimiento de Keycloak: &lt;strong>el coste está en el hash de contraseña&lt;/strong>. Desde la 25.0, el algoritmo por defecto fuera de entornos FIPS es Argon2, con unos 7 MB de memoria por operación. Antes era PBKDF2, cuyas iteraciones se multiplicaron por diez en la versión 24. En modo FIPS se sigue usando PBKDF2.&lt;/p>
&lt;p>De ahí sale una consecuencia de arquitectura para una plataforma de IA: &lt;strong>las cargas de máquina, que van por credenciales de cliente, cuestan ocho veces menos que un inicio de sesión humano&lt;/strong>. Dimensionar por número de servicios es barato; dimensionar por picos de inicio de sesión por la mañana es lo caro.&lt;/p>
&lt;h3 id="el-banco-de-pruebas">El banco de pruebas&lt;/h3>
&lt;p>Del informe de rendimiento de la 26.4, publicado el 1 de octubre de 2025: hasta 2.000 inicios de sesión por segundo y 10.000 refrescos por segundo con tres pods, 74 vCPU en total y 8 GB por pod, sobre una base Aurora PostgreSQL, con escalado vertical casi lineal.&lt;/p>
&lt;p>Dos hallazgos útiles de ese informe. Con 20 ms de tiempo de ida y vuelta entre sitios, el percentil 99 sube de 51 a 130 ms, y el proyecto &lt;strong>desaconseja desplegar entre regiones distintas&lt;/strong>. Y subir la caché de 10.000 a 200.000 entradas bajó el pico de CPU de la base de datos del 77,77 % al 63,77 %, a cambio de pausas de recolección de basura algo mayores.&lt;/p>
&lt;h3 id="seguridad">Seguridad&lt;/h3>
&lt;p>El asunto urgente, si el despliegue está por debajo de la 26.7.2:&lt;/p>
&lt;p>&lt;strong>&lt;code>CVE-2026-18963&lt;/code>, puntuación 9,1, crítico.&lt;/strong> Un salto del token de acción por correo en el flujo de restablecimiento de credenciales permitía restablecer la contraseña de cualquier usuario sin autenticación previa, administradores incluidos. Corregido en 26.7.2, publicada el 19 de agosto de 2026. La mitigación temporal, si no se puede actualizar, es desactivar la recuperación de contraseña en todos los realms. No consta explotación conocida a finales de agosto.&lt;/p>
&lt;p>En la 26.7.3 hay otros diecinueve, entre ellos la falta de verificación del nombre de host en el certificado TLS hacia LDAP con puntuación 8,8, dos saltos de restricción de inquilino en el intercambio de tokens con corredores de Microsoft y Google, y dos saltos de control de acceso en organizaciones.&lt;/p>
&lt;p>El endurecimiento oficial se resume en cuatro decisiones:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Nombre de host estricto&lt;/strong>, que es el valor por defecto desde la segunda generación de esa configuración. El servidor no deduce la URL de las cabeceras, lo que evita envenenar los enlaces de los correos y las redirecciones.&lt;/li>
&lt;li>&lt;strong>Consola de administración en un nombre de host distinto&lt;/strong>, y restringida en red.&lt;/li>
&lt;li>&lt;strong>Cabeceras de proxy declaradas explícitamente&lt;/strong>, confiando solo en un proxy inverso controlado.&lt;/li>
&lt;li>&lt;strong>Puerto de gestión separado y no expuesto.&lt;/strong>&lt;/li>
&lt;/ol>
&lt;h2 id="parte-8-el-mapeo-al-ens">Parte 8. El mapeo al ENS&lt;/h2>
&lt;p>Los códigos y títulos siguientes están verificados contra el texto oficial del Real Decreto 311/2022 publicado en el BOE, Anexo II.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Código&lt;/th>
&lt;th>Título literal&lt;/th>
&lt;th>Qué aporta un IdP central&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>op.acc.1&lt;/td>
&lt;td>Identificación&lt;/td>
&lt;td>Un identificador singular por entidad, usuario o proceso que accede&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>op.acc.2&lt;/td>
&lt;td>Requisitos de acceso&lt;/td>
&lt;td>Los permisos se conceden por rol y grupo, no por credencial suelta&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>op.acc.3&lt;/td>
&lt;td>Segregación de funciones y tareas&lt;/td>
&lt;td>Lo soporta con roles, pero el control es organizativo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>op.acc.4&lt;/td>
&lt;td>Proceso de gestión de derechos de acceso&lt;/td>
&lt;td>Mínimo privilegio y política específica de acceso remoto&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>op.acc.5&lt;/td>
&lt;td>Mecanismo de autenticación (usuarios externos)&lt;/td>
&lt;td>Flujos y factores configurables por flujo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>op.acc.6&lt;/td>
&lt;td>Mecanismo de autenticación (usuarios de la organización)&lt;/td>
&lt;td>Refuerzos exigidos ya en nivel bajo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>op.exp.8&lt;/td>
&lt;td>Registro de la actividad&lt;/td>
&lt;td>Aporta una parte de los eventos, no todos&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>op.exp.10&lt;/td>
&lt;td>Protección de claves criptográficas&lt;/td>
&lt;td>Gestión y rotación de las claves de firma del realm&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Dos matices que un auditor va a buscar.&lt;/p>
&lt;p>El primero, sobre &lt;strong>op.acc.1&lt;/strong>: el texto exige que cada entidad que accede al sistema, sea usuario o proceso, tenga un identificador singular. Eso incluye a los agentes. Una clave virtual compartida entre varios agentes no cumple, y es exactamente lo que suele pasar cuando la autenticación por JWT queda fuera del presupuesto.&lt;/p>
&lt;p>El segundo, sobre &lt;strong>op.exp.8&lt;/strong>: el control exige registrar el identificador del usuario o entidad asociado al evento, la fecha y hora, sobre qué información se realiza, el tipo y el resultado. Keycloak aporta los eventos de autenticación. Los eventos de uso los aportan el gateway y los servidores MCP, y ahí vuelven a aparecer los dos huecos ya documentados: &lt;a href="https://blog.lo0.es/posts/litellm-gateway-mcp-segunda-puerta/">las altas y bajas de servidores MCP no generan registro de auditoría&lt;/a> y &lt;a href="https://blog.lo0.es/posts/litellm-identidad-trazas-costuras/">el usuario de la traza lo pone el cliente&lt;/a>.&lt;/p>
&lt;p>La correspondencia entre control y producto de esta tabla es interpretación propia y debe validarla la entidad de certificación. Los códigos y títulos, no: esos son literales del BOE.&lt;/p>
&lt;h2 id="parte-9-la-configuración-que-hay-que-dejar-escrita">Parte 9. La configuración que hay que dejar escrita&lt;/h2>
&lt;p>Tres piezas concretas, para no quedarse en el nivel de los conceptos.&lt;/p>
&lt;p>&lt;strong>Arranque endurecido&lt;/strong>, como argumentos del contenedor:&lt;/p>
&lt;pre tabindex="0">&lt;code>kc.sh start --optimized \
--hostname=https://sso.ejemplo.es \
--hostname-admin=https://sso-admin.interna.ejemplo.es \
--proxy-headers=xforwarded \
--health-enabled=true \
--metrics-enabled=true \
--http-management-port=9000 \
--cache=ispn --cache-stack=jdbc-ping \
--db=postgres
&lt;/code>&lt;/pre>&lt;p>Las opciones de métricas, salud, caché y base de datos son de compilación: van en la imagen, y pasarlas aquí obliga a reconstruir si no coinciden.&lt;/p>
&lt;p>&lt;strong>El ámbito de cliente con audiencia&lt;/strong>, que es el rodeo obligado por la falta de indicadores de recurso. Creado con la herramienta de administración:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># un ámbito por recurso protegido&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">kcadm.sh create client-scopes -r plataforma &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -s &lt;span class="nv">name&lt;/span>&lt;span class="o">=&lt;/span>mcp-inventario -s &lt;span class="nv">protocol&lt;/span>&lt;span class="o">=&lt;/span>openid-connect &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -s &lt;span class="s1">&amp;#39;attributes.&amp;#34;include.in.token.scope&amp;#34;=true&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># el mapeador que fija la audiencia del token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">kcadm.sh create &lt;span class="s2">&amp;#34;client-scopes/&amp;lt;id&amp;gt;/protocol-mappers/models&amp;#34;&lt;/span> -r plataforma &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -s &lt;span class="nv">name&lt;/span>&lt;span class="o">=&lt;/span>aud-mcp-inventario &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -s &lt;span class="nv">protocol&lt;/span>&lt;span class="o">=&lt;/span>openid-connect &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -s &lt;span class="nv">protocolMapper&lt;/span>&lt;span class="o">=&lt;/span>oidc-audience-mapper &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -s &lt;span class="s1">&amp;#39;config.&amp;#34;included.custom.audience&amp;#34;=https://mcp.ejemplo.es/inventario&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -s &lt;span class="s1">&amp;#39;config.&amp;#34;access.token.claim&amp;#34;=true&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>El cliente pide ese ámbito y recibe un token cuya audiencia es solo ese servidor MCP. El servidor MCP valida la audiencia y rechaza cualquier otro token, como exige la especificación.&lt;/p>
&lt;p>&lt;strong>Importación del realm por GitOps&lt;/strong>, con el recurso personalizado del operador, para que la configuración no viva solo en la consola:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">k8s.keycloak.org/v2beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">KeycloakRealmImport&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">plataforma&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">identidad&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">keycloakCRName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">sso&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">realm&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">realm&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">plataforma&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># sin esto, el correo de recuperación es superficie de ataque&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resetPasswordAllowed&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">bruteForceProtected&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">sslRequired&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">all&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="parte-10-lo-que-keycloak-no-resuelve">Parte 10. Lo que Keycloak no resuelve&lt;/h2>
&lt;p>&lt;strong>Autorización de grano fino sobre recursos.&lt;/strong> La pregunta &amp;ldquo;puede esta persona ver esta traza concreta&amp;rdquo; es una relación entre objetos, no un rol. Ese problema lo resuelven los motores de tipo Zanzibar, con OpenFGA y sus tuplas de objeto, relación y usuario, o un lenguaje de políticas como Cedar. Keycloak da roles y ámbitos, y con ellos no se modela un grafo de relaciones.&lt;/p>
&lt;p>&lt;strong>Secretos de máquina.&lt;/strong> Credenciales de almacenamiento, claves de proveedores, contraseñas de base de datos. Eso es un gestor de secretos, tratado en &lt;a href="https://blog.lo0.es/posts/hardening-secretos-stack-llm-soberano/">el hardening del stack&lt;/a>.&lt;/p>
&lt;p>&lt;strong>Identidad criptográfica de carga con atestación.&lt;/strong> Eso es SPIFFE y SPIRE. En Keycloak existe como proveedor de identidad en vista previa, que es otra cosa.&lt;/p>
&lt;p>&lt;strong>Autorización dentro del modelo.&lt;/strong> Qué herramienta MCP puede invocar un agente, y con qué argumentos. La especificación ofrece ámbitos, el error de ámbito insuficiente y la elevación por pasos, pero la decisión por herramienta y por argumento la toma el servidor MCP o un motor de políticas, no el proveedor de identidad.&lt;/p>
&lt;h2 id="antipatrones">Antipatrones&lt;/h2>
&lt;ol>
&lt;li>Reenviar el token del usuario desde el gateway a servidores MCP de terceros. Prohibido explícitamente por la especificación.&lt;/li>
&lt;li>Identificador de cliente estático con registro dinámico y sin consentimiento por cliente, que es la receta exacta del delegado confuso.&lt;/li>
&lt;li>Ámbitos generales, del tipo acceso total, y publicar el catálogo entero de ámbitos soportados en los metadatos.&lt;/li>
&lt;li>Tratar un manejador de estado como autenticación, que la revisión nueva prohíbe expresamente.&lt;/li>
&lt;li>Seguir el descubrimiento de OAuth hacia cualquier URL, lo que abre la puerta a peticiones hacia direcciones internas. Aplica también al servidor de autorización cuando descarga un documento de metadatos de cliente.&lt;/li>
&lt;li>Cabeceras de confianza mal expuestas en los front de chat. La documentación de Open WebUI avisa de que una configuración incorrecta permite autenticarse como cualquier usuario.&lt;/li>
&lt;li>Arrancar en modo de desarrollo en producción, con el nombre de host sin resolver de forma estricta.&lt;/li>
&lt;li>Una sola clave estática compartida como único control entre el gateway y el motor.&lt;/li>
&lt;/ol>
&lt;h2 id="checklist-de-arranque">Checklist de arranque&lt;/h2>
&lt;ol>
&lt;li>Comprobar la versión. Por debajo de 26.7.2 hay un fallo crítico de restablecimiento de contraseña.&lt;/li>
&lt;li>Construir la imagen con la fase de compilación hecha y arrancar con la bandera de optimizado.&lt;/li>
&lt;li>Nombre de host estricto, consola de administración en otro nombre, puerto de gestión separado y no expuesto.&lt;/li>
&lt;li>Decidir entre organizaciones y un realm por inquilino antes de crear el segundo inquilino.&lt;/li>
&lt;li>Un ámbito de cliente por recurso, con mapeador de audiencia, porque los indicadores de recurso no están soportados.&lt;/li>
&lt;li>En el gateway, definir las dos variables de audiencia y emisor. Sin ellas no se valida nada de eso.&lt;/li>
&lt;li>Para cargas dentro del cluster, mirar el proveedor de identidad de Kubernetes antes de repartir secretos de cliente.&lt;/li>
&lt;li>Dimensionar por picos de inicio de sesión, no por número de servicios: la diferencia es de ocho veces.&lt;/li>
&lt;li>Exportar los eventos de Keycloak al mismo sitio donde van los del gateway, porque el control de registro de actividad los necesita juntos.&lt;/li>
&lt;li>Escribir en el diseño qué hace el sistema con una tarea de dos horas, antes de que alguien resuelva el problema con un token sin conexión.&lt;/li>
&lt;/ol>
&lt;h2 id="cierre">Cierre&lt;/h2>
&lt;p>Keycloak es una pieza madura que resuelve bien un problema acotado: saber quién es quien llama, y decirlo de forma verificable en un documento que caduca. En una plataforma de inferencia soberana eso vale mucho, porque la alternativa es un inventario de claves estáticas repartido por diez servicios que ninguna auditoría puede recorrer.&lt;/p>
&lt;p>Lo que no conviene es pedirle más. La autorización fina vive en cada servicio, la identidad de carga con atestación vive en SPIFFE, y la decisión de qué herramienta puede llamar un agente vive en el servidor MCP.&lt;/p>
&lt;p>Y hay una brecha concreta que conviene tener anotada, porque no se cierra sola: la especificación de MCP marca como obligatorios dos estándares, y de los dos que le corresponderían a un servidor de autorización, los indicadores de recurso no están implementados. El rodeo con ámbitos y mapeador de audiencia funciona, pero es un rodeo, y quien venga detrás buscará el parámetro estándar. Dejarlo escrito en el diseño ahorra una tarde.&lt;/p>
&lt;h2 id="ver-también">Ver también&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/posts/litellm-identidad-trazas-costuras/">El gateway no vive solo&lt;/a>: cómo valida el gateway los tokens que emite esta pieza, y las dos variables que hay que definir.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/mcp-crece-autenticacion-keycloak/">Cuando el MCP crece: ponerle autenticación con Keycloak&lt;/a>: el montaje concreto para servidores MCP.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/litellm-gateway-mcp-segunda-puerta/">El gateway MCP de LiteLLM&lt;/a>: la segunda puerta de entrada, sus permisos y su falta de registro de auditoría.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/identidad-aislamiento-spiffe-confidential-containers/">Cadena de confianza del modelo (4 de 4)&lt;/a>: SPIFFE, SPIRE y la identidad de carga con atestación.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/hardening-secretos-stack-llm-soberano/">Hardening y secretos del stack LLM soberano&lt;/a>: dónde encaja la identidad entre las siete capas.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/litellm-limites-presupuestos-claves-virtuales/">Claves virtuales, presupuestos y límites&lt;/a>: la alternativa cuando el JWT queda fuera del presupuesto.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/controles-tecnicos-ens-42001-eu-ai-act/">Controles técnicos: ENS, ISO 42001 y EU AI Act&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/completar-keycloak-para-mcp/">Completar Keycloak para MCP&lt;/a>: la continuación: el lado del recurso protegido que hay que construir, el intercambio de token y la extensión empresarial de autorización.&lt;/li>
&lt;/ul>
&lt;h2 id="fuentes">Fuentes&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.keycloak.org/2026/08/keycloak-2673-released">Keycloak 26.7.3&lt;/a>, 31 de agosto de 2026, y &lt;a href="https://www.keycloak.org/downloads">descargas&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.keycloak.org/server/configuration">Configuración del servidor&lt;/a>, &lt;a href="https://www.keycloak.org/server/caching">caché&lt;/a>, &lt;a href="https://www.keycloak.org/server/db">bases de datos&lt;/a> y &lt;a href="https://www.keycloak.org/server/hostname">nombre de host&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.keycloak.org/securing-apps/mcp-authz-server">Integración con Model Context Protocol&lt;/a>, &lt;a href="https://www.keycloak.org/securing-apps/token-exchange">intercambio de tokens&lt;/a> y &lt;a href="https://www.keycloak.org/2026/01/federated-client-authentication">autenticación federada de clientes&lt;/a>, 27 de enero de 2026.&lt;/li>
&lt;li>&lt;a href="https://www.keycloak.org/high-availability/multi-cluster/concepts-memory-and-cpu-sizing">Dimensionado de CPU y memoria&lt;/a> e &lt;a href="https://www.keycloak.org/high-availability/introduction">introducción a alta disponibilidad&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.keycloak.org/2025/10/keycloak-benchmark">Bancos de pruebas de rendimiento de Keycloak 26.4&lt;/a>, 1 de octubre de 2025.&lt;/li>
&lt;li>&lt;a href="https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization">Especificación de MCP, revisión 2026-07-28, autorización&lt;/a> y &lt;a href="https://modelcontextprotocol.io/docs/2026-07-28/tutorials/security/security_best_practices">buenas prácticas de seguridad&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-auth/3331-structured-authentication-configuration">KEP-3331, configuración estructurada de autenticación&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.boe.es/diario_boe/xml.php?id=BOE-A-2022-7191">Real Decreto 311/2022, Anexo II&lt;/a>.&lt;/li>
&lt;li>Registro de &lt;code>CVE-2026-18963&lt;/code> en la base de datos de Red Hat y notas de la versión 26.7.3 en GitHub.&lt;/li>
&lt;li>&lt;a href="https://www.cncf.io/projects/keycloak/">CNCF, proyecto Keycloak&lt;/a>.&lt;/li>
&lt;/ul></description></item></channel></rss>