mirror of
https://github.com/funkypenguin/geek-cookbook/
synced 2025-12-13 09:46:23 +00:00
Experiment with PDF generation
Signed-off-by: David Young <davidy@funkypenguin.co.nz>
This commit is contained in:
206
docs/docker-swarm/traefik-forward-auth/dex-static.md
Normal file
206
docs/docker-swarm/traefik-forward-auth/dex-static.md
Normal file
@@ -0,0 +1,206 @@
|
||||
---
|
||||
title: SSO with traefik forward auth and Dex
|
||||
description: Traefik forward auth needs an authentication backend, but if you don't want to use a cloud provider, you can setup your own simple OIDC backend, using Dex.
|
||||
---
|
||||
# Traefik Forward Auth for SSO with Dex (Static)
|
||||
|
||||
[Traefik Forward Auth](/docker-swarm/traefik-forward-auth/) is incredibly useful to secure services with an additional layer of authentication, provided by an OIDC-compatible provider. The simplest possible provider is a self-hosted instance of [CoreOS's Dex](https://github.com/dexidp/dex), configured with a static username and password. This recipe will "get you started" with Traefik Forward Auth, providing a basic authentication layer. In time, you might want to migrate to a "public" provider, like [Google][tfa-google], or GitHub, or to a [Keycloak][keycloak] installation.
|
||||
|
||||
--8<-- "recipe-tfa-ingredients.md"
|
||||
|
||||
## Preparation
|
||||
|
||||
### Setup dex config
|
||||
|
||||
Create `/var/data/config/dex/config.yml` something like the following (*this is a bare-bones, [minimal example](https://github.com/dexidp/dex/blob/master/config.dev.yaml)*). At the very least, you want to replace all occurances of `example.com` with your own domain name. (*If you change nothing else, your ID is `foo`, your secret is `bar`, your username is `admin@yourdomain`, and your password is `password`*):
|
||||
|
||||
```yaml
|
||||
# The base path of dex and the external name of the OpenID Connect service.
|
||||
#
|
||||
# This is the canonical URL that all clients MUST use to refer to dex. If a
|
||||
# path is provided, dex's HTTP service will listen at a non-root URL.
|
||||
issuer: https://dex.example.com
|
||||
|
||||
storage:
|
||||
type: sqlite3
|
||||
config:
|
||||
file: var/sqlite/dex.db
|
||||
|
||||
web:
|
||||
http: 0.0.0.0:5556
|
||||
|
||||
oauth2:
|
||||
skipApprovalScreen: true
|
||||
|
||||
staticClients:
|
||||
- id: foo
|
||||
redirectURIs:
|
||||
- 'https://auth.example.com/_oauth'
|
||||
name: 'example.com'
|
||||
secret: bar
|
||||
|
||||
enablePasswordDB: true
|
||||
|
||||
staticPasswords:
|
||||
- email: "admin@example.com"
|
||||
# bcrypt hash of the string "password"
|
||||
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
|
||||
username: "admin"
|
||||
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
|
||||
```
|
||||
|
||||
### Prepare Traefik Forward Auth environment
|
||||
|
||||
Create `/var/data/config/traefik-forward-auth/traefik-forward-auth.env` per the following example configuration:
|
||||
|
||||
```bash
|
||||
DEFAULT_PROVIDER: oidc
|
||||
PROVIDERS_OIDC_CLIENT_ID: foo # This is the staticClients.id value in config.yml above
|
||||
PROVIDERS_OIDC_CLIENT_SECRET: bar # This is the staticClients.secret value in config.yml above
|
||||
PROVIDERS_OIDC_ISSUER_URL: https://dex.example.com # This is the issuer value in config.yml above, and it has to be reachable via a browser
|
||||
SECRET: imtoosexyformyshorts # Make this up. It's not configured anywhere else
|
||||
AUTH_HOST: auth.example.com # This should match the value of the traefik hosts labels in Traefik Forward Auth
|
||||
COOKIE_DOMAIN: example.com # This should match your base domain
|
||||
```
|
||||
|
||||
### Setup Docker Stack for Dex
|
||||
|
||||
Now create a docker swarm config file in docker-compose syntax (v3), per the following example:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
dex:
|
||||
image: dexidp/dex
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /var/data/config/dex/config.yml:/config.yml:ro
|
||||
networks:
|
||||
- traefik_public
|
||||
command: ['serve','/config.yml']
|
||||
deploy:
|
||||
labels:
|
||||
# traefik
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=traefik_public
|
||||
|
||||
# traefikv1
|
||||
- traefik.frontend.rule=Host:dex.example.com
|
||||
- traefik.port=5556
|
||||
- traefik.docker.network=traefik_public
|
||||
|
||||
# and for traefikv2:
|
||||
- "traefik.http.routers.dex.rule=Host(`dex.example.com`)"
|
||||
- "traefik.http.routers.dex.entrypoints=https"
|
||||
- "traefik.http.services.dex.loadbalancer.server.port=5556"
|
||||
|
||||
networks:
|
||||
traefik_public:
|
||||
external: true
|
||||
```
|
||||
|
||||
--8<-- "premix-cta.md"
|
||||
|
||||
### Setup Docker Stack for Traefik Forward Auth
|
||||
|
||||
Now create a docker swarm config file for traefik-forward-auth, in docker-compose syntax (v3), per the following example:
|
||||
|
||||
```yaml
|
||||
version: "3.2"
|
||||
|
||||
services:
|
||||
|
||||
traefik-forward-auth:
|
||||
image: thomseddon/traefik-forward-auth:2.2.0
|
||||
env_file: /var/data/config/traefik-forward-auth/traefik-forward-auth.env
|
||||
volumes:
|
||||
- /var/data/config/traefik-forward-auth/config.ini:/config.ini:ro
|
||||
networks:
|
||||
- traefik_public
|
||||
deploy:
|
||||
labels:
|
||||
# traefikv1
|
||||
- "traefik.port=4181"
|
||||
- "traefik.frontend.rule=Host:auth.example.com"
|
||||
- "traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181"
|
||||
- "traefik.frontend.auth.forward.trustForwardHeader=true"
|
||||
|
||||
# traefikv2
|
||||
- "traefik.docker.network=traefik_public"
|
||||
- "traefik.http.routers.auth.rule=Host(`auth.example.com`)"
|
||||
- "traefik.http.routers.auth.entrypoints=https"
|
||||
- "traefik.http.routers.auth.tls=true"
|
||||
- "traefik.http.routers.auth.tls.domains[0].main=example.com"
|
||||
- "traefik.http.routers.auth.tls.domains[0].sans=*.example.com"
|
||||
- "traefik.http.routers.auth.tls.certresolver=main"
|
||||
- "traefik.http.routers.auth.service=auth@docker"
|
||||
- "traefik.http.services.auth.loadbalancer.server.port=4181"
|
||||
- "traefik.http.middlewares.forward-auth.forwardauth.address=http://traefik-forward-auth:4181"
|
||||
- "traefik.http.middlewares.forward-auth.forwardauth.trustForwardHeader=true"
|
||||
- "traefik.http.middlewares.forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User"
|
||||
- "traefik.http.routers.auth.middlewares=forward-auth"
|
||||
|
||||
# This simply validates that traefik forward authentication is working
|
||||
whoami:
|
||||
image: containous/whoami
|
||||
networks:
|
||||
- traefik_public
|
||||
deploy:
|
||||
labels:
|
||||
# traefik
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_public"
|
||||
|
||||
# traefikv1
|
||||
- "traefik.frontend.rule=Host:whoami.example.com"
|
||||
- "traefik.http.services.whoami.loadbalancer.server.port=80"
|
||||
- "traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181"
|
||||
- "traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User"
|
||||
- "traefik.frontend.auth.forward.trustForwardHeader=true"
|
||||
|
||||
# traefikv2
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=https"
|
||||
- "traefik.http.services.whoami.loadbalancer.server.port=80"
|
||||
- "traefik.http.routers.whoami.middlewares=forward-auth"
|
||||
|
||||
networks:
|
||||
traefik_public:
|
||||
external: true
|
||||
```
|
||||
|
||||
## Serving
|
||||
|
||||
### Launch
|
||||
|
||||
Deploy dex with `docker stack deploy dex -c /var/data/dex/dex.yml`, to launch dex, and then deploy Traefik Forward Auth with `docker stack deploy traefik-forward-auth -c /var/data/traefik-forward-auth/traefik-forward-auth.yml`
|
||||
|
||||
Once you redeploy traefik-forward-auth with the above, it **should** use dex as an OIDC provider, authenticating you against the `staticPasswords` username and hashed password described in `config.yml` above.
|
||||
|
||||
### Test
|
||||
|
||||
Browse to <https://whoami.example.com> (*obviously, customized for your domain and having created a DNS record*), and all going according to plan, you'll be redirected to a CoreOS Dex login. Once successfully logged in, you'll be directed to the basic whoami page :thumbsup:
|
||||
|
||||
### Protect services
|
||||
|
||||
To protect any other service, ensure the service itself is exposed by Traefik. Add the following label:
|
||||
|
||||
```yaml
|
||||
- "traefik.http.routers.radarr.middlewares=forward-auth"
|
||||
```
|
||||
|
||||
And re-deploy your services :)
|
||||
|
||||
## Summary
|
||||
|
||||
What have we achieved? By adding an additional label to any service, we can secure any service behind our (static) OIDC provider, with minimal processing / handling overhead.
|
||||
|
||||
!!! summary "Summary"
|
||||
Created:
|
||||
|
||||
* [X] Traefik-forward-auth configured to authenticate against Dex (static)
|
||||
|
||||
[^1]: You can remove the `whoami` container once you know Traefik Forward Auth is working properly
|
||||
|
||||
--8<-- "recipe-footer.md"
|
||||
134
docs/docker-swarm/traefik-forward-auth/google.md
Normal file
134
docs/docker-swarm/traefik-forward-auth/google.md
Normal file
@@ -0,0 +1,134 @@
|
||||
---
|
||||
title: SSO with traefik forward auth with Google Oauth2
|
||||
description: Using Traefik Forward Auth, you can selectively apply SSO to your Docker services, using Google Oauth2 / OIDC as your authentication backend!
|
||||
---
|
||||
# Traefik Forward Auth using Google Oauth2 for SSO
|
||||
|
||||
[Traefik Forward Auth][tfa] is incredibly useful to secure services with an additional layer of authentication, provided by an OIDC-compatible provider. The simplest possible provider is a self-hosted instance of [Dex][tfa-dex-static], configured with a static username and password. This is not much use if you want to provide "normies" access to your services though - a better solution would be to validate their credentials against an existing trusted public source.
|
||||
|
||||
This recipe will illustrate how to point Traefik Forward Auth to Google, confirming that the requestor has a valid Google account (*and that said account is permitted to access your services!*)
|
||||
|
||||
--8<-- "recipe-tfa-ingredients.md"
|
||||
|
||||
## Preparation
|
||||
|
||||
### Obtain OAuth credentials
|
||||
|
||||
#### TL;DR
|
||||
|
||||
Log into <https://console.developers.google.com/>, create a new project then search for and select "**Credentials**" in the search bar.
|
||||
|
||||
Fill out the "OAuth Consent Screen" tab, and then click, "**Create Credentials**" > "**OAuth client ID**". Select "**Web Application**", fill in the name of your app, skip "**Authorized JavaScript origins**" and fill "**Authorized redirect URIs**" with either all the domains you will allow authentication from, appended with the url-path (*e.g. <https://radarr.example.com/_oauth>, <https://radarr.example.com/_oauth>, etc*), or if you don't like frustration, use a "auth host" URL instead, like "*<https://auth.example.com/_oauth>*" (*see below for details*)
|
||||
|
||||
#### Monkey see, monkey do 🙈
|
||||
|
||||
Here's a [screencast I recorded](https://static.funkypenguin.co.nz/2021/screencast_2021-01-29_22-29-33.gif) of the OIDC credentias setup in Google Developer Console
|
||||
|
||||
!!! tip
|
||||
Store your client ID and secret safely - you'll need them for the next step.
|
||||
|
||||
### Prepare environment
|
||||
|
||||
Create `/var/data/config/traefik-forward-auth/traefik-forward-auth.env` as per the following example:
|
||||
|
||||
```bash
|
||||
PROVIDERS_GOOGLE_CLIENT_ID=<your client id>
|
||||
PROVIDERS_GOOGLE_CLIENT_SECRET=<your client secret>
|
||||
SECRET=<a random string, make it up>
|
||||
# comment out AUTH_HOST if you'd rather use individual redirect_uris (slightly less complicated but more work)
|
||||
AUTH_HOST=auth.example.com
|
||||
COOKIE_DOMAINS=example.com
|
||||
WHITELIST=you@yourdomain.com, me@mydomain.com
|
||||
```
|
||||
|
||||
### Prepare the docker service config
|
||||
|
||||
Create `/var/data/config/traefik-forward-auth/traefik-forward-auth.yml` as per the following example:
|
||||
|
||||
```yaml
|
||||
traefik-forward-auth:
|
||||
image: thomseddon/traefik-forward-auth:2.1.0
|
||||
env_file: /var/data/config/traefik-forward-auth/traefik-forward-auth.env
|
||||
networks:
|
||||
- traefik_public
|
||||
deploy:
|
||||
labels # you only need these if you're using an auth host
|
||||
# traefik
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=traefik_public
|
||||
|
||||
# traefikv1
|
||||
- "traefik.port=4181"
|
||||
- "traefik.frontend.rule=Host:auth.example.com"
|
||||
- "traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181"
|
||||
- "traefik.frontend.auth.forward.trustForwardHeader=true"
|
||||
|
||||
# traefikv2
|
||||
- "traefik.docker.network=traefik_public"
|
||||
- "traefik.http.routers.auth.rule=Host(`auth.example.com`)"
|
||||
- "traefik.http.routers.auth.entrypoints=https"
|
||||
- "traefik.http.routers.auth.tls=true"
|
||||
- "traefik.http.routers.auth.tls.domains[0].main=example.com"
|
||||
- "traefik.http.routers.auth.tls.domains[0].sans=*.example.com"
|
||||
- "traefik.http.routers.auth.tls.certresolver=main"
|
||||
- "traefik.http.routers.auth.service=auth@docker"
|
||||
- "traefik.http.services.auth.loadbalancer.server.port=4181"
|
||||
- "traefik.http.middlewares.forward-auth.forwardauth.address=http://traefik-forward-auth:4181"
|
||||
- "traefik.http.middlewares.forward-auth.forwardauth.trustForwardHeader=true"
|
||||
- "traefik.http.middlewares.forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User"
|
||||
- "traefik.http.routers.auth.middlewares=forward-auth"
|
||||
```
|
||||
|
||||
If you're not confident that forward authentication is working, add a simple "whoami" test container to the above .yml, to help debug traefik forward auth, before attempting to add it to a more complex container.
|
||||
|
||||
```yaml
|
||||
# This simply validates that traefik forward authentication is working
|
||||
whoami:
|
||||
image: containous/whoami
|
||||
networks:
|
||||
- traefik_public
|
||||
deploy:
|
||||
labels:
|
||||
# traefik
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=traefik_public
|
||||
|
||||
# traefikv1
|
||||
- traefik.frontend.rule=Host:whoami.example.com
|
||||
- "traefik.http.services.linx.loadbalancer.server.port=80"
|
||||
- traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
|
||||
- traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User
|
||||
- traefik.frontend.auth.forward.trustForwardHeader=true
|
||||
|
||||
# traefikv2
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=https"
|
||||
- "traefik.http.services.whoami.loadbalancer.server.port=80"
|
||||
- "traefik.http.routers.whoami.middlewares=forward-auth" # this line enforces traefik-forward-auth
|
||||
|
||||
```
|
||||
|
||||
--8<-- "premix-cta.md"
|
||||
|
||||
## Serving
|
||||
|
||||
### Launch
|
||||
|
||||
Deploy traefik-forward-auth with ```docker stack deploy traefik-forward-auth -c /var/data/traefik-forward-auth/traefik-forward-auth.yml```
|
||||
|
||||
### Test
|
||||
|
||||
Browse to <https://whoami.example.com> (*obviously, customized for your domain and having created a DNS record*), and all going according to plan, you should be redirected to a Google login. Once successfully logged in, you'll be directed to the basic whoami page.
|
||||
|
||||
## Summary
|
||||
|
||||
What have we achieved? By adding an additional three simple labels to any service, we can secure any service behind our choice of OAuth provider, with minimal processing / handling overhead.
|
||||
|
||||
!!! summary "Summary"
|
||||
Created:
|
||||
|
||||
* [X] Traefik-forward-auth configured to authenticate against an OIDC provider
|
||||
|
||||
[^1]: Be sure to populate `WHITELIST` in `traefik-forward-auth.env`, else you'll happily be granting **any** authenticated Google account access to your services!
|
||||
|
||||
--8<-- "recipe-footer.md"
|
||||
57
docs/docker-swarm/traefik-forward-auth/index.md
Normal file
57
docs/docker-swarm/traefik-forward-auth/index.md
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: Add SSO to Traefik with Forward Auth
|
||||
description: Traefik Forward Auth protects services running in Docker with an additional layer of authentication, and can be integrated into Keycloak, Google, GitHub, etc using OIDC.
|
||||
---
|
||||
# Traefik Forward Auth
|
||||
|
||||
Now that we have Traefik deployed, automatically exposing SSL access to our Docker Swarm services using LetsEncrypt wildcard certificates, let's pause to consider that we may not *want* some services exposed directly to the internet...
|
||||
|
||||
..Wait, why not? Well, Traefik doesn't provide any form of authentication, it simply secures the **transmission** of the service between Docker Swarm and the end user. If you were to deploy a service with no native security (*[Radarr][radarr] or [Sonarr][sonarr] come to mind*), then anybody would be able to use it! Even services which *may* have a layer of authentication **might** not be safe to expose publically - often open source projects may be maintained by enthusiasts who happily add extra features, but just pay lip service to security, on the basis that "*it's the user's problem to secure it in their own network*".
|
||||
|
||||
Some of the platforms we use on our swarm may have strong, proven security to prevent abuse. Techniques such as rate-limiting (*to defeat brute force attacks*) or even support 2-factor authentication (*tiny-tiny-rss or Wallabag support this)*.
|
||||
|
||||
Other platforms may provide **no authentication** (*Traefik's own web UI for example*), or minimal, un-proven UI authentication which may have been added as an afterthought.
|
||||
|
||||
Still other platforms may hold such sensitive data (*i.e., NextCloud*), that we'll feel more secure by putting an additional authentication layer in front of them.
|
||||
|
||||
This is the role of Traefik Forward Auth.
|
||||
|
||||
## How does it work?
|
||||
|
||||
**Normally**, Traefik proxies web requests directly to individual web apps running in containers. The user talks directly to the webapp, and the webapp is responsible for ensuring appropriate authentication.
|
||||
|
||||
When employing Traefik Forward Auth as "[middleware](https://doc.traefik.io/traefik/middlewares/forwardauth/)", the forward-auth process sits in the middle of this transaction - traefik receives the incoming request, "checks in" with the auth server to determine whether or not further authentication is required. If the user is authenticated, the auth server returns a 200 response code, and Traefik is authorized to forward the request to the backend. If not, traefik passes the auth server response back to the user - this process will usually direct the user to an authentication provider (*[Google][tfa-google], [Keycloak][tfa-keycloak], and [Dex][tfa-dex-static] are common examples*), so that they can perform a login.
|
||||
|
||||
Illustrated below:
|
||||
{ loading=lazy }
|
||||
|
||||
The advantage under this design is additional security. If I'm deploying a web app which I expect only an authenticated user to require access to (*unlike something intended to be accessed publically, like [Linx][linx]*), I'll pass the request through Traefik Forward Auth. The overhead is negligible, and the additional layer of security is well-worth it.
|
||||
|
||||
## AuthHost mode
|
||||
|
||||
Under normal Oauth2 / OIDC auth, you have to tell your auth provider which URLs it may redirect an authenticated user back to, post-authentication. This is a security feture of the OIDC spec, preventing a malicious landing page from capturing your session and using it to impersonate you. When you're securing many URLs though, explicitly listing them can be a PITA.
|
||||
|
||||
[@thomaseddon's traefik-forward-auth](https://github.com/thomseddon/traefik-forward-auth) includes an ingenious mechanism to simulate an "_auth host_" in your OIDC authentication, so that you can protect an unlimited amount of DNS names (_with a common domain suffix_), without having to manually maintain a list.
|
||||
|
||||
### How does it work?
|
||||
|
||||
Say for example, you're protecting **radarr.example.com**. When you first browse to **<https://radarr.example.com>**, Traefik forwards your session to traefik-forward-auth, to be authenticated. Traefik-forward-auth redirects you to your OIDC provider's login, but instructs the OIDC provider to redirect a successfully authenticated session **back** to **<https://auth.example.com/_oauth>**, rather than to **<https://radarr.example.com/_oauth>**.
|
||||
|
||||
When you successfully authenticate against the OIDC provider, you are redirected to the "_redirect_uri_" of <https://auth.example.com>. Again, your request hits Traefik, which forwards the session to traefik-forward-auth, which **knows** that you've just been authenticated (*cookies have a role to play here*). Traefik-forward-auth also knows the URL of your **original** request (*thanks to the X-Forwarded-Host header*). Traefik-forward-auth redirects you to your original destination, and everybody is happy.
|
||||
|
||||
This clever workaround only works under 2 conditions:
|
||||
|
||||
1. Your "auth host" has the same domain name as the hosts you're protecting (*i.e., auth.example.com protecting radarr.example.com*)
|
||||
2. You explictly tell traefik-forward-auth to use a cookie authenticating your **whole** domain (*i.e. example.com*)
|
||||
|
||||
## Authentication Providers
|
||||
|
||||
Traefik Forward Auth needs to authenticate an incoming user against a provider. A provider can be something as simple as a self-hosted [dex][tfa-dex-static] instance with a single static username/password, or as complex as a [Keycloak][keycloak] instance backed by [OpenLDAP][openldap]. Here are some options, in increasing order of complexity...
|
||||
|
||||
* [Authenticate Traefik Forward Auth against a self-hosted Dex instance with static usernames and passwords][tfa-dex-static]
|
||||
* [Authenticate Traefik Forward Auth against a whitelist of Google accounts][tfa-google]
|
||||
* [Authenticate Traefik Forward Auth against a self-hosted Keycloak instance][tfa-keycloak] with an optional [OpenLDAP backend][openldap]
|
||||
|
||||
--8<-- "recipe-footer.md"
|
||||
|
||||
[^1]: Authhost mode is specifically handy for Google authentication, since Google doesn't permit wildcard redirect_uris, like [Keycloak][keycloak] does.
|
||||
104
docs/docker-swarm/traefik-forward-auth/keycloak.md
Normal file
104
docs/docker-swarm/traefik-forward-auth/keycloak.md
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
title: SSO with traefik forward auth with Keycloak
|
||||
description: Traefik forward auth can selectively SSO your Docker services against an authentication backend using OIDC, and Keycloak is a perfect, self-hosted match.
|
||||
---
|
||||
# Traefik Forward Auth with Keycloak for SSO
|
||||
|
||||
While the [Traefik Forward Auth](/docker-swarm/traefik-forward-auth/) recipe demonstrated a quick way to protect a set of explicitly-specified URLs using OIDC credentials from a Google account, this recipe will illustrate how to use your own Keycloak instance to secure **any** URLs within your DNS domain.
|
||||
|
||||
!!! tip "Keycloak with Traefik"
|
||||
Did you land here from a search, looking for information about using Keycloak with Traefik? All this and more is covered in the [Keycloak][keycloak] recipe!
|
||||
|
||||
--8<-- "recipe-tfa-ingredients.md"
|
||||
|
||||
## Preparation
|
||||
|
||||
### Setup environment
|
||||
|
||||
Create `/var/data/config/traefik/traefik-forward-auth.env` as per the following example (_change "master" if you created a different realm_):
|
||||
|
||||
```bash
|
||||
CLIENT_ID=<your keycloak client name>
|
||||
CLIENT_SECRET=<your keycloak client secret>
|
||||
OIDC_ISSUER=https://<your keycloak URL>/auth/realms/master
|
||||
SECRET=<a random string to secure your cookie>
|
||||
AUTH_HOST=<the FQDN to use for your auth host>
|
||||
COOKIE_DOMAIN=<the root FQDN of your domain>
|
||||
```
|
||||
|
||||
### Prepare the docker service config
|
||||
|
||||
This is a small container, you can simply add the following content to the existing `traefik-app.yml` deployed in the previous [Traefik](/docker-swarm/traefik/) recipe:
|
||||
|
||||
```bash
|
||||
traefik-forward-auth:
|
||||
image: funkypenguin/traefik-forward-auth
|
||||
env_file: /var/data/config/traefik/traefik-forward-auth.env
|
||||
networks:
|
||||
- traefik_public
|
||||
deploy:
|
||||
labels:
|
||||
- traefik.port=4181
|
||||
- traefik.frontend.rule=Host:auth.example.com
|
||||
- traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
|
||||
- traefik.frontend.auth.forward.trustForwardHeader=true
|
||||
```
|
||||
|
||||
If you're not confident that forward authentication is working, add a simple "whoami" test container, to help debug traefik forward auth, before attempting to add it to a more complex container.
|
||||
|
||||
```bash
|
||||
# This simply validates that traefik forward authentication is working
|
||||
whoami:
|
||||
image: containous/whoami
|
||||
networks:
|
||||
- traefik_public
|
||||
deploy:
|
||||
labels:
|
||||
- traefik.frontend.rule=Host:whoami.example.com
|
||||
- traefik.port=80
|
||||
- traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
|
||||
- traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User
|
||||
- traefik.frontend.auth.forward.trustForwardHeader=true
|
||||
```
|
||||
|
||||
--8<-- "premix-cta.md"
|
||||
|
||||
## Serving
|
||||
|
||||
### Launch
|
||||
|
||||
Redeploy traefik with `docker stack deploy traefik-app -c /var/data/traefik/traeifk-app.yml`, to launch the traefik-forward-auth container.
|
||||
|
||||
### Test
|
||||
|
||||
Browse to <https://whoami.example.com> (_obviously, customized for your domain and having created a DNS record_), and all going according to plan, you'll be redirected to a Keycloak login. Once successfully logged in, you'll be directed to the basic whoami page.
|
||||
|
||||
### Protect services
|
||||
|
||||
To protect any other service, ensure the service itself is exposed by Traefik (_if you were previously using an oauth_proxy for this, you may have to migrate some labels from the oauth_proxy serivce to the service itself_). Add the following 3 labels:
|
||||
|
||||
```yaml
|
||||
- traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
|
||||
- traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User
|
||||
- traefik.frontend.auth.forward.trustForwardHeader=true
|
||||
```
|
||||
|
||||
And re-deploy your services :)
|
||||
|
||||
## Summary
|
||||
|
||||
What have we achieved? By adding an additional three simple labels to any service, we can secure any service behind our Keycloak OIDC provider, with minimal processing / handling overhead.
|
||||
|
||||
!!! summary "Summary"
|
||||
Created:
|
||||
|
||||
* [X] Traefik-forward-auth configured to authenticate against Keycloak
|
||||
|
||||
[^1]: Keycloak is very powerful. You can add 2FA and all other clever things outside of the scope of this simple recipe ;)
|
||||
|
||||
### Keycloak vs Authelia
|
||||
|
||||
[KeyCloak][keycloak] is the "big daddy" of self-hosted authentication platforms - it has a beautiful GUI, and a very advanced and mature featureset. Like Authelia, KeyCloak can [use an LDAP server](/recipes/keycloak/authenticate-against-openldap/) as a backend, but _unlike_ Authelia, KeyCloak allows for 2-way sync between that LDAP backend, meaning KeyCloak can be used to _create_ and _update_ the LDAP entries (*Authelia's is just a one-way LDAP lookup - you'll need another tool to actually administer your LDAP database*).
|
||||
|
||||
|
||||
--8<-- "recipe-footer.md"
|
||||
Reference in New Issue
Block a user