# Traefik Simple-Auth
Traefik (opens new window) has become a popular choice for load-balancing docker applications.
WARNING
This is an example config, and doesn't have SSL enabled by default. Traefik supports SSL (opens new window). Make sure to enable it so that username and password are encrypted in transit!
In both cases, we use a same-domain cookie sharing technique, described here
# Forward Auth
This strategy is similar to nginx auth_request, where traefik will forward the request
to simple-auth's vouch
endpoint to see if a user has a session (in this case, stored in a cookie). Unlike
nginx's auth_request
, the user should be forwarded to simple-auth by the vouch
endpoint if there is no valid session.
This can also be used via traefik to forward a header, eg the user id, to the downstream service.
# docker-compose
version: '3.3'
services:
# Traefik listening on port 88 (in case 80 conflicts with something...)
traefik:
image: traefik:v2.3
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:88"
ports:
- "88:88"
- "8090:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
# Simpleauth
simpleauth:
image: zix99/simple-auth:latest
environment:
SA_WEB_LOGIN_COOKIE_JWT_SIGNINGKEY: a-unqiue-signing-key # CHANGE ME!!
SA_VERBOSE: 'true'
SA_WEB_LOGIN_SETTINGS_ROUTEONLOGIN: "http://${DOMAIN}:88"
# Allow login to send user back to any subdomain
SA_WEB_LOGIN_SETTINGS_ALLOWEDCONTINUEURLS: 'https?://.*${DOMAIN}(:\d+)?/.*'
SA_WEB_LOGIN_COOKIE_DOMAIN: ${DOMAIN} # IMPORTANT: Higher-level domain
SA_WEB_BASEURL: http://auth.${DOMAIN}:88
SA_AUTHENTICATORS_VOUCH_ENABLED: 'true'
# The vouch endpoint will put the user's UUID on this header to be forwarded
SA_AUTHENTICATORS_VOUCH_USERHEADER: 'X-User-Id'
volumes:
- sadb:/var/lib/simple-auth
labels:
- "traefik.enable=true"
- "traefik.http.routers.simpleauth.rule=Host(`auth.${DOMAIN}`)" # Fill in with your own domain
- "traefik.http.routers.simpleauth.entrypoints=web"
# Set up middleware, needs to be the internal URL of the service so that the continue URL is created correctly
# Will be used by other services
- "traefik.http.middlewares.simple-auth.forwardauth.address=http://simpleauth/api/v1/auth/vouch?forward=1"
- "traefik.http.middlewares.simple-auth.forwardauth.authResponseHeaders=X-User-Id" # Forward this header to the end service
# testapp is a small nodejs app that will verify your token and only let you in if you have a valid token
testapp:
image: nginx:latest
labels:
- "traefik.enable=true"
# App settings
- "traefik.http.routers.testapp.rule=Host(`${DOMAIN}`)" # Fill in with your own domain
- "traefik.http.routers.testapp.entrypoints=web"
# Attach to the simple-auth middleware defined in simple-auth
- "traefik.http.routers.testapp.middlewares=simple-auth"
volumes:
sadb: {}
# Same-Domain Cookie in App
This strategy uses same-domain cookie auth to authenticate the user inside the app, with no special load-balancer setup.
Here, we're using traefik to have both simple-auth and a testapp (validates the token in the cookie). The test-app will forward to auth.${DOMAIN}
if it doesn't detect an auth
token.
# docker-compose
version: '3.3'
services:
# Traefik listening on port 88 (in case 80 conflicts with something...)
traefik:
image: traefik:v2.3
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:88"
ports:
- "88:88"
- "8090:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
# Simpleauth
simpleauth:
image: zix99/simple-auth:latest
environment:
SA_WEB_LOGIN_COOKIE_JWT_SIGNINGKEY: a-unqiue-signing-key # CHANGE ME!!
SA_VERBOSE: 'true'
SA_WEB_LOGIN_SETTINGS_ROUTEONLOGIN: "http://${DOMAIN}:88"
SA_WEB_LOGIN_COOKIE_DOMAIN: ${DOMAIN} # IMPORTANT: Higher-level domain
volumes:
- sadb:/var/lib/simple-auth
labels:
- "traefik.enable=true"
- "traefik.http.routers.simpleauth.rule=Host(`auth.${DOMAIN}`)" # Fill in with your own domain
- "traefik.http.routers.simpleauth.entrypoints=web"
# testapp is a small nodejs app that will verify your token and only let you in if you have a valid token
testapp:
build: ./testapp
environment:
AUTHURL: "http://auth.${DOMAIN}:88"
JWTKEY: a-unqiue-signing-key # This should match the signing key for simpleauth
labels:
- "traefik.enable=true"
- "traefik.http.routers.testapp.rule=Host(`${DOMAIN}`)" # Fill in with your own domain
- "traefik.http.routers.testapp.entrypoints=web"
volumes:
sadb: {}
# Test App
TIP
You can find more information about the testapp here
This is a very simple nodejs app that will validate your auth
cookie, or redirect
you to the authentication portal if it fails.
You can see the full app at our repository
#!/usr/bin/env node
const express = require('express');
const cookieParser = require('cookie-parser');
const jwt = require('jsonwebtoken');
const PORT = process.env.PORT || 8080;
const AUTHURL = process.env.AUTHURL;
const JWTKEY = process.env.JWTKEY;
const app = express();
app.use(cookieParser());
// Simplistic auth middleware
app.use((req, res, next) => {
const authCookie = req.cookies.auth;
if (!authCookie) {
// You could redirect here..
return res.redirect(AUTHURL);
}
return jwt.verify(authCookie, JWTKEY, (err, decoded) => {
if (err) {
return res.status(401).send('Invalid token');
}
req.auth = decoded;
return next();
});
});
// Only can get if passes auth middleware
app.get('/', (req, res) => {
res.send(`Hello!<br>
Your auth cookie is: ${req.cookies.auth}<br>
Your token decodes to: ${JSON.stringify(req.auth)}<br>
<br>
<a href="${AUTHURL}/#/manage">Click here to manage your account</a>`);
});
app.listen(PORT, () => {
console.log(`Listening on http://0.0.0.0:${PORT}`);
});