Skip to content


Repository files navigation


NPM version Build Status Coverage Status

Securely expose your private Kubernetes services.


This project is very beta. We're using it in production, but this is undergoing active development, and may change quite a bit without warning.


kube-auth-proxy is a Kubernetes-aware authorizing reverse proxy, designed as a replacement for oauth2_proxy.

You may have a number of "internal" services, such as Prometheus, Grafana, Kibana, the Kubernetes dashboard, or others, which you'd like to make available on the public internet, but which you'd like to control who can access. kube-auth-proxy makes this quite painless.

The basic idea is:

  • Install kube-auth-proxy. Configure it with an authentication provider and some default authorization rules.
  • Set up an ingress controller which forwards one or more subdomains to kube-auth-proxy (e.g. "*").
  • For each service you want to expose, either add some annotations to that service or create a ProxyTarget custom resource for the service which desicribes what domain it should be available on (e.g. ""), and optionally specify some extra authorization criteria for this service.


You can do all of this with oauth2_proxy, but the setup is quite complicated, and most of the tutorials involved assume you are using nginx for your ingress and rely on some features built into nginx to manage authentication. If you're using traefik or an AWS ALB ingress, none of these will work for you (unless you do something like set up an ALB ingress that forwards traffic to a nginx ingress).

You can do all of this with Pomerium, but unless you wrote some sort of Kubernetes Operator for Pomerium, you'd have to manage a bunch of configuration files and tell Pomerium where to find things.

kube-auth-proxy was built from the ground up to specifically target Kubernetes. It's much easier to set up and use.


Let's suppose we have an internal service in our cluster, say prometheus, and we want to expose it at

Pick a Domain Name

We're going to expose all your internal services under a single domain name. For example, if you pick "internal.MY-DOMAIN.COM", then when you expose the Kubernetes dashboard you might put it under "dashboard.internal.MY-DOMAIN.COM".

