Acelerando los desarrollos con contenedores: Keycloak

Publicado por Víctor Madrid el

Arquitectura de SolucionesKeycloakIAMIdP

En este artículo se va a mostrar cómo poder disponer de un contenedor de Keycloak de forma rápida para utilizarlo durante el desarrollo como infraestructura que proporcione la funcionalidad de gestión de identidades y de accesos.

La gestión de identidades y de accesos dentro de la seguridad siempre son temas muy controvertidos y eso se puede ver en aspectos como los siguientes:

  • Flujos de entrada a las aplicaciones
  • Requerimientos de autenticación
  • Grupos de usuarios
  • Auditoría de todos los accesos a aplicaciones
  • Principio de mínimo privilegio para un usuario
  • Múltiple factor de autenticación -> 2FA
  • Revocación de accesos
  • Olvido de contraseñas
  • Validación de cuentas
  • Cambio de password
  • Caducidad de tokens
  • Aplicaciones con passwords personales (ficheros de configuración, variables de entorno, etc.)
  • ... un millón de cosas más ....

¿Os suenan?

Madre mía... ya me he agobiado solo de nombrarlos :-(

¿Qué es Keycloak?

Keycloak es un producto Open Source escrito en Java muy popular en el mundo de las herramientas IAM y de los IdP, esta soportado por Red Hat lo que da un poco de tranquilidad y que se encuentra bajo una licencia de Apache.

Para los más curiosos diré que utiliza un servidor de aplicaciones Wildfly, pero tranquilos que NO lo vamos a tener que tocar.

¿Qué es IAM (Identity and Access Management)?

La gestión de identidades digitales de los usuarios ("quién soy yo") y su acceso ("qué puedo hacer"). En resumen, estaríamos hablando de "quién es un usuario y qué permisos/privilegios tiene a la hora de hacer cosas (acceder a recursos, ejecutar operaciones, etc.)"

Conviene aclarar que las identidades digitales pueden hacer referencia a :

  • Personas
  • Máquinas
  • Aplicaciones
  • ...
¿Qué es un IdP (Proveedor de Identidades)?

Un componente que almacena y gestiona las identidades digitales de los usuarios

Características

Algunas de las características principales que Keycloak proporciona son:

  • Centralización de la autenticación en un proyecto u organización -> Proporcionando Autenticación en modo SaaS
  • Proporciona un inicio de sesión único (SSO Single Sign On)
  • Gestión de Identidades
  • Gestión de Accesos
  • Facilita conectarse a sistemas de LDAP, AD, Kerberos, ...
  • Facilita disponer de login social (Google, Facebook, Github, ...)
  • Soporte para diferentes protocolos estándar (SAML v2 y OpenID Connect (OIDC)/OAuth2)
  • Trabaja con diferentes métodos de autenticación
  • Proporciona soluciones a problemas como : olvido de contraseñas, validación de cuentas, cambiar password inicial, etc.
  • Proporciona la posibilidad de definir workflows
  • Instalación on-premise o bien mediante el uso de contenedores
  • Facilidades de extensibilidad : base de usuarios, protocolos, métodos de autenticación, etc. -> FIDO
  • Customización de temas para pantallas de login, etc.
  • Alta disponibilidad
  • Escalabilidad
  • Proporciona la funcionalidad de "Múltiple Factor de Autenticación" (2FA)
  • Revocar sesiones
  • Audita
  • Integración con diferentes bases de datos (h2, mysql, mariadb, etc.)
  • Existen diferentes formas de conectarnos a la herramienta desde el punto de vista del desarrollo / integración:
  • Atacando directamente al API
  • Utilizando alguna librería disponible que facilite su uso
  • Adaptadores sobre servidores de aplicaciones
  • Etc.
  • ...

En definitiva es un gestor de login con mogollón de funcionalidades "out of the box" avanzadas, con una documentación bastante buena y un API muy potente.

Y la principal decisión para utilizar esta pieza en los proyectos o bien en las organizaciones os va a encantar...

¿Sabéis cuál puede ser?

Pues servir de producto funcional y terminado que se encargue de la autenticación. Es decir, que los desarrolladores ya NO tienen que diseñar ni implementar esta pieza que tanto tiempo y dolores de cabeza nos lleva siempre.

Ejemplos "Clásicos" :
Gestión de usuarios/passwords con:
  • Ficheros de texto planos
  • Bases de datos (clásica base de datos de usuarios, roles y permisos)
  • LDAP / AD
  • Password managers

Tenemos que considerar que :

  • Este tipo de productos (desarrollado a medida o de terceros) se consideran una pieza corporativa básica
  • La funcionalidad de autenticación normalmente hay que implementarla en el 95% de los casos
  • Se produce una reducción de los dolores de cabeza por parte de los desarrolladores para implementarla y por los problemas que suele generar
  • Ahorro de tiempo
  • Ahorro de costes por todo lo anterior
  • ...

Por lo tanto... ganamos todos :-)

