How To Setup GitHub Authentication for an Exposed Service in Kubernetes

Recently, I was tasked with setting up a web application on a Kubernetes cluster. Being a monitoring app, it needed authentication to remain secure. Unfortunately, the app code did not provide an authentication mechanism. But, all hope was not lost. 

Enter OAuth 2 Proxy! 

Simply put, OAuth 2 Proxy allows third-party applications to grant limited access to an HTTP service. 

You could use a number of OAuth 2 Proxy providers with this but for simplicity sake I’m going to focus on Github Auth. Our team uses GitHub for most things, so it made sense to use Github and control access with teams for our Github org.

Some nice folks have packaged up the OAuth 2 Proxy application as a helm chart so it is easily deployable. Familiarize yourself with the chart before we move on. 

The Goal

The goal is to configure our exposed service in Kubernetes to use the OAuth 2 Proxy server. Then the proxy server will contact GitHub via its OAuth 2 Proxy credentials, check that the user exists, is in the right GitHub groups, and then either allow or deny access to the service. 

The Requirements

In order to follow this tutorial you will need to have the following:

Now that we know the goal and requirements, let’s get to it.

Step 1: Creating the GitHub Token

Create a GitHub OAuth 2 Proxy token either via your org’s GitHub setting page or your personal page.

Step 2: Enter the URL

Enter your service a SSL URL as well as a “callback URL” at  the /oauth2 path. For example: https://yourapp.example.com then https://yourapp.example.com/oauth2

creating a github token

Step 3: Review Helm Chart Values

Review the OAuth 2 Proxy Helm chart values before installing. Here is an example set of values that should get you up and running pretty quickly:

 values:
   config:
     existingSecret: myservice-oauth2-secret
   extraArgs:
     provider: "github"
     github-org: "your_org"
     github-team: "your_team"
   ingress: 
     enabled: true
     path: /oauth2
     hosts:
       - myservice.mydomain.com
     annotations: 
       kubernetes.io/ingress.class: nginx
       certmanager.k8s.io/cluster-issuer: letsencrypt-production
     tls:
     - secretName: myservice-tls
       hosts:
         - myservice.mydomain.com

It might be a little bit confusing that you are giving the OAuth 2 Proxy a similar ingress configuration as your service as it has the same domain name, but you will notice it is only for the /oauth path. So only traffic to that path will be sent to the proxy (and then on to Github… for VICTORY!)

Step 4: Kubernetes Secret Configuration

Security: You could provide the GitHub OAuth 2 Proxy secrets directly in the Helm chart, but then your secrets are in Helm, which I personally wanted to avoid. We use Weaveworks Flux to keep our systems in sync, so we can commit our Helm values to GitHub. For this reason, I used the existing secret configuration flag and we will add our Github secrets to Kubernetes directly. 

Let’s go ahead and do that.

apiVersion: v1
data:
 client-id:<base-64 encoded client ID>
 client-secret: <base-64 encoded client secret>
 cookie-secret: <base-64 encoded cookie secret>
kind: Secret
metadata:
 name: myservice-oauth2-secret
 namespace: mynamespace
type: Opaque

You can create the cookie secret with this little docker invocation:

docker run -ti --rm python:3-alpine \

    python -c 'import secrets,base64;

print(base64.b64encode(base64.b64encode(secrets.token_bytes(16))));'

(As an aside, I use this little VSCode extension to base64 encode/decode within my editor. It makes dealing with Kubernetes secrets a little easier.)

Step 5: Install the Helm Chart

Save and apply that manifest with kubectl then install the helm chart to the same namespace as your application with your configured helm values.yaml. It should pick up that secret you created manually and show as running.

Step 6: Modifying the Ingress 

That’s all for the configuration of the OAuth 2 Proxy. Now, we just have to tell your service’s ingress to use it. We do this by modifying its ingress with some nginx annotations to shuttle traffic over to the proxy. 

Edit your service however you like to include these lines as annotations just as they are:

nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"

nginx.ingress.kubernetes.io/auth-signin:"https://$host/oauth2/start?rd=$escaped_request_uri"

This tells nginx to use that URL to authenticate before allowing a user in. You can read more about it here if you like, but the basics are “if the subrequest returns a 2xx response code, the access is allowed, if it returns 401 or 403, the access is denied”. Since the proxy is grabbing all requests behind “myservice.mydomain/oauth2”, this will invoke the proxy. 

Conclusion

That’s it! You can now attempt to visit your service URL and you should be presented with the option to authorize the app with GitHub. This will only happen once. After that, you can assume you have access to the GitHub team you configured.

Did it work for you? Let us know on Twitter!

From 0 to K8s in Hours, Not Months

Don’t waste time and resources on DevOps. Our team of Certified Kubernetes Admins manage and maintain Kubernetes clusters using AWS to host applications for ourselves and our partners.

Check out Revelry Managed Cloud.

More Posts by Chris Tortorich: