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 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.
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:
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;
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
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:
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.
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!