I stumbled upon a really cool project: Traefik Forward Auth that provides Google OAuth based Login and Authentication for Traefik.

This means that you can secure your Traefik backend services by using Google for authentication to access your backends. Authorizing who can logon, get's managed on the forward proxy.

If you have not worked with Traefik, Traefik is one amazing dynamic and modern reverse proxy / load balancer built for micro services.

ruanbekker-cheatsheets

What are we doing today

In this demonstration we will setup a new google application, setup the forward-auth proxy and spin up a service that we will use google to authenticate against to access our application on Docker Swarm.

Pre-Requirements

Docker Swarm: We will be running this demonstration on Docker Swarm, you can follow this guide if you don't have a swarm provisioned yet.

DNS Setup: auth.domain.com, traefik.domain.com and whoami-debug.domain.com has an A record that is pointing to the public ip address of your docker swarm manager node.

Google Project

We will create a new google project, head over to https://console.developers.google.com and search for "credentials api", you should see the "IAM Service Account Credentials API", go ahead and select it:

image

You should now see the following:

image

Once you enable the API, create a New Project by selecting it on the right hand corner:

image

Go ahead and provide a descriptive name, in my case I called my project "my-traefik-oauth-proxy", once you provided a name, select "Create":

image

From the "OAuth consent screen", read through the sections, and provide the following:

  • application name
  • authorized domains (eg. example.com)

Then hit save:

image

From the "Credentials" section, select create credentials, and from the drop down select "OAuth client id":

image

We will be creating a "Web application", provide the "Name" of the application identifier and provide the "Authorized redirect URI's".

For example, if we want to protect your application: "https://mydemo.example.com", we will set the authorized redirect uri to "http://auth.example.com/_auth" as an example:

image

After you create the OAuth client, you will receive your client id and client secret, which we will need to provide to our traefik-forward-proxy service: (be sure to keep these credentials in a safe place)

image

Traefik

In this example I will use the domain example.com.

Let's start writing our docker-compose.yml, which will consist of our traefik reverse proxy service and our traefik-forward-auth service.

I will explain the values that we require below the yaml:

version: '3.7'
services:
  traefik:
    image: traefik:1.7.14
    ports:
      - target: 80
        published: 80
        mode: host
      - target: 443
        published: 443
        mode: host
    command: >
      --acme
      --acme.storage=/certs/acme.json
      --acme.entryPoint=https
      --acme.httpChallenge.entryPoint=http
      --acme.onHostRule=true
      --acme.onDemand=false
      --acme.acmelogging=true
      --acme.email=${EMAIL:-root@localhost}
      --docker
      --docker.swarmMode
      --docker.domain=${DOMAIN:-localhost}
      --docker.watch
      --defaultentrypoints=http,https
      --entrypoints='Name:http Address::80'
      --entrypoints='Name:https Address::443 TLS'
      --logLevel=INFO
      --accessLog
      --metrics
      --metrics.prometheus
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - traefik_certs:/certs
    networks:
      - public
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
      labels:
        - "traefik.docker.network=public"
        - "traefik.port=8080"
        - "traefik.backend=traefik"
        - "traefik.enable=true"
        - "traefik.frontend.rule=Host:traefik.${DOMAIN:-localhost}"
        - "traefik.frontend.headers.SSLRedirect=true"
        - "traefik.frontend.entryPoints=http,https"

  traefik-forward-auth:
    image: thomseddon/traefik-forward-auth
    environment:
      - CLIENT_ID=your-client-id
      - CLIENT_SECRET=your-client-secret
      - OIDC_ISSUER=https://accounts.google.com
      - SECRET=a-very-random-generated-key
      - AUTH_HOST=auth.example.com
      - COOKIE_DOMAINS=example.com
      - [email protected]
    networks:
      - public
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
           - node.role==manager
      resources:
        limits:
          memory: 128M
      labels:
        - traefik.frontend.rule=Host:auth.${DOMAIN:-localhost}
        - traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
        - traefik.frontend.auth.forward.trustForwardHeader=true
        - traefik.enable=true
        - traefik.port=4181
        - traefik.tags=public
        - traefik.backend=traefik-forward-auth
        - traefik.docker.network=public
        - traefik.redirectorservice.frontend.entryPoints=http
        - traefik.redirectorservice.frontend.redirect.entryPoint=https
        - traefik.webservice.frontend.entryPoints=https

networks:
  public:
    driver: overlay
    name: public

volumes:
  traefik_certs: {}

For our Traefik service we require a valid EMAIL environment variable, which will be used for creating the certificate, and a DOMAIN which will by default map your traefik service to traefik.example.com if example.com was your domain.

Let's go ahead and set that as your environment variables:

$ export [email protected]
$ export DOMAIN=example.com

For our Traefik Forward-Auth service, we require the CLIENT_ID and CLIENT_SECRET which we got from Google, the SECRET will be a random secret key, which you can generate with openssl rand -hex 16, the AUTH_HOST being auth.example.com if your domain is example.com, COOKIE_DOMAINS will be your domain and WHITELIST will be the email addresses that you would like to authorize.

In summary, these are the environment that we would want to set in our compose:

...
   environment:
      - CLIENT_ID=your-client-id
      - CLIENT_SECRET=your-client-secret
      - OIDC_ISSUER=https://accounts.google.com
      - SECRET=a-very-random-generated-key
      - AUTH_HOST=auth.example.com
      - COOKIE_DOMAINS=example.com
      - [email protected]
...

Once we have everything in place we can deploy our stack:

$ docker stack deploy -c docker-compose.yml proxy
Creating network public
Creating service proxy_traefik-forward-auth
Creating service proxy_traefik

Integrating Google Auth with a Web Service

Now that we have our Traefik proxy and OAuth forwarder running, we would like to protect a web service by integrating google sign-in onto our application.

Since we have authorized one gmail address as a whitelist, upon successful login via gmail from the mentioned address, we will be directed to our web service.

To protect your web application with google oauth, we simple just add 3 lines to our deploy labels of the service that we want authentication enabled on:

        - traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
        - traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User
        - traefik.frontend.auth.forward.trustForwardHeader=true

A full compose that we will populate to docker-compose.app.yml :

version: '3.7'

services:
  whoami:
    image: containous/whoami
    networks:
      - public
    deploy:
      labels:
        - traefik.frontend.rule=Host:whoami-debug.${DOMAIN}
        - traefik.port=80
        - traefik.tags=public
        - traefik.backend=whoami
        - traefik-docker.network=public
        - traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
        - traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User
        - traefik.frontend.auth.forward.trustForwardHeader=true
        - traefik.redirectorservice.frontend.entryPoints=http
        - traefik.redirectorservice.frontend.redirect.entryPoint=https
        - traefik.webservice.frontend.entryPoints=https

networks:
  public:
    external: true

Deploy our web app:

$ docker stack deploy -c docker-compose.app.yml web
Creating service web_whoami

When accessing https://whoami-debug.domain.com we will be redirected to https://accounts.google.com as you can see:

image

Upon successful login, you will be redirected to auth.domain.com then directed to your web application:

image

Thank You

And there you have it, simple and easy authentication & authorization to your traefik backends using the oauth protocol.

Please have a look at thomseddon/traefik-forward-auth and make sure to star the project if you find it useful.

References: