Traefik and oAuth: Log in your own web services with Google.
The security of a web service is largely dependent on its user login. If a web service does not have its own user logon, a logon can simply be activated upstream when using the Traefik reverse proxy. The access to the actual web service is only allowed if the login to the reverse proxy was successful. The simplest variant for an upstream login is a basic authentication. Somewhat more complex, but possibly more convenient and also usually even more secure is the use of OAuth. OAuth allows logging in via an additional logon provider: Identity Provider, or IDP for short. Once logged in to the IDP, all services that use the IDP can be called. As an example, if you use Google's IDP for OAuth sign-in, you can also use the credentials for your own web services after signing in once with your Google account.
Logging in to your own web services with your Google account
The goal of this post is to pre-enable a Google login for your own web services: As an example, if the Traefik dashboard of our Docker setup is called, the reverse proxy redirects the user directly to the Google login. If the user is already logged in, the credentials can be used and access to the dashboard is allowed without the need to log in again. If the user is not yet logged in to Google, they will be prompted to enter their credentials:
Supplementary to the Traefik Docker setup, for the setup presented here, an additional Docker container (traefik-forward-auth) is used for forwarding the authentication to Google and a public DNS entry for the redirect URL (redirect URI). On the part of Google, the Google Developers portal also requires an oAuth client must be created on the Google Developers portal.
Pre-empting Google login to a Docker web service can be done later with a label to the respective container:
labels:
- "traefik.http.routers.traefik.middlewares=forward-auth-verify"
Overlay Mode vs. Auth Host Mode
In overlay mode, the /_oauth path is redirected for the domains used. When using multiple services, each domain has its own redirect URI, which means that multiple domains must be stored in the Google OAuth client. (https://service1.domain.tld/_oauth, https://servic2.domain.tld/_oauth). Alternatively, "Auth Host Mode" and a domain of one's own can be used, e.g. oauth.domain.tld. In "Auth Host Mode", it is sufficient to use this domain as the redirect URI in the Google OAuth client for several services:
Auth Host Mode: Public-DNS for the container traefik-forward-auth.
The container for OAuth needs its own DNS record in "Auth Host Mode", according to the following example: oauth.domain.tld. The DNS record points to the public IP of the web server, as in my other Docker web services, see: Domain and its management.
Prerequisite: Google OAuth client
Before creating an OAuth client, we first need to configure a new project and the consent screen in the Google Developer console, for this we log in to the Google Developer page: https://console.developers.google.com/
Consent Screen: Consent Screen
After logging in, a project must be created in advance:
Before the OAuth client can be confugured, the configuration of the "Consent Screen" is needed.
As "Authorised Domain" I have stored the domain through which the web services are made available on the Internet:
Create OAuth Client:
The creation of the OAuth client starts with "OAuth client ID":
As mentioned before, when using "Auth Host Mode" for all subdomains, the additional DNS record can be used for the OAuth login. The default path for the Docker container: thomseddon/traefik-forward-auth is "_oauth" (variable: - URL_PATH=_oauth).
After creating the oAuth client, the client ID and client secret are output:
Implementation: traefik customization
The actual OAuth login does not take place in Traefik, but in an additional container. Building on the article "secure https connection: Traefik reverse proxy + Let's Encrypt", I added the Docker container thomseddon/traefik-forward-auth in the following docker-compose-yml file and customized the configuration for its use.
File docker-compose.yml
services:
traefik:
image: "traefik:v2.8"
container_name: "traefik"
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=admin@domain.tld"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
expose:
# traefik dashboard port
- 8080
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`webproxy.domain.tld`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=myresolver"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=forward-auth-verify"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
restart: "always"
traefik-forward-auth:
image: thomseddon/traefik-forward-auth:latest
container_name: traefik-forward-auth
environment:
- PROVIDERS_GOOGLE_CLIENT_ID=??FromGoogleOAuthSetup??
- PROVIDERS_GOOGLE_CLIENT_SECRET=??FromGoogleOAuthSetup??
- SECRET=somethingrandom
- AUTH_HOST=oauth.domain.tld
- COOKIE_DOMAIN=domain.tld
- WHITELIST=EMAIL@ALLOWED
- INSECURE_COOKIE=false
labels:
- "traefik.enable=true"
- "traefik.http.routers.forward.rule=Host(`oauth.domain.tld`)"
- "traefik.http.routers.forward.entrypoints=websecure"
- "traefik.http.routers.forward.tls.certresolver=myresolver"
- "traefik.http.services.forward.loadbalancer.server.port=4181"
#Middleware
- "traefik.http.middlewares.forward-auth-verify.forwardauth.address=http://traefik-forward-auth:4181"
- "traefik.http.middlewares.forward-auth-verify.forwardauth.authResponseHeaders=X-Forwarded-User"
networks:
default:
name: webproxy
external: true
To forward the login for the Traefik dashboard from Basic-Auth to another login provider, just change the label "traefik.http.routers.traefik.middlewares" to "forward-auth-verify". (The original example uses the label: "traefik-basic-auth" for basic authentication).
The middleware for "forward-auth-verify" is defined in the container: traefik-forward-auth in the example. (Comment "#middleware" in the docker-compose.yml file).
The label of the container "traefik-forward-auth" uses the DNS entry, here "oauth-domain.tld". In addition, the domain is stored in the environment variable "AUTH-HOST", which eliminates the need to adjust the Google-oAuth client later when adding a container. AUTH-HOST handles the login for all subdomains where a Google login should be used (e.g.: webproxy.domain.tld, webservice1.domain.tld, webservice2.domain.tld). For the redirection to work for all subdomains, the variable "COOKIE_DOMAIN" must be filled with the domain zone, here domain.tld.
The variable "SECRET" should be filled with a random value, this can be generated for example on Linux with the command "openssl rand -hex 16".
The allowed Google accounts can be stored in the environment variable "WHITELIST". To allow multiple email addresses, they can be separated with a ",": WHITELIST=adresse1@gmail.com,adresse2@gmail.com.
Conclusion
The use of an external login provider, such as Google, offers a convenient way to provide your own web services with a secure login. If you are already logged in to Google in the browser, you can use your own web services easily and securely without an additional login.
{{percentage}} % positive