Keycloak SSO with docker compose and nginx

Printed: 2024-02-11, Revised: 2024-02-11
TL;DR I all the time hesitated to deploy an additional device for person administration and SSO, however the present state of the online makes it very troublesome to maintain up with safety, CVEs and so forth. Why not belief one of many longest standing options for id and entry administration? Keycloak is open supply, interoperable with main SSO protocols (OpenID Join (OIDC), OAuth 2.0, SAML
), and sturdy. The setup with docker compose shouldn’t be difficult, however it was not straight ahead both. Because of this I present a abstract of the method under.
Data
That is at the moment a stub. I believed I’d share my docker-compose.yml
and nginx.conf
rapidly and replace the publish later so as to add steps for theming and integration.
Idea
You will have seen the idea under already in my previous post about Mastodon. We are going to use a normal setup of nginx as a central reverse proxy that forwards visitors by means of localhost to particular person companies, all working in their very own rootless docker namespaces. I contemplate this the everyday economical setup, by sharing sources of a single host however with maximally remoted environments. Adapt the place this doesn’t suit your usecase.
Net | | 0.0.0.0:80 0.0.0.0:443 +------------------------------------------------------+-----------------------------------------------------+ | | | | v | | +------------------------------- nginx/acme -----------------------------+ | | | | | | | http://127.0.0.1:3000 | | | | http://127.0.0.1:4000 http://127.0.0.1:8080 http://127.0.0.1:9999 | | +--------------+---------------+ +--------------+---------------+ +-------------+----------------+ | | | | | | | | | | | | | | Rootless Docker Service | | Rootless Docker Service | | Rootless Docker Service | | | | +---------+----------+ | | +---------+----------+ | | +--------+-----------+ | | | | | | | | | | | | | | | | | | | | | | v | | | | v | | | | v | | | | | | Mastdon Docker | | | | Keycloak Docker | | | | Nextcloud Docker | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +--------------------+ | | +--------------------+ | | +--------------------+ | | | | | | | | | | | +------------------------------+ +------------------------------+ +------------------------------+ | | | +------------------------------------------------------------------------------------------------------------+
Preparations
You have to some fundamental instruments:
- SSH
- A VM with Linux (Ubuntu; Debian and so forth.)
- A website or subdomain the place you possibly can add an
A
(and optionallyAAAA
) file in your service
Observe the Mastodon post for fundamental setup of docker rootless to:
- create a brand new non-root person named
keycloak
, with out password, with its house listing set to/srv/keycloak
- replace
/and so forth/subuid
and/and so forth/subgid
ranges with personkeycloak
(as a result of e.g. the postgres container will want these to create a nested non-root person itself) - set up docker rootless by means of
dockerd-rootless-setuptool.sh
and configure automated service begin for thekeycloak
person
Keycloak Setup
Login to the newly created keycloak
person.
machinectl shell keycloak@
Warning
We have to use machinectl
to login, in any other case
XDG_RUNTIME_DIR
setting variables is not going to be out there.
Don’t use (e.g.) sudo -u keycloak -H bash
.
Create directories for persistent information (information/postgres16
) and the docker recordsdata.
cd ~
&& mkdir -p information/postgres16
&& mkdir docker && cd docker
docker-compose.yml
The official docs present some data right here . However they use docker run
, which might be uncommon in manufacturing.
Going to a compose file shouldn’t be difficult and permits us to have a extra reproducable setup. There are some instance docker-compose.yml
s out there, similar to , or .
We are going to begin with a docker-compose.yml
that instantly makes use of the official keycloak image. This may be modified later.
model: '3'
companies:
postgres_db:
picture: postgres:16
volumes:
- /srv/keycloak/information/postgres16:/var/lib/postgresql/information
setting:
POSTGRES_DB: keycloak
POSTGRES_USER: ${POSTGRES_USER:-keycloak}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-eX4mP13p455w0Rd}
keycloak:
# construct: .
picture: quay.io/keycloak/keycloak:23.0.6
setting:
KC_LOG_LEVEL: debug
KC_DB: postgres
KC_DB_URL: 'jdbc:postgresql://postgres_db/keycloak'
KC_DB_USERNAME: ${POSTGRES_USER:-keycloak}
KC_DB_PASSWORD: ${POSTGRES_PASSWORD:-eX4mP13p455w0Rd}
KC_DB_SCHEMA: public
KC_HOSTNAME: ${KC_HOSTNAME:-your.tld.com}
KC_HOSTNAME_STRICT_HTTPS: true
KC_HOSTNAME_STRICT: true
KC_PROXY: edge
HTTP_ADDRESS_FORWARDING: true
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-eX4mP13p455w0Rd}
# command: begin --optimized
ports:
- '127.0.0.1:8080:8080'
depends_on:
- postgres_db
Create an .env
file together with your delicate and variable data:
Contents (change passwords):
# DB Password
POSTGRES_PASSWORD=eX4mP13p455w0Rd
# admin password
KEYCLOAK_ADMIN_PASSWORD=eX4mP13p455w0Rd
# area
KC_HOSTNAME=your.tld.com
The related documentation of all these variables could be discovered right here .
Be aware
Optionally initialize a .git
repository in ~/docker
now, create a .gitignore
and add .env
to it, and commit the docker-compose.yml
, for monitoring modifications.
Some explanations for the docker-compose.yml
above
'127.0.0.1:8080:8080'
andKC_PROXY: edge
will make keycloak hear on localhost- the syntax for env variables (
${KC_HOSTNAME:-your.tld.com}
) means:
1. useKC_HOSTNAME
from.env
, if out there;
2. in any other case substitute a default worth (your.tld.com
) - observe (e.g.) that we don’t set
KC_DB_USERNAME
, which implies: use the default picture: quay.io/keycloak/keycloak:23.0.6
references a selected picture tag, as is advised for manufacturing (solely use:newest
for growth).KC_LOG_LEVEL: debug
could be commented out as soon as we’re finished with growth- bind-mount the persistent postgres information from the subfolder created earlier within the person’s house listing:
companies: postgres_db: picture: postgres:16 volumes: - /srv/keycloak/information/postgres16:/var/lib/postgresql/information
- if you wish to begin over from scratch, merely delete this postgres folder and it will probably be re-initialized on subsequent startup:
CTRL+D sudo rm -rf /srv/keycloak/information/postgres16 sudo machinectl shell keycloak@ cd ~ && mkdir -p information/postgres16
/srv/keycloak/information/postgres16
holds the persistent information that would want periodic backups
Take a look at domestically
At this stage, we are able to check the docker compose stack:
docker compose up -d && docker compose logs --follow
Afterwards, create a reverse SSH tunnel to your VM and the keycloak native port.
ssh you@111.11.11.11 -L :8080:127.0.0.1:8080 -p 22 -N -v
Open 127.0.0.1:8080
in your browser and you need to be greeted with the keycloak welcome display:
nginx
Logout from the keycloak person with CTRL+D.
Observe the Mastodon post for setup of nginx as a system reverse proxy.
Create a brand new nginx .conf
for the keycloak service.
Be aware
From right here on, wherever you see your.tld.com
: exchange together with your precise area.
Be aware
At this stage, it is best to head to your area registrar and add an A
file to ahead DNS queries to your VM’s IP.
nano /and so forth/nginx/sites-available/your.tld.com.conf
ln -s /and so forth/nginx/sites-available/your.tld.com.conf /and so forth/nginx/sites-enabled/
We are able to discover some related data within the keycloak docs .
Data
I like to recommend to make use of the Mozilla SSL configurator to generate greatest follow defaults for nginx . Be certain that to replace together with your nginx model (nginx -v
).
server {
if ($host = your.tld.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
hear 80;
hear [::]:80;
server_name your.tld.com;
location / { return 301 https://$host$request_uri; }
}
server {
hear 443 ssl http2;
hear [::]:443 ssl http2;
server_name your.tld.com;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 periods
ssl_session_tickets off;
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
ssl_dhparam /and so forth/nginx/dhparam/dhparam;
# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Safety "max-age=63072000" all the time;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# confirm chain of belief of OCSP response utilizing Root CA and Intermediate certs
# ssl_trusted_certificate /and so forth/letsencrypt/stay/your.tld.com/chain.pem;
access_log /var/log/nginx/your.tld.com-access.log;
error_log /var/log/nginx/your.tld.com-error.log;
location / {
proxy_set_header Host $host;
proxy_set_header X-Actual-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:8080;
# the next headers are wanted, in case your utility makes use of redirection circulate to authenticate with Keycloak.
# exchange http://127.0.0.1:8080 with the applying server url
# add_header Content material-Safety-Coverage "frame-src *; frame-ancestors *; object-src *;";
# add_header Entry-Management-Permit-Origin 'http://127.0.0.1:8080';
# add_header Entry-Management-Permit-Credentials true;
}
# ssl_certificate /and so forth/letsencrypt/stay/your.tld.com/fullchain.pem; # managed by Certbot
# ssl_certificate_key /and so forth/letsencrypt/stay/your.tld.com/privkey.pem; # managed by Certbot
}
Take a look at the configuration and reload nginx.
nginx -t
systemctl reload nginx
Use certbot
to request SSL certificates in your service.
certbot --nginx -d your.tld.com
This can robotically replace crucial traces in your.tld.com.conf
.
Edit your.tld.com.conf
and uncomment ssl_trusted_certificate
.
# confirm chain of belief of OCSP response utilizing Root CA and Intermediate certs
ssl_trusted_certificate /and so forth/letsencrypt/stay/your.tld.com/chain.pem;
Reload nginx
Debug
Now you can open your.tld.com
and login to keycloak utilizing the admin
person with the password from the .env
file.
For debugging, the primary cease are the docker compose logs.
docker compose logs --follow
For nginx, observe the entry and error logs.
tail -f /var/log/nginx/your.tld.com-access.log;
tail -f /var/log/nginx/your.tld.com-error.log;
When you want to take a look on the keycloak database.
machinectl shell keycloak@
cd ~/docker
docker compose exec postgres_db /bin/bash
psql -h localhost -p 5432 -U keycloak keycloak
SELECT ...;
Customized construct with Dockerfile
To this point, we’re utilizing the prebuild picture from quay.io.
For any customization, e.g. in an effort to use themes and run the keycloak container in --optimized
mode , we have to construct our personal picture.
We are going to make the most of a multi-stage docker construct beginning with the official quay.io picture.
Add a Dockerfile
cd ~/docker
nano Dockerfile
.. with the next content material.
FROM quay.io/keycloak/keycloak:23.0.6 as builder
# Configure a database vendor
ENV KC_DB=postgres
WORKDIR /choose/keycloak
# COPY --from=keycloakify_jar_builder /choose/app/build_keycloak/goal/ keycloakify-starter-keycloak-theme-5.1.3.jar /choose/keycloak/suppliers/
RUN /choose/keycloak/bin/kc.sh construct
FROM quay.io/keycloak/keycloak:23.0.6
COPY --from=builder /choose/keycloak/ /choose/keycloak/
# Add ENTRYPOINT
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
Afterwards, edit the docker-compose.yml
:
- take away or remark out the
picture:
line - uncomment
construct: .
- add
command: begin --optimized
Closing docker-compose.yml
model: '3'
companies:
postgres_db:
picture: postgres:16
volumes:
- /srv/keycloak/information/postgres16:/var/lib/postgresql/information
setting:
POSTGRES_DB: keycloak
POSTGRES_USER: ${POSTGRES_USER:-keycloak}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-eX4mP13p455w0Rd}
keycloak:
construct: .
setting:
KC_LOG_LEVEL: debug
KC_DB: postgres
KC_DB_URL: 'jdbc:postgresql://postgres_db/keycloak'
KC_DB_USERNAME: ${POSTGRES_USER:-keycloak}
KC_DB_PASSWORD: ${POSTGRES_PASSWORD:-eX4mP13p455w0Rd}
KC_DB_SCHEMA: public
KC_HOSTNAME: ${KC_HOSTNAME:-your.tld.com}
KC_HOSTNAME_STRICT_HTTPS: true
KC_HOSTNAME_STRICT: true
KC_PROXY: edge
HTTP_ADDRESS_FORWARDING: true
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-eX4mP13p455w0Rd}
command: begin --optimized
ports:
- '127.0.0.1:8080:8080'
depends_on:
- postgres_db
Restart the docker stack afterwards with
docker compose down
# elective specific construct step
docker compose construct
docker compose up -d && docker compose logs --follow
This can construct the picture and begin the service.
Conclusions
We are actually working a keycloak service in rootless docker behind our system nginx reverse proxy, which does the SSL termination for us.
For automated updates of the docker container, see the Mastodon post.
The subsequent step could be logging in to the keycloak companies and including
an electronic mail beneath https://your.tld.com/admin/grasp/console/#/grasp/realm-settings/electronic mail
.
Subsequent comes (e.g.) including a realm. Then theming, which could be finished with keycloakify .
You’ll be able to see that I already added the required traces to the Dockerfile:
# COPY --from=keycloakify_jar_builder /choose/app/build_keycloak/goal/ keycloakify-starter-keycloak-theme-5.1.3.jar /choose/keycloak/suppliers/
When you discover enhancements to the directions above, please add within the feedback part!