- Es un procedimiento de despliegue de SSO en una sola VM Linux, ejecutando Keycloak aislado con Docker rootless, mientras nginx del sistema se encarga de la terminación TLS y del proxy inverso
- Los requisitos previos son acceso por SSH, un dominio o subdominio para Keycloak, un registro
A, un usuario keycloak sin contraseña, el directorio home /srv/keycloak y una instalación de Docker rootless
docker-compose.yml usa postgres:16 y quay.io/keycloak/keycloak:25.0.1; Keycloak se enlaza solo a 127.0.0.1:8080 y las contraseñas y KC_HOSTNAME se administran desde .env
- nginx redirige las solicitudes HTTP de
your.tld.com a HTTPS y las reenvía con proxy_pass; después de emitir el certificado con Certbot, se habilita KC_PROXY_HEADERS: xforwarded
- Si se necesita un tema personalizado o ejecutar con
--optimized, se crea una imagen propia con un Dockerfile multietapa, y en producción se pueden ajustar además el tamaño de los buffers de JGroups y la configuración de recuperación de transacciones de Quarkus
Estructura del despliegue y requisitos previos
- Keycloak es una opción de IAM open source que se puede usar cuando resulta difícil implementar directamente la gestión de usuarios y SSO en una aplicación web
- Interopera con los principales protocolos de SSO como
OpenID Connect (OIDC), OAuth 2.0 y SAML
- La configuración se escribió tomando como base Keycloak
23.0.6 y se probó hasta 25.0.5
- La estructura general usa nginx como proxy inverso central, reenviando el tráfico por localhost hacia namespaces de Docker rootless separados por servicio
- El tráfico web entra por
0.0.0.0:80 y 0.0.0.0:443, y nginx lo reenvía a Keycloak en 127.0.0.1:8080
- El objetivo es una configuración económica que comparte los recursos de un único host mientras separa los entornos de servicio
Preparación
- Como entorno base se necesita una VM Linux, acceso remoto por SSH y un dominio o subdominio para el servicio Keycloak
- El dominio necesita un registro
A y, opcionalmente, se puede agregar un registro AAAA
- La configuración básica de Docker rootless sigue el procedimiento de otra publicación de Mastodon
- Crear un nuevo usuario non-root
keycloak sin contraseña
- Establecer el directorio home en
/srv/keycloak
- Agregar el rango del usuario
keycloak en /etc/subuid y /etc/subgid
- Instalar Docker rootless con
dockerd-rootless-setuptool.sh
- Configurar el inicio automático del servicio del usuario
keycloak
Ejecutar Keycloak con Docker Compose
- Al entrar con el usuario
keycloak recién creado, usar machinectl shell keycloak@
- Se evita el método
sudo -u keycloak -H bash porque no prepara la variable de entorno XDG_RUNTIME_DIR
- Primero crear los directorios para datos persistentes y archivos Docker
- La ruta de datos de PostgreSQL es
/srv/keycloak/data/postgres16
- Los archivos Docker se colocan en
~/docker
docker-compose.yml usa directamente la imagen oficial de Keycloak y PostgreSQL
- La imagen de PostgreSQL es
postgres:16
- La imagen de Keycloak es
quay.io/keycloak/keycloak:25.0.1
- En entornos de producción se recomienda usar una etiqueta de imagen específica en lugar de
:latest
- La configuración principal del contenedor de Keycloak es la siguiente
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres_db/keycloak
KC_HOSTNAME: ${KC_HOSTNAME:-your.tld.com}
KC_HTTP_ENABLED: true
HTTP_ADDRESS_FORWARDING: true
KEYCLOAK_ADMIN: admin
- El puerto se enlaza solo a localhost con
'127.0.0.1:8080:8080'
- En
.env se colocan valores sensibles o que varían según el entorno
POSTGRES_PASSWORD
KEYCLOAK_ADMIN_PASSWORD
KC_HOSTNAME
- La sintaxis
${KC_HOSTNAME:-your.tld.com} usa el valor de KC_HOSTNAME si existe en .env; si no existe, usa your.tld.com como valor predeterminado
/srv/keycloak/data/postgres16 contiene los datos persistentes de PostgreSQL, por lo que debe incluirse en respaldos periódicos
- Para reinicializarlo por completo, borrar esa carpeta de PostgreSQL y volver a crearla; se generará nuevamente en el siguiente inicio
- Si administras
~/docker como repositorio Git, puedes agregar .env a .gitignore y commitear solo docker-compose.yml
Prueba local
- Iniciar el stack de Docker Compose y revisar los logs
docker compose up -d && docker compose logs --follow
- Para acceder al puerto local de Keycloak en la VM, crear un túnel SSH inverso
ssh you@111.11.11.11 -L :8080:127.0.0.1:8080 -p 22 -N -v
- Abrir
127.0.0.1:8080 en el navegador y verificar la pantalla de bienvenida de Keycloak
Proxy inverso nginx y TLS
- Después de cerrar sesión del usuario
keycloak, configurar nginx del sistema
- Reemplazar
your.tld.com por el dominio real y agregar un registro A en el registrador del dominio para que las consultas DNS apunten a la IP de la VM
- Crear y habilitar el archivo de configuración del sitio nginx
nano /etc/nginx/sites-available/your.tld.com.conf
ln -s /etc/nginx/sites-available/your.tld.com.conf /etc/nginx/sites-enabled/
- La configuración de nginx redirige las solicitudes HTTP a HTTPS y, en el bloque del servidor HTTPS, hace proxy hacia Keycloak
proxy_set_header Host $host
proxy_set_header X-Real-IP $remote_addr
proxy_set_header X-Forwarded-For $remote_addr
proxy_set_header X-Forwarded-Proto $scheme
proxy_pass http://127.0.0.1:8080
- Para la configuración SSL se recomienda usar Mozilla SSL configurator for nginx para generar valores predeterminados adecuados a la versión de nginx
- Probar la configuración y recargar nginx
nginx -t
systemctl reload nginx
- Al emitir el certificado con Certbot, las líneas necesarias en
your.tld.com.conf se actualizan automáticamente
certbot --nginx -d your.tld.com
- Después, habilitar
ssl_trusted_certificate /etc/letsencrypt/live/your.tld.com/chain.pem; y recargar nginx
- Para que funcione detrás de nginx, habilitar
KC_PROXY_HEADERS: xforwarded en docker-compose.yml y reiniciar el stack Docker
docker compose down && docker compose up -d && docker compose logs --follow
Ruta de depuración
- Después de configurar, conectarse a
your.tld.com y verificar el inicio de sesión del usuario admin con la contraseña de .env
- El primer punto de revisión son los logs de Docker Compose
docker compose logs --follow
- Revisar los logs de acceso y error de nginx siguiendo estos archivos
tail -f /var/log/nginx/your.tld.com-access.log
tail -f /var/log/nginx/your.tld.com-error.log
- Si necesitas revisar directamente la base de datos de Keycloak, entra como usuario
keycloak y ejecuta psql dentro del contenedor PostgreSQL
machinectl shell keycloak@
cd ~/docker
docker compose exec postgres_db /bin/bash
psql -h localhost -p 5432 -U keycloak keycloak
Imagen personalizada y ejecución optimized
- La configuración básica usa la imagen precompilada de
quay.io
- Si se requiere personalizar temas o ejecutar en modo
--optimized, se construye una imagen propia
- El Dockerfile usa una compilación multietapa basada en la imagen oficial de Keycloak
- En la etapa builder, establecer
ENV KC_DB=postgres
- Ejecutar
/opt/keycloak/bin/kc.sh build
- Copiar
/opt/keycloak/ a la imagen final
- Definir
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
- En
docker-compose.yml, cambiarlo así
- Eliminar o comentar la línea
image:
- Habilitar
build: .
- Agregar
command: start --optimized
- Luego detener el stack Docker, opcionalmente ejecutar un build explícito y volver a iniciarlo
docker compose down
docker compose build
docker compose up -d && docker compose logs --follow
Ajustes adicionales realizados en producción
- La advertencia de buffer de recepción de
MulticastSocket relacionada con JGroups se resuelve agregando valores de buffer en /etc/sysctl.conf del host
net.core.rmem_max = 26214400
net.core.wmem_max = 1048576
- Para aplicar la configuración, ejecutar
sysctl -p
- La advertencia de recuperación de transacciones XA de Quarkus se resuelve agregando un montaje de volumen y una variable de entorno al servicio Keycloak
- Volumen:
/srv/keycloak/data/keycloak/ObjectStore/:/ObjectStore/
- Variable de entorno:
QUARKUS_TRANSACTION_MANAGER_ENABLE_RECOVERY: true
- Antes de iniciar, crear el directorio ObjectStore en el host y cambiar el propietario de
/ObjectStore dentro del contenedor al ID de usuario 1000
Pasos posteriores a la configuración
- El estado final es una configuración en la que el servicio Keycloak dentro de Docker rootless se ejecuta detrás del proxy inverso nginx del sistema, y nginx se encarga de la terminación SSL
- Para las actualizaciones automáticas de contenedores, consultar el procedimiento de actualización automática en otra publicación de Mastodon
- El siguiente paso de configuración es agregar el correo electrónico desde la consola de administración de Keycloak
- Luego se puede continuar con la creación de realms y la configuración de temas
- Para los temas se pueden usar keycloakify y keycloakify-starter
- El Dockerfile incluye una línea comentada para copiar el JAR del tema de keycloakify a
/opt/keycloak/providers/
1 comentarios
Opiniones de Hacker News
Hace poco, al agregar autenticación a mi homelab, elegí Authelia
Keycloak también funciona, pero es demasiado grande, y para usarlo con traefik forward auth se necesita otro servicio adicional
Authelia no tiene una UI para editar usuarios y tampoco sincronización bidireccional con un servidor LDAP backend, pero se puede configurar solo con archivos estáticos y variables de entorno, así que encaja bien en muchos casos
Si lo que buscas es agregar autenticación a algunos servicios y sumar SSO donde sea posible, vale la pena empezar por Authelia
Si necesitas SSO, configuración sencilla y una UI de administración, FusionAuth también vale la pena. La UI/UX sí se siente de mediados de los 2000, pero se puede descargar y ejecutar directamente[0], es compatible con Docker[1], y ofrece varias formas de configuración[2], como administrar OIDC u otros ajustes con Terraform[3]
Se puede usar gratis, pero no es open source[4]
0: https://fusionauth.io/download
1: https://fusionauth.io/docs/get-started/download-and-install/...
2: https://fusionauth.io/docs/operate/deploy/configuration-mana...
3: https://fusionauth.io/docs/operate/deploy/terraform
4: https://fusionauth.io/license-faq#28
Uso Caddy como reverse proxy y lo integré con Authelia[1]; funciona bien
Agregué autenticación de dos factores sólida a todos los servicios, y siento que es lo suficientemente seguro acceder a apps autoalojadas sin VPN
Sin embargo, me preocupa la seguridad porque Authelia lleva más de un año sin nuevos releases
[0] https://github.com/lldap/lldap
[1] https://www.authelia.com/integration/proxies/caddy/
[1] https://github.com/greenpau/caddy-security
Es un caso de uso muy bueno para entornos de homelab, y encaja especialmente bien si no necesitas o no quieres las funciones de soluciones más grandes
Por más que busco, no encuentro nada con una forma tipo esquema simple, JSON o HTTP, y me cuesta creer que las personas que reinventaron casi todo no hayan reinventado LDAP
Hasta donde sé, en la práctica el único otro estándar es Active Directory
También me pregunto si existe algún estándar o protocolo para delegar el control de acceso a un sistema externo
Authelia puede controlar el acceso por patrones de URL, pero, por ejemplo, en el caso de un servidor de archivos, esperaría algo como consultar permisos en un servidor LDAP tomando como base el ID del usuario autenticado y una clave en la base de datos
Esto parece ir en la dirección opuesta a OAuth2, donde el servidor obtiene permisos de acceso a servicios de terceros
Hace poco estuve investigando cómo configurar un SSO relativamente simple en mi homelab, y el objetivo principal era iniciar sesión fácilmente con autenticación de Google o GitHub
En mi trabajo anterior usé tanto JetBrains Hub[1] como Keycloak, y ambos eran bastante molestos de configurar
JetBrains Hub era realmente fácil de poner en marcha, y esa también fue mi experiencia anterior, pero me resultó incómodo que no hubiera una etiqueta latest en el registro de Docker
Sé que fijar versiones es una buena práctica, pero para uso personal normalmente quiero actualizar todos los contenedores Docker de una sola vez
En cambio, Keycloak fue muy engorroso para empezar; en modo de desarrollo era fácil, pero me trabé con la configuración de producción
Según recuerdo, tenía que ver con un certificado comodín de Let's Encrypt, y después de unas horas me rendí
Al final elegí Dex[2]. Lo había postergado por falta de documentación, pero la configuración real fue muy sencilla: un YAML básico, una base de datos SQLite y un subdominio alcanzaron
Combiné Dex con el excelente OAuth2 Proxy[3] y una plantilla personalizada de Nginx Proxy Manager para dejar una configuración de SSO de dos líneas por cada servicio interno, y también hice una plantilla Docker de Dex para unRAID[4]
Además, fuera de casa agregué Cloudflare Access y WAF para reforzar la seguridad, y solo me gustaría sumar CrowdSec para obtener un poco más de visibilidad
Personalmente, creo que es la opción más simple
https://github.com/lastlogin-io/obligator
Hice una tabla comparativa incompleta de varios servidores OpenID Connect que se pueden autoalojar[0]
Una de las cosas que me sorprendió fue lo enorme que es realmente el codebase de Keycloak
[0]: https://github.com/lastlogin-io/obligator?tab=readme-ov-file...
Es graciosa la idea de que Keycloak te resuelve los problemas de seguridad
Si miras la lista de CVE, entiendes a qué me refiero
También sería ridículo decir que una solución cerrada y poco transparente, sin CVE reportadas, es “segura”
Además, la versión más reciente, 22.0.2, solo tiene 3 vulnerabilidades conocidas
https://www.cvedetails.com/vulnerability-list/vendor_id-25/p...
Al menos fue muy útil que ese artículo mencionara https://www.keycloakify.dev/
Parece una gran alternativa al enfoque estándar de temas
Lo uso desde hace 2 años y no tengo más que cosas buenas para decir
El mantenedor responde muy rápido, y recientemente tanto Keycloak como keycloakify incorporaron cambios que mejoran la compatibilidad futura del enfoque de temas
Por ahora oficialmente solo admite apps creadas con create-react-app, pero hay una rama vite en desarrollo y, personalmente, ya lo vengo usando con vite desde hace un tiempo
Estoy siguiendo de cerca a authentik[1] y authelia[2]
Authelia se ve muy bien, pero mientras que Keycloak tiene un conector para Angular, con Authelia habría que configurar directamente, por ejemplo, un plugin OIDC para Angular, así que me daba un poco de cautela
Aun así, si ya hay una configuración para Keycloak, creo que sería más fácil empezar
[1] https://goauthentik.io/
[2] https://www.authelia.com/
Protejo constantemente más de 10 servicios en Docker y Kubernetes, y si no te gusta configurar la protección de cada servicio de forma independiente, vas a sufrir con authentik
authentik tiene un bug grave[0] cuando se protegen varios subdominios (app1.example.com, app2.example.com, etc.) con una sola configuración: después de que expira la sesión y el usuario se vuelve a autenticar, se lo redirige aleatoriamente a otro servicio
[0]: https://github.com/goauthentik/authentik/issues/6886
No se puede arreglar sin cambios que rompan compatibilidad, y no funciona con muchas herramientas que usan el grant cc
Después de ver eso, lo descarté por completo como candidato
https://github.com/goauthentik/authentik/issues/6139
Si hay algo en lo que pueda ayudar con la configuración de Angular, con gusto lo haré a través de GitHub Discussions
Authentik se veía mejor, pero el bug mencionado en otra respuesta se ve bastante malo
El problema de Keycloak es que es un proyecto antiguo y ha cambiado muchísimo
Empezó como un proyecto de JBOSS, y creo que su utilidad como IdP brilla en la autenticación de clústeres on-premises, pero hasta ahí llega
Implementé Keycloak a gran escala en AWS ECS para una división de Fortune 500, y lograr que clusterizara correctamente fue como una guerra de mil años
El descubrimiento por DNS no funcionaba bien, y el descubrimiento del clúster estaba basado en UDP, así que no servía en entornos cloud
Un login con estado en un servidor no existía en otro, así que el balanceo de carga simple era imposible, y las sesiones sticky eran la única opción
Levantar Keycloak con
docker runy enchufarlo como Auth0 es fácil, pero se siente como comprar una Ford F-150 de 1996 con 250 mil millasAnda y funciona, pero el mantenimiento es verdaderamente horrible
Por lo que recuerdo, el método de descubrimiento predeterminado usa multicast, que no está habilitado en redes cloud típicas ni en redes overlay de Swarm/Kubernetes
También vi database ping, que usa un RDBMS como una especie de mecanismo de quórum, pero se veía muy frágil y se sentía como un último recurso
Al final pude usar el driver de clúster de Kubernetes, que descubre nodos mediante el DNS del clúster de Swarm
Costó bastante hacerlo funcionar, pero desde entonces, hasta donde sé, es estable
Parece que hoy también hay un driver de red nativo para EC2, pero no lo he investigado personalmente
Me da curiosidad cuándo fue esa implementación en ECS
Nosotros solo tenemos permitido UDP para DNS
Keycloak es excelente, pero puede ser bastante confuso para principiantes
Tiene muchas funciones y la documentación no es la mejor
Hace poco probé Zitadel y fue mucho más fácil de usar
Eso sí, no puede ejecutarse con una base de datos integrada, así que el self-hosting es un poco más difícil
A futuro van en dirección de usar Postgres como base de datos, así que espero que sea más fácil desplegarlo junto con otras herramientas
Mi jefe llamó hace poco a Keycloak “el regalo que sigue dando”, pero en realidad quería decir que siguen apareciendo tickets de Jira nuevos para averiguar cómo hacer algo
Aun así, tenemos Terraform que crea un clúster EKS y despliega Keycloak, crea clientes SAML/OIDC, agrega proveedores de identidad externos e incluso configura un AWS IAM Identity Provider
Una vez que averiguas qué se puede hacer, cómo hacerlo en la UI y cómo automatizarlo con el provider de Terraform de mrparkers, usarlo en sí se vuelve muy fácil
Un amigo lo necesita :)
Después de usar Keycloak durante varios años, la verdad es que me cansé de todo tipo de comportamientos raros y empecé a buscar alternativas
Varias opciones como Authentik se veían bien, pero Zitadel[1] me llamó la atención, y desde entonces no miré atrás
[1] https://zitadel.com/blog/zitadel-vs-keycloak
Me da curiosidad qué fue lo que te atrajo de forma decisiva