GitHub wants a single domain name to use for OAuth callbacks (we'll use auth.internal.MY-DOMAIN.COM in this example), which means when we set a cookie, we're going to set it for some parent of that domain, which in turn means we're going to put all our other services under that same domain.

Create a Github Oauth App

Go to your GitHub organization, click on "Settings" then pick "OAuth Apps" on the left. Click the "New OAuth App" button in the upper right corner. In the "Authorization callback URL", put http://auth.internal.MY-DOMAIN.COM/kube-auth-proxy/github/callback. Fill in the rest of these fields however you like. When you create your app, take note of the client ID and client secret; you'll need these in the next step.

Installation and Configuration

Start with examples/kube-auth-proxy-github.yaml. Download this file, and update (at a minimum) internal.MY-DOMAIN.COM, CLIENT-ID-HERE, CLIENT-SECRET-HERE, and MY-ORG-HERE. Apply this with:

$ kubectl apply -f `./kube-auth-proxy-github.yaml`.

Define an Ingress

We need to create an ingress which forwards "*.internal.MY-DOMAN.COM" to our new service. Unlike with oauth2-proxy or other services, kube-auth-proxy doesn't rely on features built into nginx-ingress, and should work with any ingress, include the ALB ingress or with Traefik. For example, on AWS an ALB ingress could be as simple as:

apiVersion: extensions/v1beta1
kind: Ingress
  name: kube-auth-proxy-ingress
  namespace: kube-system
  annotations: alb '[{"HTTPS":443}]' internet-facing
    - host: '*.internal.MY-DOMAIN.COM'
          - path: /*
              serviceName: kube-auth-proxy
              servicePort: http

This will create an ALB listening for https traffic on 443, and will forward all traffic to kube-auth-proxy. We need to set up DNS and certificates, but again, this is dependent on your specific setup. On AWS if you're using external-dns, it will configure your A-Records for you in Route 53.

Annotate our Internal Service

We'll add some annotations to our service so kube-auth-proxy will find it and route to it:

apiVersion: v1
kind: Service
  name: prometheus
    app: prometheus
    # Expose this as prometheus.internal.MY-DOMAIN.COM
    kube-auth-proxy/host: prometheus
    # Forward traffic to Prometheus service's "web" port.
    kube-auth-proxy/targetPort: web
    # Only allow github users in the "devOps" team in the "MY-ORG-HERE"
    # organization to access this service.
    kube-auth-proxy/githubAllowedTeams: devOps@MY-ORG-HERE
  type: ClusterIP
    - name: web
      port: 9090
      protocol: TCP
      targetPort: 9090
    app: prometheus

That's all you need to do! As soon as you create/update this service, kube-auth-proxy will update it's internal configuration and start forwarding traffic to your internal service. Only Github authenticated users will be able to connect.

See a list of services

You can visit https://auth.internal.MY-DOMAIN.COM/kube-auth-proxy/list to see a list of services you are authorized to view.

Service Annotations

  • kube-auth-proxy/host - The hostname to assign to the service. This can either be just the hostname (e.g. "prometheus") in which case it will combined the configured domain (e.g. ""), or it can be a FQDN (e.g. "".)

  • kube-auth-proxy/targetPort - The port to forward traffic to. This can either be the name of a port in the service's ports section, or it can be a numeric port.

  • kube-auth-proxy/protocol - The protocol to use to communicate with the back end - "http" or "https". Defaults to "http".

  • kube-auth-proxy/validateCertificate - If "protocol" is https, and this is "false", then kube-auth-proxy will not validate the target service's certificate. Defaults to "true".

  • kube-auth-proxy/bearerTokenSecret - A reference to a secret, used to populate a bearer token header when requests are sent to the target service. For example:

      kube-auth-proxy/bearerTokenSecret: "{secretName: 'mysecret', dataName: 'token'}"

    would find the secret "mysecret" in the same namespace as the service, extract value "token", and inject this as a bearer token in an "Authorization" header for all requests forwarded to the service. You can also specify a secretRegex in place of secretName, in which case the first secret found which matches the regex will be used. This is handy for tokens created by a ServiceAccount.

  • kube-auth-proxy/basicAuthUsername - A username to send in basic auth credentials to the target. If kube-auth-proxy/basicAuthPasswordSecret or kube-auth-proxy/basicAuthPassword is not present, this will be ignored.

  • kube-auth-proxy/basicAuthPasswordSecret - A reference to a secret, used to send basic auth credentials to the target. For example:

      kube-auth-proxy/basicAuthPasswordSecret: "{secretName: 'mysecret', dataName: 'password'}"
  • kube-auth-proxy/basicAuthPassword - A password to send in basic auth credentials to the target. In general you should prefer kube-auth-proxy/basicAuthPasswordSecret over this.


Note that if more than one condition is defined, they are "or"ed together. In other words, if you specify:

  kube-auth-proxy/githubAllowedOrganizations: myorg
  kube-auth-proxy/githubAllowedUsers: jwalton

then the github user "jwalton" will be allowed to access your service, and anyone in "myorg" will also be able to access your service (as opposed to the more restrictive "and" case where only users with the name "jwalton" who are also members of "myorg" will be allowed to access you service).

  • kube-auth-proxy/githubAllowedOrganizations - A comma delimited list of organization names. Any user who is a member of one of these organizations will be allowed to access your service. e.g. "github,benbria". Note that this is not case sensitive.
  • kube-auth-proxy/githubAllowedTeams - A comma delimited list of github teams allowed to access this service. Team names are specified as team@org. For example, if your organization was named "benbria", and you had two teams called "dev" and "ops", you could grant access to both these teams with "dev@benbria,ops@benbria". Note that this is not case sensitive.
  • kube-auth-proxy/githubAllowedUsers - A comma delimited list of github users allowed to access this service. Note that this is not case sensitive.

Configuring Services with ProxyTarget CRDs

Adding annotations to services is the preferred way to configure kube-auth-proxy, but sometimes it is impractical - for example perhaps you have a service you've installed via helm, and the helm chart doesn't give you an easy way to add annotations to the service.

In these cases, you can configure services using a ProxyTarget CRD. First, install the CRD:

$ kubectl apply -f

You can restrict which proxy targets will be considered in the config file using
label selectors:

    type: kube-auth-proxy-config

This make it so kube-auth-proxy will actively watch secrets and configmaps with the label "kube-auth-proxy-config". It will load all data inside any such configmap or secret found, and try to parse it as a YAML config file. Here's an example config file for the kubernetes dashboard:

kind: ProxyTarget
  name: rabbit-mq
    type: kube-auth-proxy-config
  host: dashboard
    service: kubernetes-dashboard
    targetPort: 443
    protocol: https
    validateCertificate: false
    secretRegex: '^kubernetes-dashboard-token.*$'
    dataName: 'token'
      - devOps@MY-ORG-HERE

Inside a target, you can use (almost) any annotation you could use on a service (minus the "kube-auth-proxy/" prefix). Condition annotations must be in the "conditions" section. In addition, you must specify a to which must either be a {targetUrl} or a {service, targetPort, namespace?} object.

Run locally in minikube

$ eval $(minikube docker-env)
$ docker build --target release --tag jwalton/kube-auth-proxy .
$ eval $(minikube docker-env -u)
$ kubectl apply -f ./examples/kube-auth-proxy-minikube.yaml
$ kubectl --namespace kube-system port-forward svc/kube-auth-proxy 5050:5050

And then visit http://localhost:5050.

Run locally in the shell

  • Create a file called "./config/kube-auth-proxy.yaml".

  • Create a config/kube-auth-proxy.yaml file:

      domain: localhost:5050
      secureCookies: false
          clientID: 'YOUR-CLIENT-ID'
          clientSecret: 'YOUR-CLIENT-SECRET'
  • Run npm start.

Copyright 2019 Jason Walton