Este artículo está dividido en 4 partes:

  • 1. Introducción
  • 2. Stack Tecnológico
  • 3. Ejemplos de Uso
  • 4. Conclusiones

1. Introducción

En este apartado se tratarán los siguiente puntos :

  • 1.1. Introducción al uso de contenedores como aceleradores del desarrollo
  • 1.2. ¿Qué necesidades tenemos para tener un "Keycloak" con contenedores?

1.1. Introducción al uso de contenedores como aceleradores del desarrollo

Para centralizar esta información en un único punto y así poder facilitar su consulta se ha diseñado un artículo específico.

1.2. ¿Qué necesidades tenemos para requerir un "Keycloak" con contenedores?

Los motivos principales que me llevaron a tratar de investigar en tener un Keycloak dentro de un contenedor fueron los siguientes:

  • Disponer de una instalación inmutable
  • Replicar la instalación del producto del cliente en local (versionado, entorno, etc.)
  • Minimizar en un entorno previo los posibles cambios de configuración que pudiéramos requerir --> Perdiendo el miedo a los cambios :-)
  • Asegurarse de que a todo el mundo le funcionaba de primeras
  • Ayudar al equipo a coger experiencia en el uso de Keycloak
  • Disponer en el entorno local de la misma pieza que se utilizará en entornos altos
  • Investigar previamente cómo funciona su API de integración
  • Ayudarme a establecer cierta lógica de negocio, gestión de errores sobre la pieza de desarrollo a realizar
  • ...

2. Stack Tecnológico

Este es stack tecnológico elegido para implementar la funcionalidad "Keycloak":

  • Docker - Tecnología de Contenedores/Containers
  • Docker Hub - Repositorio de Docker Público donde se ubican las imágenes oficiales
  • Keycloak - Herramienta IAM / IdP

3. Ejemplos de Uso

Para enseñar a utilizarlo y así practicar se ha habilitado un repositorio, este repositorio se reutilizará para otros artículos de "Acelerando los desarrollos con contenedores".

La parte que tiene que ver con este artículo se encuentra en el apartado de docker/keycloak/basic.

Este proyecto consta del siguiente elemento:

  • Contenedor de Keycloak
  • Proporciona la instalación del producto en la versión establecida o bien en la última versión disponible en Docker Hub
  • Modo standalone (sin persistencia)
  • Sin datos iniciales
  • Proporciona la configuración para su uso (usuarios, password, etc.) con una cuenta del tipo admin mediante variables de entorno (esta funcionalidad esta proporcionada por el propio contenedor). Este usuario facilita el acceso a la plataforma y permite crear nuevos realms, nuevos clientes, ...
  • Proporciona la configuración para ver trazas de depuración

Ejemplo de fichero "docker-compose.yaml"

version: '3'  
services:

  keycloak:
    #image: jboss/keycloak
    image: jboss/keycloak:16.1.0
    environment:
      KEYCLOAK_USER: admin
      KEYCLOAK_PASSWORD: password
      KEYCLOAK_LOGLEVEL: DEBUG
      ROOT_LOGLEVEL: DEBUG
    ports:
      - '8083:8080'

Para ver como lanzarlo ver fichero README dentro del proyecto.

