How to Setup Keycloak With MySQL Database using CLI in Docker
Tags: keycloak, mysql, database, docker
Published: 2022-10-25 02:39:56

## 1. Introduction
Keycloak is one of the most popular open-source Identity and Access Management platforms backed by RedHat. It is known for its flexibility and extensibility, making it a top candidate in the enterprise world, where there are complicated use cases for user authentication and authorization use cases. For example, multiple applications must support multi-tenant and n-reseller levels with a single login.

### 1.1 Prerequisites
Knowledge of the following is required.
- Keycloak
- Docker
- MySQL

## 2. ct-keycloak-iam
ct-keycloak-iam is a project I developed to deliver a custom Keycloak server in a docker container. It includes a default realm, custom themes, database connection (MySQL), and custom SPIs (required sponsorship).

It contains CLI scripts that will download the Keycloak server and install a MySQL data source.

The project is available at  https://github.com/czetsuya/ct-keycloak-iam.

Folders/files that we will use.

keycloak-docker-assembly
  - docker
    - Dockerfile - builds a custom Keycloak container
    - docker-compose-dev.yml - builds and runs the custom Keycloak container and MySQL.
  - src/main/resources
    - build
      - cli/database/mysql
        - set-database.cli - a set of instructions to create an entry of MySQL data source and driver in your Keycloak configuration. Note that it uses the environment variables defined in your docker-compose file.
        - build-keycloak.sh
    - modules/databases/mysql
      - module.xml - MySQL module file needed by Keycloak. Make sure that the version matches the one defined in the Dockerfile (instead, you changed it)

## 3. Docker Compose
Instead of manually creating a MySQL database, users, and permissions, we will use a MySQL docker image to do the job.

We need to define the MySQL connection settings as environment variables.

```
version: '3'
 
services:
  keycloak-db:
    image: mysql:8.0
    ports:
      - 33066:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: keycloak
      MYSQL_USER: keycloak
      MYSQL_PASSWORD: keycloak
    command: mysqld --sql_mode=""
 
  ct-keycloak-iam:
    depends_on:
      - keycloak-db
    build:
      context: ../
      dockerfile: docker/Dockerfile
    ports:
      - 8888:8888
      - 8080:8080
      - 8443:8443
      - 9990:9990
    environment:
      DB_ADDR: keycloak-db
      DB_PORT: 3306
      DB_DATABASE: keycloak
      DB_USER: keycloak
      DB_PASSWORD: keycloak
      DB_JDBC_PARAMS: useSSL=false&allowPublicKeyRetrieval=true
 
      KEYCLOAK_IMPORT: /opt/jboss/keycloak_install_stage/realms/ct-realm-dev.json
      KEYCLOAK_USER: keycloak.admin
      KEYCLOAK_PASSWORD: keycloak.admin
 
      KC_HOSTNAME_STRICT: false
 
      DEBUG_PORT: 8888
      PROXY_ADDRESS_FORWARDING: 'true'
```

Make sure that the DB_XXX parameter values in the ct-keycloak-iam container match MySQL's.

## 4. Configure the MySQL Driver and Module
This is already done by the build-keycloak.sh, a script that copies the MySQL driver and module.xml file to the extracted Keycloak server inside the Docker container.

Here's our MySQL module file.

```
<?xml version="1.0" encoding="UTF-8"?>
<module
    xmlns="urn:jboss:module:1.0" name="com.mysql.jdbc">
  <resources>
    <resource-root path="mysql-connector-java-8.0.29.jar"/>
  </resources>
  <dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
  </dependencies>
</module>
```

## 5. Add the MySQL Datasource and Driver Configuration in Keycloak
This is handled by the set-database.cli script, which installs the data source and driver configuration by using the values from the environment variables such as database URL, username, password, and JDBC params.

```
/subsystem=datasources/data-source=KeycloakDS: remove()
/subsystem=datasources/data-source=KeycloakDS: add(jndi-name=java:jboss/datasources/KeycloakDS,enabled=true,use-java-context=true,use-ccm=true, connection-url=jdbc:mysql://${env.DB_ADDR:mysql}:${env.DB_PORT:3306}/${env.DB_DATABASE:keycloak}${env.DB_JDBC_PARAMS:}, driver-name=mysql)
/subsystem=datasources/data-source=KeycloakDS: write-attribute(name=user-name, value=${env.DB_USER:keycloak})
/subsystem=datasources/data-source=KeycloakDS: write-attribute(name=password, value=${env.DB_PASSWORD:password})
/subsystem=datasources/data-source=KeycloakDS: write-attribute(name=check-valid-connection-sql, value="SELECT 1")
/subsystem=datasources/data-source=KeycloakDS: write-attribute(name=background-validation, value=true)
/subsystem=datasources/data-source=KeycloakDS: write-attribute(name=background-validation-millis, value=60000)
/subsystem=datasources/data-source=KeycloakDS: write-attribute(name=flush-strategy, value=IdleConnections)
/subsystem=datasources/jdbc-driver=mysql:add(driver-name=mysql, driver-module-name=com.mysql.jdbc,driver-xa-datasource-class-name=com.mysql.cj.jdbc.MysqlXADataSource)
```

## 6. Running the Project
If you're familiar with docker-compose, you know that it's our entry point to our custom Keycloak server.

Before running it, comment on the line that imports the SPIs, or become my sponsor in GitHub so that you can gain access to those restricted projects.

```
docker-compose -f ./keycloak-docker-assembly/docker/docker-compose-dev.yml up --build
```