From b8aeb3dfd90ea3e4403b0cc1d13ca4cd05a7dee1 Mon Sep 17 00:00:00 2001 From: David Young Date: Thu, 13 Dec 2018 20:36:41 +1300 Subject: [PATCH] Added Keycloak --- manuscript/CHANGELOG.md | 1 + manuscript/images/keycloak.png | Bin 0 -> 32527 bytes .../recipes/{sso-stack => }/keycloak.md | 65 ++++++++++------- manuscript/recipes/munin.md | 2 +- manuscript/recipes/openldap.md | 69 +++++++++++++----- manuscript/reference/networks.md | 3 +- mkdocs.yml | 1 + 7 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 manuscript/images/keycloak.png rename manuscript/recipes/{sso-stack => }/keycloak.md (57%) diff --git a/manuscript/CHANGELOG.md b/manuscript/CHANGELOG.md index 3949b02..d4f4f65 100644 --- a/manuscript/CHANGELOG.md +++ b/manuscript/CHANGELOG.md @@ -15,6 +15,7 @@ ## Recently added recipes +* Added [KeyCloak](/recipes/keycloak), an open source identity and access management solution which backends neatly into [OpenLDAP](/recipes/openldap/) (among other providers), providing true SSO (_13 Dec 2018_) * Added [OpenLDAP](/recipes/openldap/), a 20-year old project which [refuses to die](https://www.youtube.com/watch?v=cnQEo4bazIo), underpinning many of today's authentication platforms, and providing a single authentication backend for multiple recipes (_9 Dec 2018_) * Added [Wetty](/recipes/wetty/), a remote terminal client in your web browser (_22 Nov 2018_) * Added [PrivateBin](/recipes/privatebin/), a self-hosted pastebin alternative (_5 Nov 2018_) diff --git a/manuscript/images/keycloak.png b/manuscript/images/keycloak.png new file mode 100644 index 0000000000000000000000000000000000000000..2e6a6c92c217c2a821ebc41ff4f2d38bc21dab2e GIT binary patch literal 32527 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 literal 0 HcmV?d00001 diff --git a/manuscript/recipes/sso-stack/keycloak.md b/manuscript/recipes/keycloak.md similarity index 57% rename from manuscript/recipes/sso-stack/keycloak.md rename to manuscript/recipes/keycloak.md index 3f75015..35547ff 100644 --- a/manuscript/recipes/sso-stack/keycloak.md +++ b/manuscript/recipes/keycloak.md @@ -1,7 +1,11 @@ # KeyCloak -!!! warning - While this could stand on its own as a standalone recipe, it's a component of the [sso-stack](/recipes/sso-stack/) "_uber-recipe_", and is written in the expectation that the entire SSO stack is being deployed. +[KeyCloak](https://www.keycloak.org/) is "an open source identity and access management solution." Using a local database, or a variety of backends (_think [OpenLDAP](/recipes/openldap/)_), you can provide Single Sign-On (SSO) using OpenID, OAuth 2.0, and SAML. + +!!! important + Development of this recipe is sponsored by [The Common Observatory](https://www.observe.global/). Thanks guys! + + [![Common Observatory](../images/common_observatory.png)](https://www.observe.global/) ![KeyCloak Screenshot](../images/keycloak.png) @@ -9,7 +13,7 @@ 1. [Docker swarm cluster](/ha-docker-swarm/design/) with [persistent shared storage](/ha-docker-swarm/shared-storage-ceph.md) 2. [Traefik](/ha-docker-swarm/traefik_public) configured per design -3. DNS entry for the hostname you intend to use, pointed to your [keepalived](ha-docker-swarm/keepalived/) IP +3. DNS entry for the hostname (_i.e. "keycloak.your-domain.com"_) you intend to use for LDAP Account Manager, pointed to your [keepalived](ha-docker-swarm/keepalived/) IP ## Preparation @@ -24,12 +28,13 @@ mkdir /var/data/keycloak/database-dump ### Prepare environment -Create /var/data/keycloak/keycloak.env, and populate with the following variables, customized for your own domain struction. Take care with LDAP_DOMAIN, this is core to the rest of the [sso-stack](/recipes/sso-stack/), and can't easily be changed later. +Create ```/var/data/keycloak/keycloak.env```, and populate with the following variables, customized for your own domain structure. + ``` # Technically, this could be auto-detected, but we prefer to be prescriptive DB_VENDOR=postgres DB_DATABASE=keycloak -DB_ADDR=db +DB_ADDR=keycloak-db DB_USER=keycloak DB_PASSWORD=myuberpassword KEYCLOAK_USER=admin @@ -39,7 +44,7 @@ KEYCLOAK_PASSWORD=ilovepasswords PROXY_ADDRESS_FORWARDING=true # What's our hostname? -KEYCLOAK_HOSTNAME=cloud.example.com +KEYCLOAK_HOSTNAME=keycloak.batcave.com # Tell Postgress what user/password to create POSTGRES_USER=keycloak @@ -49,7 +54,7 @@ POSTGRES_PASSWORD=myuberpassword Create /var/data/keycloak/keycloak-backup.env, and populate with the following, so that your database can be backed up to the filesystem, daily: ``` -PGHOST=db +PGHOST=keycloak-db PGUSER=keycloak PGPASSWORD=myuberpassword BACKUP_NUM_KEEP=7 @@ -69,28 +74,31 @@ services: keycloak: image: jboss/keycloak env_file: /var/data/config/keycloak/keycloak.env + volumes: + - /etc/localtime:/etc/localtime:ro networks: - traefik_public deploy: labels: - - traefik.frontend.rule=Host:keycloak.cloud.example.com + - traefik.frontend.rule=Host:keycloak.batcave.com - traefik.port=8080 - traefik.docker.network=traefik_public - db: + keycloak-db: env_file: /var/data/config/keycloak/keycloak.env image: postgres:10.1 volumes: - /var/data/runtime/keycloak/database:/var/lib/postgresql/data + - /etc/localtime:/etc/localtime:ro networks: - traefik_public - db-backup: + keycloak-db-backup: image: postgres:10.1 env_file: /var/data/config/keycloak/keycloak-backup.env volumes: - /var/data/keycloak/database-dump:/dump -# - /etc/localtime:/etc/localtime:ro + - /etc/localtime:/etc/localtime:ro entrypoint: | bash -c 'bash -s <_internal network. This avoids IP/gateway conflicts which can otherwise occur when you're creating/removing stacks a lot. See [my list](/reference/networks/) here. + + However, KeyCloak's JBOSS startup script assumes a single interface, and will crash in a ball of 🔥 if you try to assign multiple interfaces to the container. This means that we can't use a "keycloak_internal" network for our supporting containers. This is why unlike our other recipes, all the supporting services are prefixed with "keycloak-". ## Serving -### Launch OpenLDAP stack +### Launch KeyCloak stack Launch the OpenLDAP stack by running ```docker stack deploy keycloak -c ``` Log into your new instance at https://**YOUR-FQDN**, and login with the user/password you defined in keycloak.env. +### Integrating into OpenLDAP + +KeyCloak gets really sexy when you integrate it into your [OpenLDAP](/recipes/openldap/) stack (_also, it's great not to have to play with ugly LDAP tree UIs_). + +You'll need to have completed the [OpenLDAP](/recipes/openldap/) recipe + You start in the "Master" realm - but mouseover the realm name, to a dropdown box allowing you add an new realm: ![KeyCloak Add Realm Screenshot](/images/sso-stack-keycloak-1.png) @@ -139,16 +150,16 @@ Once in the desired realm, click on **User Federation**, and click **Add Provide * **Edit Mode** : Writeable * **Vendor** : Other * **Connection URL** : ldap://openldap -* **Users DN** : ou=People, +* **Users DN** : ou=People, * **Authentication Type** : simple -* **Bind DN** : cn=admin, -* **Bind Credential** : +* **Bind DN** : cn=admin, +* **Bind Credential** : Save your changes, and then navigate back to "User Federation" > Your LDAP name > Mappers: ![KeyCloak Add Realm Screenshot](/images/sso-stack-keycloak-3.png) -For each of the following names, click the name, and set the "_Read Only_" flag to "_Off_" (_this enables 2-way sync between KeyCloak and OpenLD_AP) +For each of the following mappers, click the name, and set the "_Read Only_" flag to "_Off_" (_this enables 2-way sync between KeyCloak and OpenLDAP_) * last name * username @@ -157,11 +168,15 @@ For each of the following names, click the name, and set the "_Read Only_" flag ![KeyCloak Add Realm Screenshot](/images/sso-stack-keycloak-4.png) -Proceed to setting up [Email](/recipes/sso-stack/docker-mailserver/)... +!!! important + Development of this recipe is sponsored by [The Common Observatory](https://www.observe.global/). Thanks guys! + + [![Common Observatory](../images/common_observatory.png)](https://www.observe.global/) + ## Chef's Notes -1. I wanted to be able to add multiple networks to KeyCloak (i.e., a dedicated overlay network for LDAP authentication), but the entrypoint used by the container produces an error when more than one network is configured. This could theoretically be corrected in future, with a PR. +1. I wanted to be able to add multiple networks to KeyCloak (_i.e., a dedicated overlay network for LDAP authentication_), but the entrypoint used by the container produces an error when more than one network is configured. This could theoretically be corrected in future, with a PR, but the [GitHub repo](https://github.com/jboss-dockerfiles/keycloak) has no issues enabled, so I wasn't sure where to start. ### Tip your waiter (donate) 👏 diff --git a/manuscript/recipes/munin.md b/manuscript/recipes/munin.md index 6172d2b..be55f96 100644 --- a/manuscript/recipes/munin.md +++ b/manuscript/recipes/munin.md @@ -94,7 +94,7 @@ services: - /var/data/munin/cache:/var/cache/munin proxy: - image: a5huynh/oauth2_proxy + image: funkypenguin/oauth2_proxy env_file: /var/data/config/munin/munin.env networks: - traefik_public diff --git a/manuscript/recipes/openldap.md b/manuscript/recipes/openldap.md index 4b28826..7315d22 100644 --- a/manuscript/recipes/openldap.md +++ b/manuscript/recipes/openldap.md @@ -45,7 +45,7 @@ mkdir /var/data/runtime/openldap/ ### Prepare environment -Create /var/data/openldap/openldap.env, and populate with the following variables, customized for your own domain structure. Take care with LDAP_DOMAIN, this is core to your directory strucutre, and can't easily be changed later. +Create /var/data/openldap/openldap.env, and populate with the following variables, customized for your own domain structure. Take care with LDAP_DOMAIN, this is core to your directory structure, and can't easily be changed later. ``` LDAP_DOMAIN=batcave.gotham @@ -53,12 +53,15 @@ LDAP_ORGANISATION=BatCave Inc LDAP_ADMIN_PASSWORD=supermansucks LDAP_TLS=false -# For the oauth2_proxy elements used to protect LAM +# Use these if you plan to protect the LDAP Account Manager webUI with an oauth_proxy OAUTH2_PROXY_CLIENT_ID= OAUTH2_PROXY_CLIENT_SECRET= OAUTH2_PROXY_COOKIE_SECRET= ``` +!!! note + I use an [OAuth proxy](/reference/oauth_proxy/) to protect access to the web UI, when the sensitivity of the protected data (i.e. my authentication store) warrants it, or if I don't necessarily trust the security of the webUI. + Create ```authenticated-emails.txt```, and populate with the email addresses (_matched to GitHub user accounts, in my case_) to which you want grant access, using OAuth2. ### Create config.cfg @@ -329,7 +332,7 @@ Create yours profile (_you chose a default profile in config.cfg above, remember ### Setup Docker Swarm -Create a docker swarm config file in docker-compose syntax (v3), something like this: +Create a docker swarm config file in docker-compose syntax (v3), something like this, at (```/var/data/config/openldap/openldap.yml```) !!! tip I share (_with my [patreon patrons](https://www.patreon.com/funkypenguin)_) a private "_premix_" git repository, which includes necessary docker-compose and env files for all published recipes. This means that patrons can launch any recipe with just a ```git pull``` and a ```docker stack deploy``` 👍 @@ -341,7 +344,8 @@ services: image: osixia/openldap env_file: /var/data/config/openldap/openldap.env networks: - - internal + - traefik_public + - auth_internal volumes: - /var/data/runtime/openldap/:/var/lib/ldap - /var/data/openldap/openldap/:/etc/ldap/slapd.d @@ -349,46 +353,75 @@ services: lam: image: jacksgt/ldap-account-manager networks: - - internal + - auth_internal volumes: - /var/data/openldap/lam/config/config.cfg:/var/www/html/config/config.cfg - /var/data/openldap/lam/config/batcave.conf:/var/www/html/config/batcave.conf - proxy: + lam-proxy: image: funkypenguin/oauth2_proxy env_file: /var/data/config/openldap/openldap.env networks: - traefik_public - - internal + - auth_internal deploy: labels: - - traefik.frontend.rule=Host:lam.batcave.gotham + - traefik.frontend.rule=Host:lam.batcave.com + - traefik.docker.network=traefik_public - traefik.port=4180 - volumes: - - /var/data/config/openldap/authenticated-emails.txt:/authenticated-emails.txt command: | -cookie-secure=false - -upstream=http://lam:8080 - -redirect-url=https://lam.batcave.gotham + -upstream=http://lam:80 + -redirect-url=https://lam.batcave.com -http-address=http://0.0.0.0:4180 - -email-domain=example.com + -email-domain=batcave.com -provider=github - -authenticated-emails-file=/authenticated-emails.txt networks: + # Used to expose lam-proxy to external access, and openldap to keycloak traefik_public: external: true + + # Used to expose openldap to other apps which want to talk to LDAP, including LAM + auth_internal: + external: true ``` -!!! note - Setup unique static subnets for every stack you deploy. This avoids IP/gateway conflicts which can otherwise occur when you're creating/removing stacks a lot. See [my list](/reference/networks/) here. +!!! warning + **Normally**, we set unique static subnets for every stack you deploy, and put the non-public facing components (like databases) in an dedicated _internal network. This avoids IP/gateway conflicts which can otherwise occur when you're creating/removing stacks a lot. See [my list](/reference/networks/) here. + + However, you're likely to want to use OpenLdap with KeyCloak, whose JBOSS startup script assumes a single interface, and will crash in a ball of 🔥 if you try to assign multiple interfaces to the container. + + Since we're going to want KeyCloak to be able to talk to OpenLDAP, we have no choice but to leave the OpenLDAP container on the "traefik_public" network. We can, however, create **another** overlay network (_auth_internal, see below_), add it to the openldap container, and use it to provide OpenLDAP access to our other stacks. + +Create **another** stack config file (```/var/data/config/openldap/auth.yml```) containing just the auth_internal network, and a dummy container: + +``` +version: '3' + +services: + helloworld: + image: hello-world + networks: + - internal + +networks: + internal: + driver: overlay + ipam: + config: + - subnet: 172.16.39.0/24 +``` + + + ## Serving ### Launch OpenLDAP stack -Launch the OpenLDAP stack by running ```docker stack deploy openldap -c ``` +Create the auth_internal overlay network, by running ```docker stack deploy auth -c /var/data/config/openldap/auth.yml`, then launch the OpenLDAP stack by running ```docker stack deploy openldap -c /var/data/config/openldap/openldap.yml``` Log into your new LAM instance at https://**YOUR-FQDN**. @@ -406,7 +439,7 @@ Create your users using the "**New User**" button. ## Chef's Notes -1. An upcoming recipe for [KeyCloak](https://www.keycloak.org/) will illustrate how to integrate KeyCloak with your LDAP directory. +1. The KeyCloak](/recipes/keycloak/) recipe illustrates how to integrate KeyCloak with your LDAP directory, giving you a cleaner interface to manage users, and a raft of SSO / OAuth features. ### Tip your waiter (donate) 👏 diff --git a/manuscript/reference/networks.md b/manuscript/reference/networks.md index ec29f3e..f73c05f 100644 --- a/manuscript/reference/networks.md +++ b/manuscript/reference/networks.md @@ -38,7 +38,7 @@ Network | Range [ElkarBackup](https://geek-cookbook.funkypenguin.co.nz/recipes/elkarbackp/) | 172.16.36.0/24 [Mayan EDMS](https://geek-cookbook.funkypenguin.co.nz/recipes/realms/) | 172.16.37.0/24 [Shaarli](https://geek-cookbook.funkypenguin.co.nz/recipes/shaarli/) | 172.16.38.0/24 -[KeyCloud](https://geek-cookbook.funkypenguin.co.nz/recipes/keycloak/) | 172.16.39.0/24 +[OpenLDAP](https://geek-cookbook.funkypenguin.co.nz/recipes/openldap/) | 172.16.39.0/24 [MatterMost](https://geek-cookbook.funkypenguin.co.nz/recipes/mattermost/) | 172.16.40.0/24 [PrivateBin](https://geek-cookbook.funkypenguin.co.nz/recipes/privatebin/) | 172.16.41.0/24 [Mayan EDMS](https://geek-cookbook.funkypenguin.co.nz/recipes/mayan-edms/) | 172.16.42.0/24 @@ -46,7 +46,6 @@ Network | Range [FlightAirMap](https://geek-cookbook.funkypenguin.co.nz/recipes/flightairmap/) |172.16.44.0/24 [Wetty](https://geek-cookbook.funkypenguin.co.nz/recipes/wetty/) | 172.16.45.0/24 [FileBrowser](https://geek-cookbook.funkypenguin.co.nz/recipes/filebrowser/) | 172.16.46.0/24 -[OpenLDAP](https://geek-cookbook.funkypenguin.co.nz/recipes/openldap/) | 172.16.47.0/24 ## Chef's Notes diff --git a/mkdocs.yml b/mkdocs.yml index 2c7be7e..65154a8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -85,6 +85,7 @@ pages: - GitLab Runner: recipes/gitlab-runner.md - Gollum: recipes/gollum.md - InstaPy: recipes/instapy.md + - KeyCloak: recipes/keycloak.md - OpenLDAP: recipes/openldap.md - Piwik: recipes/piwik.md - Portainer: recipes/portainer.md