Install Keycloak on CentOS 7 with MySQL backend

Written by Pim on Tuesday October 23, 2018 - Comment - Permalink
Categories: devops, technology, howto - Tags: centos7, authentication, keycloak, mysql, nginx, jboss, identity-provider, active-directory, security

Keycloak is an open source Identity and Access Management solution we're going to install on a CentOS 7 machine. The Keycloak application including the MySQL server requires at least 2 CPU cores and 2 GB of memory. It's recommended to have 4 GB memory when you're going to have a lot of traffic to this identity server.

Install Keycloak

Keycloak is based on Wildfly and requires Java 8. We're using the YUM package manager to install all required dependencies.

$ yum install java-1.8.0-openjdk

We're going to run the Keycloak application with user 'keycloak'. Add the user and group to your machine.

$ groupadd -r keycloak
$ useradd -m -d /var/lib/keycloak -s /sbin/nologin -r -g keycloak keycloak

Keycloak doesn't provide a RPM so we're going to install it manually. In this blog post I'm using the following paths:

  • Base path: /opt/keycloak
  • Application path: /opt/keycloak/current

The application path is a symlink to a specific version. This simplifies the upgrade process in the future.

Go to the download page of Keycloak and get the URL of the latest final version. Download the final Keycloak version from the website and extract it into /opt/keycloak/$version. Use a symlink to link Keycloak to /opt/keycloak/current.

$ curl https://downloads.jboss.org/keycloak/4.5.0.Final/keycloak-4.5.0.Final.tar.gz -o keycloak.tar.gz
$ mkdir -p /opt/keycloak/4.5.0
$ ln -s /opt/keycloak/4.5.0 /opt/keycloak/current
$ tar -xzf keycloak.tar.gz -C /opt/keycloak/current --strip-components=1
$ chown keycloak: -R /opt/keycloak

Limit access to standalone file because it contains sensitive data.

$ cd /opt/keycloak/current
$ sudo -u keycloak chmod 700 standalone

We're going to run Keycloak on MySQL instead of the default H2 database. First, install the MySQL Yum repository.

$ yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm

This will install the MySQL repository with the MySQL 8.0 repository enabled by default. Because Keycloak doesn't support MySQL 8.0 yet, disable the MySQL 8.0 repository and enable the MySQL 5.7 repository.

$ yum-config-manager --disable mysql80-community
$ yum-config-manager --enable mysql57-community

Install and start the MySQL server.

$ yum install mysql-server
$ systemctl start mysqld

The MySQL server generates a temporary password which can be found in the log file located in the /var/log directory. Change this temporary password to something else before proceeding.

$ mysqladmin -p password

Save the MySQL credentials in the home directory of the root user.

$ cat > /root/.my.cnf <<EOF
[client]
user=root
password="YOURPASS"
EOF

Create a database and user account for Keycloak (change YOURPASS to your something random).

$ mysql
 
mysql$ CREATE DATABASE keycloak;
mysql$ CREATE USER 'keycloak'@'localhost' IDENTIFIED BY 'YOURPASS';
mysql$ GRANT ALL PRIVILEGES ON keycloak.* TO 'keycloak'@'localhost';
mysql$ FLUSH PRIVILEGES;
mysql$ exit;

Configure Keycloak to use MySQL. Download the MySQL connector for Java.

$ curl -L http://central.maven.org/maven2/mysql/mysql-connector-java/5.1.46/mysql-connector-java-5.1.46.jar -o /root/mysql-connector-java-5.1.46.jar

