I am a part-time cyber security lecturer at the software engineering department of the University of Applied Science in Rapperswil Switzerland. My students must learn several programming skills and in almost any web software project some sort of authentication and authorization must be applied. I want my students to spend their time working on the real purpose of the software problem (problem domain), instead of spending hours with authentication and authorization. Needless to say this is a crucial task in a real software project. Read this tutorial and I will show you how to add authentication to any web service that does not have a builtin authentication layer using keycloak IdP and keycloak proxy.
For the sake of this tutorial I have chosen the ttyd Docker image we want to add authentication using Keycloak. The ttyd application provides web access bash
to a kali linux machine. The ttyd sample application is not asking for a username and password. You can grab the ttyd docker source from GitHub https://github.com/ibuetler/e1pub/tree/master/docker/hl-kali-docker-ttyd or pull the image from Docker Hub. I will pull and run the docker image below, as this tutorial is not about "how to create docker images/". The ttyd web port is listening on port 7681
.
docker pull hackinglab/hl-kali-docker-ttyd
docker run --rm -i -p 7681:7681 hackinglab/hl-kali-docker-ttyd
CTRL+C will stop the docker
See the screenshot below how to pull and run and test ttyd
Please give it a try! I am doing this demo using the latest Hacking-Lab LiveCD from https://livecd.hacking-lab.com/, as the LiveCD has docker and everything already configured and works like a charm. If you want to use the Hacking-Lab LiveCD too, please follow the following installation instructions
https://github.com/ibuetler/e1pub/tree/master/hacking-lab-livecd-installation
Once you're good, please stop the docker in the same terminal you have executed "docker run..." by pressing CTRL-C. This will shutdown the ttyd docker service. It must be shutdown for the next steps.
I run all my docker services behind
traefik (https://traefik.io/). I do not want to have my (hundreds of) docker services, APIs, RESTful APIs and more directly accessible from the Internet (security). I do not want to create and handle SSL/TLS certificates for every single docker services. In production; I am using an SSL wildcard certificate or Let's Encrypt TLS and point it to the traefik ip address. In development; Traefik is automatically creating self-signed certificates for me. This is what we want in this tutorial. Needless to say, Traefik is a docker service too.
Traefik terminates TLS/SSL and routes everything, based on HOST or URL pattern rules, to the designated docker-based and on-demand back-end service. Furthermore, traefik is docker-aware and allows registering or unregistering docker services without restarting traefik.
Before we proceed with setting up our traefik docker, please pull the workshop github repo first. This will save you time as the traefik and all other docker-compose.yml files are ready for testing in the workshop repo.
Please pull the workshop repo using the following commands. I have chosen /opt/git/
as the base directory for this tutorial. Change it to whatever you like or prefer.
mkdir -p /opt/git
cd /opt/git
git clone https://github.com/ibuetler/docker-keycloak-traefik-workshop.git
cd /opt/git/docker-keycloak-traefik-workshop/
ls -al
The command ls -al
is listing the directory of the workshop files. You should have multiple files and directories we need in this tutorial.
Traefik itself must be assigned to every docker network it will route packages to and from. The workshop demo is based on a docker network between Traefik and the IdP (Keycloak) and another docker network between Traefik and our sample application (ttyd). The following commands will create the transit_idp and transit_ttyd networks for you.
cd /opt/git/docker-keycloak-traefik-workshop/traefik
bash create_network.sh
This will create the transit networks for you. If you don't want to run the script, you can run the commands manually
docker network create transit_idp
docker network create transit_ttyd
Next we want to run the traefik service. There is a docker-compose.yml available. Please follow the instructions below. This will pull the traefik image and starts traefik in daemon mode. Using the command docker-compose logs -f
, you can see the traefik service log which is set to DEBUG.
cd /opt/git/docker-keycloak-traefik-workshop/traefik
docker-compose up -d
docker-compose logs -f
You should have tested ttyd in Step 1
and Traefik should be up and running in Step 2
. Time to test, how to connect these two docker services together. Please open a new root terminal.
The commands below will start the ttyd docker and is registering the ttyd service to traefik. The magic is within the traefik labels of the docker-compose.yml
file. Please make sure your traefik service is still running from Step 2
cd /opt/git/docker-keycloak-traefik-workshop/ttyd
docker-compose up -d
docker-compose logs -f
Before you can test the traefik and ttyd daemon, you must add three host entries into the /etc/hosts file. This is, because we do the demo without real DNS names.
echo "127.0.0.1 ttyd.idocker.hacking-lab.com" >> /etc/hosts
echo "127.0.0.1 auth.idocker.hacking-lab.com" >> /etc/hosts
echo "127.0.0.1 traefik.idocker.hacking-lab.com" >> /etc/hosts
Now you should have the /etc/hosts entries, in one linux terminal you should have your traefik docker service up and running and in another linux terminal you should have the ttyd docker service up and running.
Can you answer all these pre-requirements
with YES?
Ok, then let's see how it works using the browser.
Please open Firefox and point your browser to https://ttyd.idocker.hacking-lab.com
Due to the self-signed TLS certificates (traefik will generate them on the fly for you) you must click on "Advanced" and "Add Exception" to proceed. And as you can see in the screenshot below, the ttyd is now secured with the https of the traefik load balancer (but still without authentication).
If you did the tutorial until here? This is awesome. Until now you have setup a load balancer (traefik) and you put a service (ttyd) behind the load balancer. You have SSL/TLS up and running and the dynamic registration of your application (ttyd) with traefik works like a charm. You have not yet added authentication to it (next step) but still, this is a first success.
For the sake of this tutorial I use keycloak, an open-source identity provider IdP
that runs smoothly with docker. If you don’t know keycloak, I encourage you to get into this project. It is the open source version of the RedHat RH-SSO solution.
We need to setup and configure Keycloak. Thus, please follow the instructions below, assuming have successfully done step 1 to step 5 in this tutorial.
Please open another new linux terminal.
cd /opt/git/docker-keycloak-traefik-workshop/keycloak
docker-compose up -d
If you run this the first time, it will pull the keycloak images/
Once the prompt returns, you can start monitoring the logs
cd /opt/git/docker-keycloak-traefik-workshop/keycloak
docker-compose logs -f
You must wait 30-60 seconds before keycloak is fully setup. Plese wait some time.
Afterwards, you should be able to use Firefox to reach your newly created IdP.
Traefik is issuing another self-signed TLS certificate.
Please proceed again and you should see the IdP login prompt.
username: admin
password: changeme-keycloak
And voilà, your keycloak IdP should be up and working.
If you did the tutorial until here? You are awesome. You have now Keycloak IdP, together with Traefik up and running. Keycloak is not yet setup for you. But still, this is great work. Well done!
Please note; We want to secure an application (ttyd) that comes without built-in authentication and authorization and have therefore configured traefik
, keycloak
and ttyd
in the steps above.
What is the final step? A new docker is required. The keycloak-gatekeeper
docker image in front of the ttyd docker will do the job for us. The keycloak-gatekeeper
docker service will ensure users must authenticate before the ttyd service can be used. In other words, keycloak-gatekeeper is kind of a reverse-proxy in front of our application that has no built-in authentication and authorization layer but integrates very well with Keycloak IdP.
As you can see in the picture above, traefik is handling all internet traffic and forwards the traffic to the backend service(s). Backend services are not configured statically, instead they register on-demand once we spin-up the backend docker service.
With OIDC (openid-connect), the client and IdP are sharing a shared secret. Thus, we must first setup a new client in Keycloak and copy the secret from there. We must then use the new key in our keycloak-gatekeeper configuration. These are the lasts steps in this tutorial.
You must create a new client in Keycloak. Please follow the screenshots below. Please click on "Clients" in the left menu and then click on "Create" as in the picture below.
Please give it a name and configure the client URL. For this tutorial https://ttyd.idocker.hacking-lab.com
.
Press choose "confidential" in the "Access Type" item and press "Save".
After saving, please click the "Credentials" menu item where you will find the secret we need for keycloak-gatekeeper. Copy the Secret as you need it later when configuring keycloak-gatekeeper
.
With the new Keycloak software, users must be assigned to a valid audience and scope before they can use a keycloak enabled service. Thus, let's configure the audience and scope.
Please click on "Client Scopes" in the left menu and press "Create".
Give a Name and Description. I have chosen ttyd.
Please click on "Mappers".
Please configure the mapper the same as in the screenshot below. Most important, you must use Audience
in the mapper type field.
Last, you must apply the newly created mapper to your ttyd client configuration.
Now you have successfully finished the Keycloak configuration for the new (ttyd) client application.
The settings are applied to the "Master Realm". If we would have created a new REALM when we started configuring Keycloak, this could as easily be applied to your self-defined REALM. If the last sentence makes no sense to you; don't worry. You can play with the Keycloak Realms (organisation, entity) later on your own.
Please switch on "User registration" on the Master Realm Settings tab.
Please start in Firefox a "New Private Window" and connect to the following URL
https://auth.idocker.hacking-lab.com/auth/realms/master/account
Please register a new account
Enter your data here
Use your Firefox instance where you are logged-in as admin
and check if the user has been created.
PS: you can setup the user directly within Keycloak, if you want. These steps were more to say: "hey, users can self-register in Keycloak".
Did your really do the tutorial until here? This is extremely passionate. Let's briefly give some conclusion what you have reached so far. You did the client configuration in Keycloak, you have created the mappers (access control for the service) and you have created and copied the client secret.
Furthermore, you have configured the login service to allow self registration and you have tested this by self-registering a test user in a "New Private Browsing Firefox" session. Lastely, you have checked if the newly created user is being listed/available in Keycloak. This is mandatory to have a test account for the next step.
If you have not missed anything of the steps above, you should now be ready for the last step, configuring keycloak-gatekeeper and applying authentication to the ttyd docker application.
First of all, please stop the ttyd docker (only the tty docker, but keep the keycloak and traefik docker up and running). We will start the ttyd together with keycloak-gatekeeper. That's why we must stop it here.
With CTRL-C, you are only stopping the log watch. Thus, please stop the docker using the following command
docker-compose down
Please configure your keycloak-gatekeeper with your client secret.
cd /opt/git/docker-keycloak-traefik-workshop/keycloak-gatekeeper
mousepad keycloak-gatekeeper.conf
Please specify your own client secret
. Everything else can be the same as in the screenshot below.
If you don't remember, the client secret comes from the client configuration tab. Copy your value from there.
Let's briefly check the docker-compose.yml. This will start your keycloak-gatekeeper
and the ttyd
docker service. They share the transit_ttyd
network.
cd /opt/git/docker-keycloak-traefik-workshop/keycloak-gatekeeper
╰─$ cat docker-compose.yml
version: '2'
services:
auth-proxy:
image: hackinglab/keycloak-gatekeeper:latest
labels:
- "traefik.port=3000"
- "traefik.frontend.rule=Host:ttyd.idocker.hacking-lab.com"
- "traefik.protocol=http"
networks:
transit_ttyd:
volumes:
- ./keycloak-gatekeeper.conf:/etc/keycloak-gatekeeper.conf
entrypoint:
- /opt/keycloak-gatekeeper
- --config=/etc/keycloak-gatekeeper.conf
ttyd:
image: hackinglab/hl-kali-docker-ttyd
networks:
transit_ttyd:
labels:
- "traefik.enable=false"
networks:
transit_ttyd:
external: true
Now, let's start keycloak-gatekeeper & ttyd using docker-compose.
cd /opt/git/docker-keycloak-traefik-workshop/keycloak-gatekeeper
docker-compose up -d
docker-compose logs -f
After this tutorial you should have an application (ttyd) that comes without authentication and authorization secured using traefik, keycloak and keycloak-gateeeper. The steps taken in this tutorial hopefully have guided you to the end - to a working setup.
Thank you, Ivan Bütler