Using single-sign-on oauth2 across many sites in Kubernetes

You have a set of web resources (a kibana dashboard, a grafana dashboard, a few other misc ones). You are setting them all up with ‘basic’ auth because its simple, and secretly hoping no-one guesses “MyS3cret”. You, my friend, are doing it wrong. Let me explain.

It turns out there is a protocol called ‘oauth2’. You have probably seen this on many sites (e.g. ‘sign in with Google’/’GitHub’ etc). As a consumer, you should always do that when you can. Its much better to have one strong setup (your Google one) than many weak ones. When you ‘sign in with Google’ it doesn’t actually share your password or profile, it just does authentication.

Now, how can we translate that into the misc set of web pages that we run in our system? This is super simple but it wasn’t well documented and took me a bit to figure out how to do it well.

First, lets create a small yaml file, ‘oauth2-values.yaml’. Fill it in like so. You will need to get the clientID and clientSecret. I am using Google (so https://console.cloud.google.com/apis/credentials), but there are other sites like GitHub, GitLab, etc you can use, and ample instructions online for this. In the Google case, allow redirect URI of ‘oauth2.MYDOMAIN/oauth2/callback

config:
  clientID: "xxxxx.apps.googleusercontent.com"
  clientSecret: "yyyyyyy"
  # Create a new cookieSecret with the following command
  # python -c 'import os,base64; print base64.b64encode(os.urandom(16))'
  cookieSecret: "zzzzz=="
  configFile: |-
    pass_basic_auth = false
    pass_access_token = true
    set_authorization_header = true
    pass_authorization_header = true

image:
  repository: "quay.io/pusher/oauth2_proxy"
  tag: "v3.1.0"
  pullPolicy: "IfNotPresent"

extraArgs:
  provider: "google"
  email-domain: "MYDOMAIN"
  cookie-domain: "MYDOMAIN"
  upstream: "file:///dev/null"
  http-address: "0.0.0.0:4180"

ingress:
  enabled: true
  annotations:
    ingress.kubernetes.io/ssl-redirect: 'true'
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    certmanager.k8s.io/cluster-issuer: letsencrypt
    nginx.ingress.kubernetes.io/proxy-body-size: 100m
    path: /
  hosts:
    - oauth2.MYDOMAIN
    - oauth2.MYDOMAIN
  tls:
    - secretName: oauth2-noc-tls
      hosts:
        - oauth2.MYDOMAIN
        - oauth2.MYDOMAIN

Now we are going to install an ‘oauth2 proxy’. We will run *1* for our entire domain, and it will allow anyone with our domain to access.

helm install -f oauth2-values.yaml --name oauth2 --namespace oauth2 stable/oauth2-proxy

OK, now we just need to add 2 annotation lines to every ingress:

 nginx.ingress.kubernetes.io/auth-signin: https://oauth2.MYDOMAIN/oauth2/start?rd=$http_host$request_uri
 nginx.ingress.kubernetes.io/auth-url: https://oauth2.MYDOMAIN/oauth2/auth

And boom we are done. I’m assuming you are already using the excellent cert-manager so your site is TLS protected. Now you have strong sign-on, and, more usefuly, single-sign-on.

The key is that ‘cookie-domain’ above. It means we are using a single oauth2-proxy protecting the entire domain, and, once one site is signed in, all sites are signed in. So great!

Even better, if you use Multi-Factor-Authenticaation it fits in with it. Rarely type a password again, prevent needing passwords for new sites, and be more secure. What’s not to love!


Posted

in

by

Tags:

Comments

2 Responses to “Using single-sign-on oauth2 across many sites in Kubernetes”

  1. Dom

    Hi Don,

    This is cool. I am wondering if you had to do anything special for Grafana? I am finding that the users/access/oauth is annoying to configure and I can’t work out the best way to do it. I login via Oauth2-Proxy and I get “Invalid username or password”.

    Any tips?

    Cheers,
    Dom

    1. db

      we switched to using a technique w/ istio.
      https://www.agilicus.com/using-istio-openid-connect-oauth2-to-authorise/

      but i suspect that doesn’t make a lot of difference on your question.

      for grafana, i am logged straight in. The grafana.ini ends up being set as below, see the auth section.

      “`
      grafana.ini: |
      [analytics]
      check_for_updates = false
      eporting_enabled = false
      [auth.anonymous]
      enabled = true
      org_role = Admin

      “`

      ultimately what this means is, if my admin-only-oauth2-proxy accepts the user, they are the admin in grafana.for us this is sufficient.

Leave a Reply

Your email address will not be published. Required fields are marked *