Connecting an application

Putting an application behind a route protects it. Making it know who is using it - their name, their rights - is the second half, and each application takes it its own way. These recipes cover a few common ones, one per family: read the one closest to yours.

Two families cover nearly everything:

The examples below use https://apps.example.com for the gateway's public address, a route per application under its own path, and meerkat for the gateway's name inside the cluster (the OIDC / JWT drawer writes the real one).

Both families rest on one promise: the application is reachable only through the gateway. A header is trusted because nobody else can set it; an application also reachable directly - a NodePort, an ingress of its own, a published port - trusts whoever reaches it that way. Keep its Service internal (ClusterIP), put nothing else in front of it, and where the platform allows, add a network policy that admits only the gateway.

Grafana, by headers

Mechanism: headers, read by Grafana's auth proxy.

Grafana side (environment variables; the same keys exist in grafana.ini under [auth.proxy] and [server]):

GF_SERVER_ROOT_URL=https://apps.example.com/grafana/
GF_SERVER_SERVE_FROM_SUB_PATH=true
GF_AUTH_PROXY_ENABLED=true
GF_AUTH_PROXY_HEADER_NAME=X-WEBAUTH-USER
GF_AUTH_PROXY_HEADER_PROPERTY=username
GF_AUTH_PROXY_AUTO_SIGN_UP=true
GF_AUTH_PROXY_HEADERS=Email:X-WEBAUTH-EMAIL Name:X-WEBAUTH-NAME Role:X-WEBAUTH-ROLE
GF_AUTH_PROXY_WHITELIST=<the addresses the gateway calls from>
GF_AUTH_SIGNOUT_REDIRECT_URL=https://apps.example.com/logout

Meerkat side:

  1. A route on /grafana/** to the Grafana service, path kept as is (Grafana serves from the sub-path).
  2. Identity: username as X-WEBAUTH-USER, email as X-WEBAUTH-EMAIL, fullname as X-WEBAUTH-NAME.
  3. Auth forward: mechanism Headers.
  4. The role. Grafana wants one of Viewer, Editor, Admin. The plainest way is two routes on the same path, the first with an access rule on your Grafana administrators' role and an Incoming filter set-request-header X-WEBAUTH-ROLE: Admin, the second for everyone else with Viewer. The first route that lets a person in serves them.

Traps:

GeoServer, by headers

Mechanism: headers, read by GeoServer's HTTP Header authentication filter.

GeoServer side (web administration, Security > Authentication):

  1. Authentication Filters, Add new, HTTP Header. Name it (gateway), and set Request header attribute to a name nobody would guess, such as X-Gw-Auth-7f3c9a - GeoServer's own documentation calls it a shared secret between the proxy and GeoServer.
  2. Role source: either User group service (GeoServer's own users and roles, matched on the name), or Request header with a second header carrying the roles, separated by ;.
  3. Filter Chains: in each chain the browser and the clients use (web, rest, gwc, default), add the new filter before anonymous, and remove basic and form where people should only arrive through the gateway.
  4. Settings > Global, Proxy Base URL: https://apps.example.com/geoserver, so the capabilities documents name the public address.

Meerkat side:

  1. A route on /geoserver/** to the GeoServer service.
  2. Identity: username as X-Gw-Auth-7f3c9a (the same name). With roles from a header, roles as the roles header, shaped to GeoServer's form, for instance {{.Roles | .Keep "tag:GEOSERVER" | join ";"}} for the roles you tagged for it, named as GeoServer names them (ROLE_ADMINISTRATOR...).
  3. Auth forward: mechanism Headers.

Traps:

RabbitMQ management, through the OpenID provider

Mechanism: OIDC (Enterprise). The management UI signs in through Meerkat with PKCE, then calls the management API with its access token through the same route.

Meerkat side:

  1. The issuer: the application plane's public name, declared in Domains & TLS, Application tab - here apps.example.com, so https://apps.example.com.
  2. A client rabbitmq-ui, without a secret (the UI is browser code), and Audience rabbitmq (RabbitMQ's resource_server_id). A client declares no redirect URI: the UI's callback page is under the route's path, which is what the provider accepts.
  3. A route on /rabbitmq/** to the management port (15672), mechanism OIDC, client rabbitmq-ui, claims preferred_username from username and a roles claim. Two levels are two routes on the same path and client: the first for your RabbitMQ administrators with roles fixed to admin, the second for the others with roles fixed to viewer.

RabbitMQ side (rabbitmq.conf):

auth_backends.1 = rabbit_auth_backend_oauth2
# during the switch only, so the existing accounts still work:
auth_backends.2 = rabbit_auth_backend_internal

auth_oauth2.resource_server_id = rabbitmq
auth_oauth2.issuer = https://apps.example.com
auth_oauth2.preferred_username_claims.1 = preferred_username
auth_oauth2.additional_scopes_key = roles
auth_oauth2.scope_aliases.admin = rabbitmq.tag:administrator rabbitmq.read:*/* rabbitmq.write:*/* rabbitmq.configure:*/*
auth_oauth2.scope_aliases.viewer = rabbitmq.tag:monitoring rabbitmq.read:*/*

management.path_prefix = /rabbitmq
management.oauth_enabled = true
management.oauth_client_id = rabbitmq-ui
management.oauth_scopes = openid profile
# during the switch only: keeps the username and password form
management.oauth_disable_basic_auth = false

Traps:

DbGate, through the OpenID provider

Mechanism: OIDC (Enterprise). DbGate's server runs the sign-in and keeps a secret.

Meerkat side:

  1. The issuer: the public name apps.example.com, so https://apps.example.com.
  2. A client dbgate with a secret: Drawn by Meerkat (copy it from the form before saving), or Given by the application when DbGate's chart generates one - paste it from its Kubernetes Secret. DbGate comes back under /dbgate/, the route's path: nothing to declare.
  3. A route on /dbgate/** to DbGate, mechanism OIDC, client dbgate, claim preferred_username from username (and email, name if you like).

DbGate side (environment variables):

WEB_ROOT=/dbgate
OAUTH_AUTH=https://apps.example.com/meerkat/oidc/authorize
OAUTH_TOKEN=http://meerkat:7070/meerkat/oidc/token
OAUTH_LOGOUT=https://apps.example.com/logout
OAUTH_CLIENT_ID=dbgate
OAUTH_CLIENT_SECRET=mko_...
OAUTH_SCOPE=openid profile
OAUTH_LOGIN_FIELD=preferred_username
LOGIN_PERMISSIONS_alice=*
LOGIN_PERMISSIONS_bob=~*, widgets/database

Traps:

Read more