También se puede lanzar directamente tras la ejecución del siguiente comando de Docker

docker run -p 8083:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=password jboss/keycloak:16.1.0 -Dkeycloak.profile.feature.docker=enabled -b 0.0.0.0  

3.1. Scripts de Soporte

N/A

3.2. Investigar lo que se usa

Cuando uno crea un contenedor basado en una imagen, ya se ha visto que consideraciones se deben tener para llegar a entender que es lo que hace.

Si tienes alguna duda vuelve a revisar el apartado "Soporte de Análisis de Contenedores" del artículo de introducción : Acelerando los desarrollos con contenedores: Introducción.

Ejemplo de ejecución para mostrar la información del proceso ejecutado tras realizar un "up"

Ejemplo de inspección sobre el contenedor creado

Ejemplo de investigación general dentro del contenedor

Se podrán validar algunos de los aspectos configurados

3.3. Verificar resultados

Se accede a la URL del Keycloak con:

http://localhost:8083/  
  • Acceder a la consola de administración (Administration Console)
  • Verificar el acceso con el usuario declarado en las variables de entorno

3.4. Preparación de la Configuración

Creación de un Realm

¿Qué es un Realm?
Objeto que representa dentro de Keycloak a un conjunto de usuarios, roles, clientes y grupos
Se podría considerar como una "configuración", se puedes disponer de varios cada uno con unas características. Por ejemplo  un realm para usuarios internos con autenticación sobre su base de datos y otro realm con autenticación por LDAP
Proporciona diferentes funcionalidades en sus pestañas
Existe un realm por defecto que se denomina "Master"
Los realms están aislados los unos de los otros
Solo pueden ser gestionados y autenticados por usuarios que ellos gestionan

Pasos a seguir:

  • Acceder a la plataforma con el usuario admin utilizado (si es necesario)
  • Añadir un realm nuevo desde el desplegable superior de la izquierda
  • Por defecto pondrá "Master" (realm proporcionado por defecto)
  • Pulsar sobre el botón "Add realm"
  • Establecer el nombre del realm : test
  • Pulsar sobre el botón "Create"
  • Verificar que se ha cargado las opciones de configuración del nuevo realm "test" (Opción "Realm Settings" marcada en el menu de la izquierda)
  • Al crear el realm automáticamente se cambia de realm
  • En la pestaña "Login"
  • Activar la opción "User registration" para permitir registro de usuarios
  • Pulsar sobre el botón "Save"

Creación de un Cliente

¿Qué es un Cliente?
Objeto que representa a una aplicación o servicio que funcionará como un cliente que usará Keycloak para autenticarse
Existen varios cliente por defecto
Se suelen considerar "usuarios no humanos" y no necesitan usuario/password

Pasos a seguir:

  • Acceder a la plataforma con el usuario admin utilizado (si es necesario)
  • Seleccionar el realm objetivo -> En nuestro caso el creado anteriormente "test"
  • Acceder a la opción "Clients" del menú lateral izquierdo
  • Pulsar sobre el botón "Create"
  • Establecer el client id : client-postman
  • Establecer el client protocol : openid-connect
  • Establecer el client name (opcional)
  • Establecer la client description (opcional)
  • Verificar que el client protocol es "openid-connect" (Para nuestro casso concreto)
  • Establecer el access type : confidential
  • Significa que requerirá "client id" y "client secret"
  • Aparecerán unas opciones particulares al seleccionarla
  • La app cliente requerirá incluir los valores clientid y clientsecret  en la solicitud de token de acceso
  • Establecer como Valid Redirect URIs: http://localhost:8083/*
  • Debería ser la URL de la aplicación sobre la que redirigir en caso de utilizar un desarrollo
  • Habilitar la opcion "Service Account Enabled" -> Se podrán copiar "client credentials" y así usarlas en peticiones HTTP
  • Proporciona el soporte de "Client Credentials Grant" a este cliente
  • Pulsar sobre el botón "Save"
  • Copiar el campo Client ID (por ejemplo en un fichero de texto, ya que luego lo utilizaremos)
  • Pulsar sobre la pestaña "Credentials"
  • Verficar que el campo Cliente Authenticator tiene la opcion marcada de "Client Id and Secret"
  • Copiar el valor "Client Secret" (por ejemplo en el mismo fichero que antes)

