OAuth2 Support

Kubernetes Web View support OAuth2 for protecting its web frontend. Use the following environment variables to enable it:

OAUTH2_AUTHORIZE_URL
OAuth 2 authorization endpoint URL, e.g. https://oauth2.example.org/authorize
OAUTH2_ACCESS_TOKEN_URL
Token endpoint URL for the OAuth 2 Authorization Code Grant flow, e.g. https://oauth2.example.org/token
OAUTH2_CLIENT_ID
OAuth 2 client ID
OAUTH2_CLIENT_ID_FILE
Path to file containing the client ID. Use this instead of OAUTH2_CLIENT_ID to read the client ID dynamically from file.
OAUTH2_CLIENT_SECRET
OAuth 2 client secret
OAUTH2_CLIENT_SECRET_FILE
Path to file containing the client secret. Use this instead of OAUTH2_CLIENT_SECRET to read the client secret dynamically from file.
SESSION_SECRET_KEY
Secret to encrypt the session cookie. Must be 32 bytes base64-encoded. Use cryptography.fernet.Fernet.generate_key() to generate such a key.

The OAuth2 login flow will (by default) just protect the web frontend, the configured credentials (in-cluster Service Account, Kubeconfig, or Cluster Registry) will be used to access the cluster(s). This behavior can be changed and the session’s OAuth2 access token can be used for cluster authentication instead of using configured credentials. Enable this operation mode via --cluster-auth-use-session-token.

The OAuth redirect flow will not do any extra authorization by default, i.e. everybody who can login with your OAuth provider can use Kubernetes Web View! You can plug in a custom Python hook function (coroutine) via --oauth2-authorized-hook to validate the login or do any extra work (store extra info in the session, deny access, log user ID, etc). Note that the hook needs to be a coroutine function with signature like async def authorized(data, session). The result should be boolean true if the login is successful, and false otherwise. Examples of such hooks are provided in the examples directory. A minimal hooks.py would look like:

import logging

async def oauth2_authorized(data: dict, session):
    access_token = data["access_token"]
    # TODO: do something with the access token, e.g. look up user info
    logging.info("New OAuth login!")
    # TODO: validate whether login is allowed or not
    return True  # allow all OAuth logins

This file would need to be in the Python search path, e.g. as hooks.py in the root (“/”) of the Docker image. Pass the hook function as --oauth2-authorized-hook=hooks.oauth2_authorized to Kubernetes Web View.

Google OAuth Provider

This section explains how to use the Google OAuth 2.0 provider with Kubernetes Web View:

GitHub OAuth Provider

How to use GitHub as the OAuth provider with Kubernetes Web View:

  • create a new OAuth app in the GitHub UI
  • use https://{my-kube-web-view-host}/oauth2/callback as the Authorization callback URL in the GitHub UI
  • use “https://github.com/login/oauth/authorize” for OAUTH2_AUTHORIZE_URL
  • use “https://github.com/login/oauth/access_token” for the OAUTH2_ACCESS_TOKEN_URL
  • pass the obtained client ID in the OAUTH2_CLIENT_ID environment variable
  • pass the obtained client secret in the OAUTH2_CLIENT_SECRET environment variable

Note that any GitHub user can now login to your deployment of Kubernetes Web View! You have to configure a --oauth2-authorized-hook function to validate the GitHub login and only allow certain usernames:

  • copy hooks.py from examples/oauth2-validate-github-token/hooks.py (see examples dir) to a new folder
  • customize the username in hooks.py to match your allowed GitHub user logins
  • create a new Dockerfile in the same folder
  • edit the Dockerfile to have two lines: 1) FROM hjacobs/kube-web-view:{version} (replace “{version}”!) as the first line, and 2) COPY hooks.py / to copy our OAuth validation function
  • build the Docker image
  • configure your kube-web-view deployment and add --oauth2-authorized-hook=hooks.oauth2_authorized as argument
  • deploy kube-web-view with the new Docker image and CLI option

AWS Cognito Provider

Setting up Cognito

A number of steps need to be taken to setup Amazon Cognito for OAuth2. These instructions are correct as of August 2019.

Create User Pool

  1. Create a User Pool
  2. Choose how you want End Users to sign in (for example via Email, Username or otherwise)
  3. Once you have gone through all the settings (customise to your liking) for creating a user pool, add an App Client

Create an App Client

  1. Choose a Name that is relevant to the application (eg kube-web-view)
  2. Make sure the Generate client secret option is selected, and set your Refresh token expiration time to whatever you are comfortable with.

The App Client will then generate a Client ID and Client Secret, wich will be used later

App Client Settings

  1. Select the previously created client
  2. Fill in the Callback URL(s) section with https://{my-kube-web-view-host}/oauth2/callback
  3. Under OAuth 2.0, choose the relevant Allowed OAuth Flows (eg Authorization Code Grant, Implicit Grant)
  4. Choose the Allowed OAuth Scopes you want to include. email is the minimum you will need

IMPORTANT: Domain Name

You must create a domain name for OAuth to function against AWS Cognito, otherwise the required Authorization and Token URLs will not be exposed.

You can choose whether to use an AWS-hosted Cognito Domain (eg https://{your-chosen-domain}.auth.us-east-1.amazoncognito.com), or to use your own domain.

Update Deployment

You can now update your Deployment with the relevant Environment variables. If you have chosen to use an AWS Cognito Domain, then the {FQDN} variable in the below section will be https://{your-chosen-domain}.auth.{aws-region}.amazoncognito.com. Otherwise, replace it with your domain

  • use “https://{FQDN}/oauth2/authorize” for OAUTH2_AUTHORIZE_URL
  • use “https://{FQDN}/oauth2/token” for OAUTH2_ACCESS_TOKEN_URL
  • Use the App Client ID generated during “Create an App Client” in the OAUTH2_CLIENT_ID environment variable
  • Use the App Client secret in the OAUTH2_CLIENT_SECRET environment variable. If you cannot see the secret, press “Show Details” in the AWS Console

Terraform

An example Terraform deployment of the above is below:

# Create the User Pool
resource "aws_cognito_user_pool" "kube-web-view" {
  name = "userpool-kube-web-view"
  alias_attributes = [
    "email",
    "preferred_username"
  ]

  auto_verified_attributes = [
    "email"
  ]

  schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true
    name                     = "name"
    required                 = true

    string_attribute_constraints {
      min_length = 3
      max_length = 70
    }
  }

  admin_create_user_config {
    allow_admin_create_user_only = true
  }

  tags = {
    "Name" = "userpool-kube-web-view"
  }
}

# Create the oauth2 Domain

resource "aws_cognito_user_pool_domain" "kube-web-view" {
  domain = "oauth-kube-web-view"
  user_pool_id = aws_cognito_user_pool.kube-web-view.id
}

# kube-web-view Client

resource "aws_cognito_user_pool_client" "kube-web-view" {
  name = "kube-web-view"
  user_pool_id = aws_cognito_user_pool.kube-web-view.id

  allowed_oauth_flows = [
    "code",
    "implicit"
  ]

  allowed_oauth_scopes = [
    "email",
    "openid",
    "profile",
  ]

  supported_identity_providers = [
    "COGNITO"
  ]

  generate_secret = true

  allowed_oauth_flows_user_pool_client = true

  callback_urls = [
    "https://{my-kube-web-view-host}/oauth2/callback"
  ]
}


# Outputs

output "kube-web-view-id" {
  description = "Kube Web View App ID"
  value = aws_cognito_user_pool_client.kube-web-view.id
}

output "kube-web-view-secret" {
  description = "Kube Web View App Secret"
  value = aws_cognito_user_pool_client.kube-web-view.client_secret