Keycloak is an Access Management System which can be used for single sign-on, social login, user federation, etc. In a nutshell, it's a tool that can be used to manage user authentication and authorization for free. It's open source, and the source code can be accessed from its GitHub repository.

Identity Verification with Keycloak

It supports authentication mechanisms like username/password, social login, SAML, etc. When a user signs up for an application with Keycloak integrated, a unique identifier is provided, which can be used to identify our user. Whenever the user logs in, an access token is issued along with a refresh token. The access token contains information about the user, like their ID, permissions, roles, etc.

To administer Keycloak, a web console is provided, which allows managing users and their roles and permissions. It also provides a feature to impersonate the user and access applications. This is especially useful when debugging.

Keycloak can also be configured for users to log in via Google, Facebook, etc. Anything that uses the OpenID protocol is compatible to be used with Keycloak.


Related article: Identity and Access Management for Microservices with Keycloak


Deploying Keycloak

To deploy Keycloak, we will need to do a few things, and they are:

Configure Nginx reverse proxy

Create an Nginx virtual host configuration in the sites-available directory.

server {

    proxy_read_timeout 600s;
    proxy_connect_timeout 600s;
    proxy_send_timeout 600s;
    proxy_buffer_size 128k;
    proxy_buffers 4 256k;
    proxy_busy_buffers_size 256k;

    server_name keycloak.example.com;

    listen [::]:443 ssl;
    listen 443 ssl;

    location / {
        proxy_pass http://127.0.0.1:8080; #we'll host keycloak at localhost:8080
        include proxy_params;

    }
    
    ssl_certificate /home/ubuntu/keycloak/certs/full-chain.crt;
    ssl_certificate_key /home/ubuntu/keycloak/certs/privkey.pem;
    
    #These are provided by certbot, if you're sourcing the certificate from sources other than certbot, remove these two lines below.
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

Nginx configuration

Now, symlink this file to the sites-enabled directory using the following command:

ln -s /etc/nginx/sites-available/keycloak.example.com /etc/nginx/sites-enabled

Symlink Keycloak configuration in sites-available to sites-enabled

In the nginx.conf file, add the following line inside the http block.

include /etc/nginx/sites-enabled/*;

Entry to be added inside http block in nginx.conf

This will make sure that Nginx reads the configuration from the sites-enabled directory, where we have saved the Keycloak hosting config.

Provision SSL certificates

Let's generate SSL certificates for the Keycloak server. I will use Let's Encrypt as my CA and Certbot to generate and manage my certificates.

In the server, install Certbot.

sudo apt update && sudo apt install certbot

Installing Certbot

Make sure you have a domain name pointing towards your server. To verify, you can simply use nslookup and dig.

First, check the public IP of your server. Here, I'm using the example.com domain for reference purposes only. Your domain will be different from mine. We will send an http request to icanhazip.com to check our public IPV4 address using curl.

Run the following command from inside the server.

curl icanhazip.com

To check public IPV4 address

Now run the following:

nslookup keycloak.example.com

To check the IPV4 address of the domain name

This will provide the IP address of the domain name.

Make sure your domain name resolves to your server's public IPV4 address.

Finally, we'll generate our SSL certificates.

certbot --nginx --register-unsafely-without-email

Command to generate SSL certificates

You can remove the --register-unsafely-without-email flag to use an email address. The email address will be used to provide expiry notices and other important information related to your SSL certificates.

The generation command should be interactive enough for you to understand and follow the provided instructions.

Once your certificate is generated, Certbot will automatically edit the Nginx config you used for cert generation purposes with the path to our SSL certificates.

Now, we need to copy the certificate and the private key from the Let's Encrypt directory to the certs directory to mount it inside our Keycloak Docker container for a production-ready deployment.

Create the directory if you have not done yet.

mkdir $PWD/certs . 

Generating directory

Copy the certificate using the following command:

sudo cp /etc/ssl/letsencrypt/keycloak.example.com/full-chain.crt /etc/ssl/letsencrypt/keycloak.example.com/privkey.key $PWD/certs/

Copying the certificates from Let's Encrypt directory to the certs directory

We could've just mounted the certificate from the Let's Encrypt directory, but the reason we've copied it is due to our Keycloak container running as the non-root keycloak user. This means the certificate files should also come under the ownership of Keycloak with full read/write permissions. Otherwise, the Keycloak user will be unable to read our certificate files, and thus the Keycloak container will fail to start in production mode.

Let's change the ownership and modify the permissions of the certificate files.

sudo chown -R keycloak:keycloak $PWD/certs

Changing certificate ownership to Keycloak user

sudo chmod -R 660 $PWD/certs

Changing certificate permissions

Host Keycloak

We're now finally ready to host our Keycloak instance. We will use Docker Compose for this, as it's much easier to set up networking between containers.

Our compose file will consist of two services; One is a Postgres database, and the other is Keycloak, provided by Bitnami.

Copy and paste the contents below to a docker-compose.yml file.

version: '3.9'
services:
  postgres:
    image: postgres:15.1-alpine
    container_name: postgres-keycloak
    restart: always
    env_file:
      - .env
    volumes:
      - postgres-kc:/var/lib/postgresql/data
    networks:
      - keycloak-and-pg-network

  keycloak-w:
    image: bitnami/keycloak:21.0.2
    ports:
      - "8080:8080"
    restart: unless-stopped
    volumes:
      - {PWD}/certs:/opt/bitnami/keycloak/certs:ro
    env_file:
      - .env
    depends_on:
      - dev-db-kc-prod
    networks:
      - keycloak-and-pg-network

volumes:
  postgres-kc:
    name: pg-data-kc

networks:
  keycloak-and-pg-network:
    name: kc-pg-network

Compose Keycloak file

Certain environment variables need to be provided to our containers, so copy the following contents and paste them into a .env file.

DB_HOST=postgres
DB_PORT=5432
DB_SCHEMA=public
POSTGRES_DB=keycloak
POSTGRES_USER=yb_keycloak
POSTGRES_PASSWORD=randomlongalphanumericpassword

KEYCLOAK_CREATE_ADMIN_USER=true
KEYCLOAK_ADMIN_USER=keycloak-admin
KEYCLOAK_ADMIN_PASSWORD=randomlongalphanumericpassword
KEYCLOAK_MANAGEMENT_USER=keycloak-manager
KEYCLOAK_MANAGEMENT_PASSWORD=randomlongalphanumericpassword

KEYCLOAK_DATABASE_HOST=${DB_HOST}
KEYCLOAK_DATABASE_PORT=${DB_PORT}
KEYCLOAK_DATABASE_NAME=${POSTGRES_DB}
KEYCLOAK_DATABASE_USER=${POSTGRES_USER}
KEYCLOAK_DATABASE_PASSWORD=${POSTGRES_PASSWORD}
KEYCLOAK_DATABASE_SCHEMA=${DB_SCHEMA}

KEYCLOAK_PRODUCTION=true
KEYCLOAK_JDBC_PARAMS=sslmode=disable&connectTimeout=40000
KEYCLOAK_EXTRA_ARGS="-Dkeycloak.profile.feature.scripts=enabled"

KEYCLOAK_ENABLE_HTTPS=true
KEYCLOAK_HTTPS_USE_PEM=true
KEYCLOAK_HTTPS_CERTIFICATE_FILE=/opt/bitnami/keycloak/certs/fullchain.pem
KEYCLOAK_HTTPS_CERTIFICATE_KEY_FILE=/opt/bitnami/keycloak/certs/privkey.pem

Compose .env file

Now, from the root of the Keycloak project folder (or wherever you've saved the certs, compose, and env file), run the following command to start the Keycloak and Postgres instance.

docker compose -f docker-compose.yml up -d

Compose command to run Keycloak

To check logs, simply run the following:

docker compose -f docker-compose.yml logs -f

Compose command to view logs

ℹ️
If all steps are followed correctly, the Keycloak instance should run successfully without any errors. As of 11th May, it should work as per the above instructions.

Also read: Load Balancing with Nginx


Frequently Asked Questions (FAQs)

Why are the SSL certificates not being recognized by Keycloak?

Make sure you have changed the SSL certificate file owners to the Keycloak user. If a user is not present, then create a user on the host machine with adduser keycloak and run the chown keycloak:keycloak command on the SSL Certificate files.

Also, ensure that read/write permission is provided on the certificate files. Try giving full permission to owner, groups and others if all else fails.

Why should I use Keycloak and not something like Auth0?

You can go with either of those for your authentication and authorization needs. The main difference is that Keycloak is a self-hosted solution, meaning that the data stored is under your control, and you're liable for any leaks. On the other hand, AuthO is a user identity management service provided by Okta, and the data stored is under their control.

In this article,

we learned to set up an Nginx reverse proxy, provision SSL certificates, configure a Postgres database, and host a production-ready Keycloak server.

Please comment below if you have any queries, I try to periodically update my articles to ensure legibility!