Creación de un Usuario

Pasos a seguir:

  • Acceder a la plataforma con el usuario admin utilizado (si es necesario)
  • Acceder a la opción "Users"
  • Pulsar sobre el botón "Add user" de la cabecera de la tabla
  • Establecer el username : user1
  • Pulsar sobre el botón "Save"

Configuración del Usuario

Pasos a seguir:

  • Pulsar sobre la pestaña "Credentials"
  • Establecer el password : user1
  • Confirmar el password
  • Deshabilitar la opción "Temporary"
  • Flag que obliga a cambiar la password cuando el usuario se conecte la primera vez
  • Pulsar sobre el botón "Set Password"
  • Confirmar la ventana modal

Debido a que el sistema de Keycloak esta basado en roles por usuario, sería interesante crear un rol y asociarlo a un usuario. En nuestro caso no lo hemos hecho, pero si fuera necesario se realiza de la siguiente manera

  • Acceder a la opción "Roles"
  • Pulsar sobre el botón "Add user"
  • Establecer el role name : role-test
  • Pulsar sobre el botón "Save"
  • Acceder sobre el usuario seleccionado
  • Seleccionar pestaña de "Role Mappings"
  • Añadir el role "role-test"

3.5. Probar la generación de un token

En esta sección enseñaré como obtener token con carácterísticas diferentes

  • 3.5.1. Generación de un token de acceso de administrador (Admin Access Token) con la estrategia "Password Grant"
  • 3.5.2. Generación de un token de acceso de administrador (Admin Access Token) con la estrategia "Client Credential Grant"
  • 3.5.3. Generación de un token de acceso de usuario apartir de "Client Credential Grant"
Importante
Las especificaciones de OAuth 2.0 dice que el token de actualización (refresh token) no debe incluirse en la respuesta
Keycloak incluye el token de actualización (refresh token) de todos modos

Tras recibir el access token ya se podría trabajar para acceder a los recursos

3.5.1. Generación de un token de acceso de administrador (Admin Access Token) con la estrategia "Password Grant"
Importante
NO lo recomiendo porque obliga a incluir el nombre de usuario y la constraseña del administrador principal/master en la petición
Hace uso del realm "Master"
Usando un token de acceso de administrador se pueden hacer muchas cosas, así que hay que tener cuidado

Para ello vamos a ejecutar una petición POST con la siguiente estructura :

Estructura de la petición

#URL
http://localhost:8083/auth/realms/master/protocol/openid-connect/token

La URL apunta al realm "master"

#HEADER
Content-Type: application/x-www-form-urlencoded

#BODY
{
    'username': 'username_admin_master',
    'password': 'password_admin_master',
    'client_id': 'admin-cli',
    'grant_type': 'password'
}

No cambiar los valores de client_id y grant_type

En nuestro ejemplo  
* username y el password serían los pasados como variables de entorno en el contenedor

Ejemplo de cURL

curl --location --request POST 'http://localhost:8083/auth/realms/master/protocol/openid-connect/token' \  
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=XXX' \
--data-urlencode 'password=YYY' \
--data-urlencode 'client_id=admin-cli' \
--data-urlencode 'grant_type=password'
3.5.2. Generación de un token de acceso de administrador (Admin Access Token) con la estrategia "Client Credential Grant"

Este método nos permite solicitar el token de administrador proporcionando : client-id y client-secret

Ya NO se requiere utilizar el usuario y la password del administrador

Para poder utilizar esta estrategia se requiere :

  • Configurar como "confidencial" el usuario "admin-cli" del realm "master"
  • La opción "Service Accounts Enabled" debería de estar activa

Para ello vamos a ejecutar una petición POST con la siguiente estructura :

Estructura de la petición

#URL
http://localhost:8083/auth/realms/master/protocol/openid-connect/token

La URL apunta al realm "master"

