Skip to content

Instantly share code, notes, and snippets.

@soletan
Last active September 8, 2021 10:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soletan/02e141993a811221ce8347c5a6129021 to your computer and use it in GitHub Desktop.
Save soletan/02e141993a811221ce8347c5a6129021 to your computer and use it in GitHub Desktop.

Background

Intention

  • Single-node Docker swarm is used to benefit from single stack definition w/o need for installing docker-compose and lots of python libs on host.
    • Multi-node swarm is not supported here.
  • nginx is used as a reverse proxy in a separate container with certs maintained by host.

Assumptions

This tutorial is assuming some information you need to adopt to work on your server:

  • idp.example.com must be the FQDN of your host.
  • <db-user-secret> and <db-root-secret> must be random strings of sufficient length.
  • /opt/keycloak is name of the folder containing files specific to the docker stack. You can keep it like that.
  • Admin account name will be john.doe. You should use a different name for sure. Using admin is an option, but an obvious one. Using different name slightly increases security.

Host setup

  • Start with vanilla host (Ubuntu Linux).

Install Docker engine

  • Install Docker according to official tutorial.
  • Enable swarm mode: docker swarm init

Install nginx:

  • apt install nginx
  • Replace content of file /etc/nginx/sites-enabled/default with:
    server {
      listen 80 default_server;
    
      location /.well-known {
        root /var/www/certbot;
      }
    
      location / {
        return 308 https://$host$request_uri;
      }
    }
    
  • mkdir /var/www/certbot
  • systemctl restart nginx

Install certbot:

  • apt install snapd
  • snap install --classic certbot
  • Create file /etc/letsencrypt/renewal-hooks/deploy/kc.sh with content
    #!/bin/sh
      
    docker stack rm keycloak
    sleep 10
    docker stack deploy -c /opt/keycloak/docker-compose.yml keycloak
    
  • chmod 0755 /etc/letsencrypt/renewal-hooks/deploy/kc.sh

Fetch certificate:

  • certbot certonly --webroot -w /var/www/certbot -d idp.example.com

Prepare stack

  • mkdir /opt/keycloak
  • cd /opt/keycloak
  • Create file admin-pw containing desired admin password.
  • chmod 0400 admin-pw
  • Create file docker-compose.yml containing
    version: "3.8"
    
    services:
      idp:
        image: jboss/keycloak
        secrets:
          - admin-pw
        environment:
          KEYCLOAK_USER: john.doe
          KEYCLOAK_PASSWORD_FILE: /run/secrets/admin-pw
          KEYCLOAK_FRONTEND_URL: "https://idp.example.com/auth/"
          PROXY_ADDRESS_FORWARDING: "true"
          DB_VENDOR: mysql
          DB_ADDR: mysql
          DB_USER: keycloak
          DB_PASSWORD: "<db-user-secret>"
        networks:
          - db
          - www
    
      mysql:
        image: mysql
        environment:
          MYSQL_DATABASE: keycloak
          MYSQL_USER: keycloak
          MYSQL_PASSWORD: "<db-user-secret>"
          MYSQL_ROOT_PASSWORD: "<db-root-secret>"
        volumes:
          - "mysql:/var/lib/mysql"
        networks:
          - db
    
      nginx:
        image: nginx
        ports:
          - target: 443
            published: 443
            protocol: tcp
            mode: host
        configs:
          - source: nginx.conf
            target: /etc/nginx/conf.d/keycloak.conf
            uid: "101"
            gid: "101"
            mode: 0400
        secrets:
          - ssl.key
          - ssl.cert
        networks:
          - www
    
    secrets:
      admin-pw:
        file: ./admin-pw
      ssl.cert:
        file: /etc/letsencrypt/live/idp.example.com/fullchain.pem
      ssl.key:
        file: /etc/letsencrypt/live/idp.example.com/privkey.pem
    
    configs:
      nginx.conf:
        file: ./nginx.conf
    
    volumes:
      mysql:
    
    networks:
      db:
      www:
  • Create file nginx.conf with following content:
    proxy_buffer_size   128k;
    proxy_buffers   4 256k;
    proxy_busy_buffers_size   256k;
    
    server {
      listen 443 ssl default_server http2;
    
      add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    
      ssl_session_cache shared:SSL:20m;
      ssl_session_timeout 10m;
      ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
      ssl_prefer_server_ciphers on;
      ssl_ciphers 'ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5';
    
      ssl_certificate /run/secrets/ssl.cert;
      ssl_certificate_key /run/secrets/ssl.key;
    
      location / {
        proxy_pass http://idp:8080/;
        proxy_set_header Host idp.example.com;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
      }
    }
    

Control stack

Start

docker stack deploy -c /opt/keycloak/docker-compose.yml keycloak

Stop

docker stack rm keycloak

Inspect

docker stack services keycloak

Testing

Basically follow steps described here.

You probably will have issues with accessing account console for testing login as a regular user as instructed. This is due to some missing definition of permitted web origins for the account console.

  • Open admin console.
  • Select the realm you'd like to test.
  • Click "Clients" in left panel.
  • Click on "account-console" in list of clients for editing.
  • In "Settings" tab, look for field labelled "Web Origins", enter * there and click on "Save" button.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment