Skip to content

feat: OIDC configurable profiles with template support and Kubernetes annotation passing#3917

Open
mjungsbluth wants to merge 7 commits intomasterfrom
oidc-profiles
Open

feat: OIDC configurable profiles with template support and Kubernetes annotation passing#3917
mjungsbluth wants to merge 7 commits intomasterfrom
oidc-profiles

Conversation

@mjungsbluth
Copy link
Copy Markdown
Collaborator

@mjungsbluth mjungsbluth commented Mar 13, 2026

Usage

Define profiles

Pass named profiles via -oidc-profiles (inline YAML) or the new -oidc-profiles-file flag (path to a YAML file; the two flags are mutually exclusive):

# profiles.yaml
myprofile:
  idp-url: https://idp.example.com
  client-id: my-client-id
  client-secret: secretRef:my-client-secret
  callback-url: https://{{.Request.Host}}/.well-known/oauth2-callback
  scopes: email profile
skipper -oidc-secrets-file /path/to/secrets \
        -oidc-profiles-file /path/to/profiles.yaml

All fields except idp-url support Go text/template expressions resolved at request time:

Expression Value
{{.Request.Host}} Hostname from the incoming request
{{index .Annotations "key"}} Value set by a preceding annotate() filter

client-id and client-secret also accept the existing secretRef: prefix and for client-secret this is the secure default.

Reference profiles in routes

Use profile:<name> as the first argument to any oauthOidc* filter. Claims are still passed as a second argument:

myroute: * -> oauthOidcAnyClaims("profile:myprofile", "groups") -> "https://backend";

Multi-tenant with Kubernetes annotations

Define a template-driven profile:

oidc-profiles:
  multi-tenant:
    idp-url: https://idp.example.com
    client-id: '{{index .Annotations "oidc/client-id"}}'
    client-secret: 'secretRef:{{index .Annotations "oidc/client-secret"}}'
    callback-url: https://{{.Request.Host}}/.well-known/oauth2-callback
    scopes: email profile

Start Skipper with the new -kubernetes-annotations-to-route-annotations flag to automatically inject Kubernetes resource annotations as annotate() filters into generated routes:

skipper -kubernetes-annotations-to-route-annotations=oidc/client-id,oidc/client-secret

An optional -kubernetes-annotations-to-route-annotations-prefix prepends a string to each key in the generated annotate() call (no separator added; K8s annotation lookup key is unchanged):

# annotation "oidc/client-id" produces annotate("k8s:oidc/client-id", value)
skipper -kubernetes-annotations-to-route-annotations=oidc/client-id \
        -kubernetes-annotations-to-route-annotations-prefix=k8s:

Annotate Kubernetes Ingress or RouteGroup resources:

metadata:
  annotations:
    oidc/client-id: tenant-abc-client
    oidc/client-secret: tenant-abc
    zalando.org/skipper-filter: 'oauthOidcAnyClaims("profile:multi-tenant", "groups")'

New flags

Flag Description
-oidc-profiles Named OIDC profiles as inline YAML. Mutually exclusive with -oidc-profiles-file.
-oidc-profiles-file Path to a YAML file of named OIDC profiles. Mutually exclusive with -oidc-profiles.
-kubernetes-annotations-to-route-annotations Comma-separated annotation keys to inject as annotate() filters into routes generated from Kubernetes resources.
-kubernetes-annotations-to-route-annotations-prefix Optional prefix prepended to the key in generated annotate() filter calls (no separator added).

Architecture

  • filters/auth/oidcprofile.go (new) — OidcProfile struct with YAML tags; tokenOidcProfileFilter which resolves Go text/template fields at request time and caches fully-constructed tokenOidcFilter delegates in a sync.Map keyed by SHA-256 hash of resolved parameters. Provider discovery runs once at CreateFilter time so it is shared across all delegates.
  • filters/auth/oidc.goCreateFilter detects the profile: prefix and delegates to createProfileFilter, which looks up the profile, discovers the provider, and returns a tokenOidcProfileFilter. OidcOptions gains a Profiles map[string]OidcProfile field.
  • dataclients/kubernetes/annotations.go — new injectAnnotateFilters(annotations, keys, prefix, route) helper; prepends annotate(prefix+key, value) filters for each configured key present on the resource. Called from both Ingress (ingressv1.go) and RouteGroup (routegroup.go) conversion paths.
  • config/config.go / skipper.go — four new flags wired through skipper.Options → kubernetes.Options / auth.OidcOptions.

@mjungsbluth mjungsbluth added major moderate risk, for example new API, small filter changes that have no risk like refactoring or logs do-not-merge and removed documentation labels Mar 13, 2026
@mjungsbluth mjungsbluth marked this pull request as ready for review March 13, 2026 21:42
…ing templating

Signed-off-by: Magnus Jungsbluth <magnus.jungsbluth@zalando.de>
Signed-off-by: magnus-jungsbluth_zse <magnus.jungsbluth@zalando.de>
Signed-off-by: Magnus Jungsbluth <magnus.jungsbluth@zalando.de>
Signed-off-by: magnus-jungsbluth_zse <magnus.jungsbluth@zalando.de>
Signed-off-by: magnus-jungsbluth_zse <magnus.jungsbluth@zalando.de>
Signed-off-by: magnus-jungsbluth_zse <magnus.jungsbluth@zalando.de>
Signed-off-by: magnus-jungsbluth_zse <magnus.jungsbluth@zalando.de>
Signed-off-by: magnus-jungsbluth_zse <magnus.jungsbluth@zalando.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge documentation major moderate risk, for example new API, small filter changes that have no risk like refactoring or logs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant