OAuth2 Proxy is a great way to easily secure internal company applications that are running on Kubernetes. We host a few simple applications - helpers really - that need some form of authentication to prevent anyone who has network access from accessing the site. Building the auth flow into the application would be ideal but when the application already exists and you need a quick solution…

Since our company uses Azure AD, oauth2-proxy can be configured to force all traffic hitting the application ingress to authenticate against Azure AD.

Azure AD App Registration

To use Azure AD for your authentication you first need to create an application in your Azure AD tenant. The guide below assumes you have permissions to create all the required elements.

  1. Open the Azure portal and go to App registrations

  2. Select New registration

  3. Give your app a name - this name will be seen by the user when logging in so make it meaningful

  4. Click Register

    Azure App registration

    The portal will now open you application, the next steps are to configure your application

  5. Navigate to Token configuration from the left menu

  6. Select Add groups claim

  7. Select All groups and click Add

    Azure App registration

  8. Navigate to Certificates & Secrets from the left menu

  9. Select New client secret

    1. Enter a description and select a suitable expiry time
  10. Copy the Value and save it for later - you cannot see this value again so be sure to save it

  11. Navigate to Overview from the left menu

    1. Copy the Application (client) ID
    2. Click Endpoints and copy the value for OAuth 2.0 token endpoint (v2)

oauth2-proxy Helm Chart Instructions

My preferred way of deploying application to Kubernetes is using helm charts. You don’t have to use a helm chart to deploy oauth2-proxy - the configuration will be the same no matter how you decide to deploy it.

From the above App Registration you should have recorded the

  • Application (client) ID
  • Secret Value
  • OAuth 2.0 token endpoint (v2)

For the OAuth 2.0 Token, you do not need the full url. The url only needs up to the /v2.0 point:

https://login.microsoftonline.com/<your tenant id>/oauth2/v2.0

These values are all required by oauth2-proxy when communicating with Azure AD. The instructions below will show you how to deploy the oauth2-proxy helm chart for your application and test that it works with Azure AD.

  1. Add the helm repo

    helm repo add oauth2-proxy https://oauth2-proxy.github.io/manifests
    
  2. Generate a cookie secret for oauth2-proxy, you can use bash for this, or follow the instructions for other methods like Python or OpenSSL:

    dd if=/dev/urandom bs=32 count=1 status=none | base64 -w 0 | tr -- '+/' '-_'; echo
    
  3. Create a values.yaml file that will be used to configure the helm chart. There are several configuration values that need to be populated for oauth2-proxy to work in you environment. The values listed below are the key requirements, anything beyond this is up to you. For a full overview of all the settings passed to the configFile field, have a look at the documentation:

    1. clientID
    2. clientSecret
    3. cookieName - keep this unique to each deployment
    4. cookieSecret - generated above
    5. configFile - oidc_issuer_url - this is your tenant login url
    6. configFile - cookie_domains - this is unique to your application environment
    7. configFile - whitelist_domains - allowed domains for redirection after authentication
    config:
      clientID: # Insert your Application (client) ID
      clientSecret: # Insert your client secret
      cookieSecret: XTJolTar1JH9oU5pYSBe4pt25s7KGTP1s70PwntT7Ro=
      cookieName: _oauth2_proxy_cookie_name
      configFile: |-
        oidc_issuer_url = "https://login.microsoftonline.com/<your tenant uuid>/v2.0"
        oidc_groups_claim = "roles"
        provider = "oidc"
        pass_user_headers = true
        # return authenticated user to nginx
        set_xauthrequest = true
        skip_provider_button = false
        skip_auth_regex = "^/api/\\d+/webhook/"
        provider_display_name = "Azure AD"
        cookie_domains = ["example.com", "example.cloud"]
        cookie_expire = "1h"
        cookie_httponly = false
        cookie_secure = true
        email_domains = ["example.com"]
        errors_to_info_log = true
        show_debug_on_error = true
        exclude_logging_paths = ["/ping"]
        # reverse_proxy = "true"
        whitelist_domains = [".subdomain.example.cloud"]
        # we don't want to proxy anything so pick a non-existent directory
        upstreams = [ "file:///dev/null" ]    
    
    sessionStorage:
      type: redis
      # redis:
      #   existingSecret: "oauth2-login-proxy-redis"
    
    # Deploy redis subchart as part of oauth2-proxy
    redis:
      enabled: true
      auth:
        enabled: true
      architecture: standalone
    
      master:
        resources:
          requests:
            cpu: 50m
            memory: 128Mi
          limits:
            cpu: 250m
            memory: 1024Mi
    
      replica:
        resources:
          requests:
            cpu: 50m
            memory: 128Mi
          limits:
            cpu: 250m
            memory: 1024Mi
    
      metrics:
        enabled: true
    
  4. The above config is missing the ingress portion. You will still need to add a suitable ingress for your application, for example:

    ingress:
      enabled: true
      path: /
      hosts:
        - login.subdomain.example.cloud
      className: nginx
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
        nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
        cert-manager.io/cluster-issuer: "letsencrypt-cluster-issuer"
        external-dns.alpha.kubernetes.io/hostname: login.subdomain.example.cloud
      tls:
        - secretName: tls-secret-oauth2-login-example
          hosts:
            - login.subdomain.example.cloud
    
  5. Deploy your application using helm

    helm upgrade --install \
     -f values.yaml \
     oauth2-proxy-example \
     oauth2-proxy/oauth2-proxy
    