#HEADER
Content-Type: application/x-www-form-urlencoded

#BODY
{
    'client_id': 'admin-cli',
    'client_secret': 'XXX',
    'grant_type': 'client_credentials'
}

No cambiar los valores de client_id y grant_type  

Ejemplo de cURL

curl --location --request POST 'http://localhost:8083/auth/realms/master/protocol/openid-connect/token' \  
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=admin-cli' \
--data-urlencode 'client_secret=XXX' \
--data-urlencode 'grant_type=client_credentials'
3.5.3. Generación de un token de acceso de usuario apartir de "Client Credential Grant"

Para ello vamos a ejecutar una petición POST con la siguiente estructura:

Estructura de la petición

#URL
http://localhost:8083/auth/realms/test/protocol/openid-connect/token

La URL apunta al realm "test"

#HEADER
Content-Type: application/x-www-form-urlencoded

#BODY
{
    'username': 'custom_username',
    'password': 'custom_userpassword',
    'client_id': 'custom_client_id',
    'client_secret': 'custom_client_secret',
    'grant_type': 'client_credentials'
}

No cambiar los valores de client_id y grant_type  

Ejemplo de cURL

Sustituir las "xxx" por el valor almacenado en el fichero (secret del cliente)

curl --location --request POST 'http://localhost:8083/auth/realms/test/protocol/openid-connect/token' \  
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=XXX' \
--data-urlencode 'password=YYY' \
--data-urlencode 'client_id=ZZZ' \
--data-urlencode 'client_secret=WWW' \
--data-urlencode 'grant_type=password'

Se podrá verificar que se devuelve el token de acceso :-)

3.6. Exportar la configuración

Vamos a exportar la configuración para poderla utilizar en el siguiente artículo.

Pasos a seguir:

  • Acceder a la plataforma con el usuario admin utilizado (si es necesario)
  • Acceder al realm sobre el que se quiere trabajar
  • Pulsar sobre el botón "Export" del menu lateral (Abajo Izquierda)
  • Activar 'Export groups and roles'
  • Activar 'Export clientes'
  • Pulsar sobre el botón "Export"
  • Confirmar el botón "Export" de la modal
  • a partir de aquí se puede como se ha descargado un JSON de Keycloak con la configuración : realm-export.json

3.7. Página de Loging para un realm custom

Para aquellos que lo necesitéis, os comentaré que una vez creado el realm y creado el primer usuario ya podrías probar el login desde la plataforma web accediendo a una URL.

Ejemplo de URL de acceso

http://localhost:8083/auth/realms/test/account  

La URL incluye el realm al que se quiere acceder, en este ejemplo se accede a "test"

4. Conclusiones

Empecé el artículo con muchos aspectos de seguridad que agobiaban un poco, pero tras ver la funcionalidad que esta herramienta me proporciona de base me quedo un poco más tranquilo.

Tras los pasitos que hemos hecho en este tutorial ya tendríamos disponible de forma básica la herramienta configurada, no sé si sois del todo conscientes de lo que este sistema de login nos proporciona de base. Lo que si estoy segurísimo es que tratar de montarlo por nuestra cuenta a este nivel es bastante complicado y nos vamos a "dejar la vida" si lo queremos tener en un tiempo razonable.

Y con la que esta cayendo a nivel de seguridad en el mundo no podemos escatimar en nada ;-)

Ahora, solo nos falta aprender a utilizarla un poco mejor y configurarla según nuestras necesidades. Como pasa casi siempre en estas cosas, el nivel de integración que podamos necesitar lo va a determinar el proyecto o bien nosotros mismos.

Os voy avisando que en los siguientes artículos trabajaremos con persistencia en Keycloak lo cual ya cambia la película.

Espero que os haya gustado y sobre todo que os sea de utilidad.

Si te ha gustado, ¡síguenos en Twitter para estar al día de próximos posts!

Autor

Víctor Madrid

Líder Técnico de la Comunidad de Arquitectura de Soluciones en atSistemas. Aprendiz de mucho y maestro de nada. Técnico, artista y polifacético a partes iguales ;-)