Home Deploying Docker Container with OAuth2 Reverse Proxy (SSO)
Post
Cancel

Deploying Docker Container with OAuth2 Reverse Proxy (SSO)

Problem Statement

Sometimes you find yourself in a position where you want to deploy something, but not (yet?) for the whole world to see. Think of an internal blog or a few tools that you built as a handy webapp for your coworkers to use. In such scenario you maybe also don’t want to use antiquated things like basic auth that requires your target audience (your coworkers in this case) to memorize even more passwords. What we really want is a single sign-on solution (SSO).

Solution

A simple solution for that problem is to make use of an OAuth2 provider. In our case, we all use Office365 in our company and therefore all have credentials for the Azure AD (Active Directory) server which also provides OAuth2 compatible endpoints for the authcode grant flow that we can use. Thanks to the open source community an off-the-shelf solution in form of OAuth2-Proxy is readily available and can be simply configured to fit our needs.

The Setup

This is what we have on our server where we want to deploy a new webapp that has limited access:

  • Docker with docker compose plugin installed
  • A Traefik reverse proxy that handles the routing of URL to webapp (running in a Docker container)

Implementation

Step 1: Set up the application on Azure

Register a new App

Simply click on App Registrations

App Registrations

then click on New Registration and add a new app

New Registration

Specify a name, in our case we want to provide a Toolbox for our coworkers, but you are free to essentially name it anything you like

Register an application

Make sure to select Accounts in this organizational directory only, as we don’t want people from other companies to be able to use our toolbox. Also add the Redirect URI, in our case the page is located at https://toolbox.mobiuscode.de, so we provide the URI https://toolbox.mobiuscode.de/oauth2/callback here. This is the standard path used by our OAuth2 reverse proxy, so if your URI is something like https://mygreatsite.com then the callback URI would be https://mygreatsite.com/oauth2/callback.

Add a client secret

For our reverse proxy to be able to authenticate itself against the Azure AD OAuth2 provider, it needs to have a valid client secret. To obtain that we have to create a new one by clicking on Certificates & secrets.

Certificates & secrets

Here we click on New client secret and specify when the secret is supposed to expire. After we are done a new row appears like this one:

New client secret

Make sure to copy the Value (which is in fact your client secret) as you can only copy the value now.

Add API permissions

Next we need to allow our OAuth2 client to get read access. This is done by clicking on API permissions

API permissions

and adding the Group.Read.All permission. First click on Add a permission and then add a Microsoft Graph type permission. Now search for group and select Group.Read.All.

Add a permission

To add the selected permission click on Add permission. Finally don’t forget to also grant admin consent for your employees by clicking on Grant admin consent for {your organization}, so that they are able to log in and use your webapp.

Grant admin consent

Update manifest

As a final step we need to adjust the application manifest slightly and set accessTokenAcceptedVersion from null to 2

Modify manifest

Step 2: Create a docker compose file

Finally we create a docker compose file that specifies the following containers:

  1. the OAuth2-Proxy that calls the Azure AD OAuth2 endpoint to log you in & check your identity
  2. the backend application that you want to run (as an example here we’re using Homer which is a simple webpage with links to other services)

This is an example docker-compose.yml file that assumes that you have a Traefik running:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
version: '3.5'
services:

  oauth2:
    image: bitnami/oauth2-proxy
    command: oauth2-proxy
    networks:
      - internal
      - web
    environment:
      - OAUTH2_PROXY_COOKIE_SECRET=<your-cookie-secret>
      - OAUTH2_PROXY_HTTP_ADDRESS=http://0.0.0.0:4180
      - OAUTH2_PROXY_UPSTREAMS=http://homer:8080
      - OAUTH2_PROXY_COOKIE_NAME=_oauth2_proxy
      - OAUTH2_PROXY_COOKIE_EXPIRE=48h
      - OAUTH2_PROXY_COOKIE_REFRESH=24h
      - OAUTH2_PROXY_COOKIE_SECURE=true
      - OAUTH2_PROXY_COOKIE_HTTPONLY=true
      - OAUTH2_PROXY_REVERSE_PROXY=true
      - OAUTH2_PROXY_PROVIDER=azure
      - OAUTH2_PROXY_AZURE_TENANT=<your-azure-tenant-id>
      - OAUTH2_PROXY_CLIENT_ID=<your-azure-client-id>
      - OAUTH2_PROXY_CLIENT_SECRET=<your-azure-client-secret>
      - OAUTH2_PROXY_OIDC_ISSUER_URL=https://login.microsoftonline.com/<your-azure-tenant-id>/v2.0
      - OAUTH2_PROXY_EMAIL_DOMAINS=mobiuscode.de
    labels: # traefik configuration via labels
      - traefik.enable=true
      - traefik.http.routers.homer.rule=Host(`toolbox.mobiuscode.de`)
      - traefik.http.routers.homer.tls.certResolver=default
      - traefik.http.routers.homer.tls=true
      - traefik.http.services.homer.loadbalancer.server.port=4180
    restart: unless-stopped

  homer:
    image: b4bz/homer:latest
    volumes:
      - ./assets/:/www/assets
    networks:
      - internal
    restart: unless-stopped

networks:
  internal:
  web: # this is the network that we share with Traefik
    name: traefik_web
    external: true

Placeholders are marked in <...> and should be filled using these values:

Variable Description
your-cookie-secret A random value that can be generated using one of the methods
described here
your-azure-client-secret The value that we got when we created a client secret in step #1:
client secret
your-azure-tenant-id This can be obtained from the application overview:
tenant id
your-azure-client-id This can also be obtained from the application overview:
client id

As for the Traefik labels, check the official Traefik documentation

Once everything is configured properly you should be able to start the two containers by issuing docker compose up. After everything started up you should see a login page like this here and you should be able to login with your office credentials:

login page

🎉 Congratulations you have now a SSO solution for your company’s internal service!

This post is licensed under CC BY-NC-SA by the author.