You can test your application by opening the ingress url in a browser. A working proxy will present you with a login screen

Login Screen

Adding the oauth2-proxy to an application

`nginx-ingress`` has annotations that cater for a auth redirects on ingress. When added, nginx will force all traffic to the authentication url before passing it on to the application. This is a simple way to ensure no unauthorised traffic hits your application.

For this to work you need

  • The external url of your authentication proxy
  • The internal service url accessible in the EKS cluster

The internal url follows the usual Kubernetes naming scheme of:

<service name>.<namespace>.svc.cluster.local

By way of example, these annotations were added to an internal only application that needed Azure AD authentication. You can edit the auth-* fields and server-snippet to suite your application.

ingress:
  annotations:
    external-dns.alpha.kubernetes.io/hostname: application.subdomain.example.cloud
    nginx.ingress.kubernetes.io/auth-response-headers: X-Auth-Request-User,X-Auth-Request-Groups,X-Auth-Request-Email,X-Auth-Request-Preferred-Username
    nginx.ingress.kubernetes.io/auth-signin: https://login.subdomain.example.cloud/oauth2/start
    nginx.ingress.kubernetes.io/auth-url: http://oauth2-proxy-example.default.svc.cluster.local/oauth2/auth
    nginx.ingress.kubernetes.io/server-snippet: |
      location ~* "^/oauth2/sign_out" {
        return 302 https://login.subdomain.example.cloud/oauth2/sign_out;
      }      

Limiting group access

To limit access to an application to only the assigned users or groups, you need to enable the explicit assignment feature of the application.

From the Azure portal:

  1. Open the Enterprise Applications page

  2. Search for your application and open it

  3. From the left menu select Properties

  4. Change the Assignment required? field to Yes and then hit Save

    Enterprise App Registration

  5. Select Users and Groups from the left menu

    1. Select Add user/group and then add the users or groups who will have access

To test the above configuration, leave yourself out of the users/groups with access and try access the application. You will be prompted to login but then denied access by Azure AD.

Final thoughts

If you’ve read this far, thank you! You have probably also figured out that this is not a good long term solution, but this is a great stop gap for getting authentication in front of applications that started as a quick fix and are now business critical.

Using this setup you have oauth2-proxy ready for the next stage of authentication, it will pass the roles like admin or read_only assigned to a user, or group of users, and the application can then use that to assign privileges/roles internally.

You just need to decipher the groups passed by Azure AD that arrive in the X-Auth-Request-Groups header…