Ansible Role keycloak¶
This role installs Keycloak.
Available since LFOps 2.0.0.
Dependent Roles¶
Any LFOps playbook that installs this role runs these for you. Optional ones can be disabled via the playbook’s skip variables.
A MariaDB database and user for Keycloak must be created (role: linuxfabrik.lfops.mariadb_server).
Requirements¶
Minimum supported Keycloak version:
Keycloak 24.0.0
Make sure you have OpenJDK installed.
Keycloak 25+: OpenJDK 21
Keycloak 24+: OpenJDK 17
Keycloak supports one of the following database servers; create a database and a user for it. The „Setup Keycloak“ playbook wires up MariaDB for you (see Dependent Roles), the others must be provided separately.
mariadb
mssql
mysql
oracle
postgres
If Keycloak itself should terminate TLS (e.g. when not running behind a reverse proxy, or when using a reverse proxy in reencrypt/passthrough mode), you need to provide SSL/TLS certificates via keycloak__https_certificate_file and keycloak__https_certificate_key_file. This can be done using the linuxfabrik.lfops.acme_sh role. When running behind a reverse proxy that terminates TLS (edge mode), no certificates are needed, and you can leave the certificate variables empty (the default).
All Keycloak config settings are described here: https://www.keycloak.org/server/all-config
Post-Installation Steps¶
The first role run provisions a temporary bootstrap admin (keycloak__admin_login, by convention suffixed -temp) in the master realm. Replace it with a permanent admin and remove the bootstrap account afterwards. The order matters: verify that the permanent admin works before deleting the bootstrap one, otherwise you risk locking yourself out of the master realm.
Log in to the Keycloak admin console (
masterrealm) as the bootstrap admin (keycloak__admin_login["username"]).Create the permanent admin via Users > Add user: set a username (e.g.
linuxfabrik-admin), turn Email verified on, then Create.Role mapping > Assign role > Filter by realm roles: assign the
adminrole.Credentials > Set password: set the password with Temporary off (otherwise the user must change it on first login), and store it in your password manager.
Verify the permanent admin: log out, then log in as the permanent admin in a fresh (incognito) session and confirm the admin console is fully accessible (Realms, Clients and Users are visible).
Delete the bootstrap admin: as the permanent admin, go to Users >
keycloak__admin_login["username"]> Delete.The role already removed the
KC_BOOTSTRAP_ADMIN_*credentials from/etc/sysconfig/keycloakand wrote the marker/etc/ansible/facts.d/keycloak__admin_login_bootstrapped.stateafter the first run. Verify this:grep --quiet '^KC_BOOTSTRAP_ADMIN_' /etc/sysconfig/keycloak && echo FAIL || echo OK test -f /etc/ansible/facts.d/keycloak__admin_login_bootstrapped.state && echo OK || echo FAIL
Mandatory Role Variables¶
keycloak__admin_login
The temporary Keycloak bootstrap admin login credentials. Keycloak only honors
KC_BOOTSTRAP_ADMIN_USERNAME/KC_BOOTSTRAP_ADMIN_PASSWORDon the very first start, when no admin user exists in themasterrealm yet. Subsequent restarts ignore these variables.Mandatory only on the first role run. The role writes the credentials to
/etc/sysconfig/keycloak, restarts Keycloak so it consumes them and provisions the bootstrap admin in themasterrealm, then immediately re-renders the sysconfig file with the credentials removed and marks the bootstrap as done via/etc/ansible/facts.d/keycloak__admin_login_bootstrapped.state. The cleartext password no longer lingers on disk after the role finishes.On subsequent runs the role detects the marker file and renders the sysconfig file without credentials right away.
keycloak__admin_logincan be removed from the inventory at that point.Use a username that visibly marks the account as throwaway (suffix
-temp), so it is obvious in the Keycloak UI which account must be deleted once a permanent admin has been created. See „Post-Installation Steps“ for the handover to a permanent admin.For disaster recovery (e.g. lost database, need to re-bootstrap an admin): remove
/etc/ansible/facts.d/keycloak__admin_login_bootstrapped.state, re-addkeycloak__admin_loginto the inventory, and re-run the role.Type: Dictionary.
Subkeys:
username:Mandatory. Username. By convention, end with
-temp(e.g.keycloak-admin-temp) to flag the account as the bootstrap user that must be deleted after the permanent admin is in place.Type: String.
password:Mandatory. Password.
Type: String.
keycloak__db_login
The database login credentials for keycloak.
Type: Dictionary.
Subkeys:
username:Mandatory. Username.
Type: String.
password:Mandatory. Password.
Type: String.
keycloak__hostname
The hostname where keycloak is reachable.
Type: String.
keycloak__version
The version of Keycloak that should be installed.
Possible options: https://github.com/keycloak/keycloak/releases.
Type: String.
Example:
# mandatory
keycloak__admin_login:
username: 'keycloak-admin-temp'
password: 'linuxfabrik'
keycloak__db_login:
username: 'keycloak'
password: 'linuxfabrik'
keycloak__hostname: 'keycloak.local'
keycloak__version: '26.1.2'
Optional Role Variables¶
keycloak__db_url
The full database JDBC URL. If not provided, a default URL is set based on the selected database vendor.
Type: String.
Default: unset
keycloak__db_url_database
The database name for Keycloak. If the db-url option is set, this option is ignored.
Type: String.
Default:
'keycloak'
keycloak__db_url_host
The host where the database for Keycloak is running. If the db-url option is set, this option is ignored.
Type: String.
Default:
'localhost'
keycloak__db_vendor
Specifies the database server Keycloak is supposed to use. Changing this requires a full run with the
keycloaktag, askc.sh buildneeds to be re-executed. Possible options:mariadb,mssql,mysql,oracle,postgres.Type: String.
Default:
'mariadb'
keycloak__expose_healthcheck_endpoints
If the server should expose healthcheck endpoints.
Type: Bool.
Default:
true
keycloak__expose_metrics_endpoints
If the server should expose metrics endpoints.
Type: Bool.
Default:
true
keycloak__hostname_backchannel_dynamic
Enables dynamic resolving of backchannel URLs, including hostname, scheme, port and context path. Set to
trueif your application accesses Keycloak via a private network. If set totrue,keycloak__hostnameneeds to be specified as a full URL.Type: Bool.
Default:
false
keycloak__https_certificate_file
The file path to a server certificate or certificate chain in PEM format. Only needed when Keycloak itself terminates TLS (reencrypt/passthrough). Leave empty for edge proxy setups where the reverse proxy handles TLS.
Type: String.
Default:
''
keycloak__https_certificate_key_file
The file path to a private key in PEM format. Only needed when Keycloak itself terminates TLS (reencrypt/passthrough). Leave empty for edge proxy setups where the reverse proxy handles TLS.
Type: String.
Default:
''
keycloak__https_cipher_suites
The cipher suites to use. If none is given, a reasonable default is selected.
Type: String.
Default: unset
keycloak__https_protocols
The TLS protocol versions Keycloak should use. Only applies when HTTPS certificate files are provided.
Type: String.
Default:
'TLSv1.3,TLSv1.2'
keycloak__log
Enable one or more log handlers in a comma-separated list.
Type: String.
Default:
'file'
keycloak__log_file
Set the log file path and filename.
Type: String.
Default:
'/var/log/keycloak/keycloak.log'
keycloak__mode
The mode to start Keycloak in. The development mode is targeted for people trying out Keycloak the first time and get it up and running quickly. It also offers convenient defaults for developers, for example to develop a new Keycloak theme. Possible options:
production,development.Type: String.
Default:
'production'
keycloak__proxy_headers
The proxy headers that should be accepted by the server. Only applies in production mode without HTTPS certificates (edge proxy mode).
Type: String.
Default:
'xforwarded'
keycloak__proxy_trusted_addresses
A comma separated list of trusted proxy addresses. Only applies in production mode without HTTPS certificates (edge proxy mode).
Type: String.
Default: unset
keycloak__service_enabled
Enables or disables the service, analogous to
systemctl enable/disable --now.Type: Bool.
Default:
true
keycloak__spi_sticky_session_encoder_infinispan_should_attach_route
https://www.keycloak.org/server/reverseproxy#_enable_sticky_sessions
Type: Bool.
Default:
false
keycloak__state
Controls the Systemd service. One of
started,stopped,reloaded.Type: String.
Default:
'started'
Example:
# optional
keycloak__db_url: 'jdbc:mariadb://localhost/keycloak/'
keycloak__db_url_database: 'keycloak'
keycloak__db_url_host: 'localhost'
keycloak__db_vendor: 'mariadb'
keycloak__expose_healthcheck_endpoints: true
keycloak__expose_metrics_endpoints: true
keycloak__hostname_backchannel_dynamic: false
keycloak__https_certificate_file: '/etc/pki/tls/certs/www.example.com-chain.crt'
keycloak__https_certificate_key_file: '/etc/pki/tls/private/www.example.com.key'
keycloak__https_cipher_suites: 'TLS_RSA_WITH_AES_128_GCM_SHA256'
keycloak__https_protocols: 'TLSv1.3,TLSv1.2'
keycloak__log: 'file'
keycloak__log_file: '/var/log/keycloak/keycloak.log'
keycloak__mode: 'production'
keycloak__proxy_headers: 'xforwarded'
keycloak__proxy_trusted_addresses: '10.0.0.2'
keycloak__service_enabled: true
keycloak__spi_sticky_session_encoder_infinispan_should_attach_route: false
keycloak__state: 'started'
Using a reverse proxy¶
See the Keycloak reverse proxy documentation for details. When running behind a reverse proxy that terminates TLS (edge mode), leave the HTTPS certificate variables empty. The role will automatically set http-enabled=true and proxy-headers (default: xforwarded). Optionally set keycloak__proxy_trusted_addresses to restrict which proxy addresses are trusted. When the reverse proxy does not terminate TLS (reencrypt/passthrough), provide certificate paths via keycloak__https_certificate_file and keycloak__https_certificate_key_file.
Troubleshooting¶
Role fails with Could not obtain an admin-cli token
On a run where the bootstrap is not yet marked as done (the marker
/etc/ansible/facts.d/keycloak__admin_login_bootstrapped.stateis missing), the role verifies that the bootstrap admin can obtain a token before writing the marker. This fails when the bootstrap admin no longer exists, which is the expected end state after the permanent-admin handover (see „Post-Installation Steps“) once the-tempaccount has been deleted, combined with a missing marker file (e.g. a fresh Ansible controller, or a lost/etc/ansible/facts.d).If the handover is already complete, recreate the marker on the target and re-run the role:
mkdir --parents /etc/ansible/facts.d touch /etc/ansible/facts.d/keycloak__admin_login_bootstrapped.state
Otherwise, check that
keycloak.serviceis running and thatkeycloak__admin_loginmatches the actual bootstrap admin, then re-run.