Open the Jboss CLI and add the MySQL module (you don't have to connect with the Jboss websocket).

$ ./bin/jboss-cli.sh
 
jboss-cli$ module add --name=org.mysql  --dependencies=javax.api,javax.transaction.api --resources=/root/mysql-connector-java-5.1.46.jar
jboss-cli$ exit

Add the MySQL driver to the configuration.

$ sudo -u keycloak ./bin/jboss-cli.sh 'embed-server,/subsystem=datasources/jdbc-driver=mysql:add(driver-name=mysql,driver-module-name=org.mysql,driver-class-name=com.mysql.jdbc.Driver)'

Remove the h2 KeycloakDS data source and add the MySQL KeycloakDS data source. (Don't delete the test database and change YOURPASS to something random)

$ sudo -u keycloak ./bin/jboss-cli.sh 'embed-server,/subsystem=datasources/data-source=KeycloakDS:remove'
$ sudo -u keycloak ./bin/jboss-cli.sh 'embed-server,/subsystem=datasources/data-source=KeycloakDS:add(driver-name=mysql,enabled=true,use-java-context=true,connection-url="jdbc:mysql://localhost:3306/keycloak?useSSL=false&amp;useLegacyDatetimeCode=false&amp;serverTimezone=Europe/Amsterdam&amp;characterEncoding=UTF-8",jndi-name="java:/jboss/datasources/KeycloakDS",user-name=keycloak,password="YOURPASS",valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker,validate-on-match=true,exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker)'

Add management user to keycloak (change YOURPASS to your something random).

$ sudo -u keycloak ./bin/add-user-keycloak.sh -u admin -p YOURPASS -r master
 
# output: Added 'admin' to '/opt/keycloak/4.5.0/standalone/configuration/keycloak-add-user.json', restart server to load user

We're going to run Keycloak behind a Nginx reverse proxy. To allow this, change http-listener and socket-binding configurations in Keycloak.

$ sudo -u keycloak ./bin/jboss-cli.sh 'embed-server,/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)'
$ sudo -u keycloak ./bin/jboss-cli.sh 'embed-server,/socket-binding-group=standard-sockets/socket-binding=proxy-https:add(port=443)'
$ sudo -u keycloak ./bin/jboss-cli.sh 'embed-server,/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=redirect-socket,value=proxy-https)'

Create a systemd configuration to start and stop keycloak using systemd.

cat > /etc/systemd/system/keycloak.service <<EOF
 
[Unit]
Description=Keycloak
After=network.target
 
[Service]
Type=idle
User=keycloak
Group=keycloak
ExecStart=/opt/keycloak/current/bin/standalone.sh -b 0.0.0.0
TimeoutStartSec=600
TimeoutStopSec=600
 
[Install]
WantedBy=multi-user.target
EOF

Reload the systemd daemon and start Keycloak.

$ systemctl daemon-reload
$ systemctl enable keycloak
$ systemctl start keycloak

Now, we'll install the Nginx server to do SSL termination for our Keycloak application. Install Nginx using the YUM package manager.

$ yum install nginx

Copy the SSL certificates to the following paths on the server:

  • Certificate: /etc/pki/tls/certs/
  • Private key: /etc/pki/tls/private/

Configure Nginx to proxy traffic for Keycloak. (Change my.url.com to your own URL)

cat > /etc/nginx/conf.d/keycloak.conf <<EOF
upstream keycloak {
    # Use IP Hash for session persistence
    ip_hash;
  
    # List of Keycloak servers
    server 127.0.0.1:8080;
}
  
      
server {
    listen 80;
    server_name my.url.com;
 
    # Redirect all HTTP to HTTPS
    location / {   
      return 301 https://\$server_name\$request_uri;
    }
}
  
server {
    listen 443 ssl http2;
    server_name my.url.com;
 
    ssl_certificate /etc/pki/tls/certs/my-cert.cer;
    ssl_certificate_key /etc/pki/tls/private/my-key.key;
    ssl_session_cache shared:SSL:1m;
    ssl_prefer_server_ciphers on;
 
    location / {
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_pass http://keycloak;
    }
}
EOF

Enable and start Nginx.

$ systemctl enable nginx
$ systemctl start nginx

Open port 80 and 443 in your firewall and you're done!