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:
- Helm
- A GitHub account
- Nginx ingress controller
- Certmanager with LetsEncrypt for SSL
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
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 how it works 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.
We're building an AI-powered Product Operations Cloud, leveraging AI in almost every aspect of the software delivery lifecycle. Want to test drive it with us? Join the ProdOps party at ProdOps.ai.