Skip to content

Feature: Register custom OIDC issuers at Project level #693

Description

@ValentinGerlach

What would you like to be added?

A new namespace-scoped CRD OIDCIssuer that lives in the project namespace (project-<name>). A project admin can create one or more OIDCIssuer resources to register custom OIDC issuers with the onboarding API without platform operator involvement.

The system generates a globally unique, human-readable prefix for each registered issuer and exposes it in status.prefix. Once registered, the issuer is trusted globally by the onboarding API (not just within the owning project). Members from this issuer can be referenced in any Project.spec.members or Workspace.spec.members by prepending the prefix to the username or group name. The prefix includes the trailing colon so that the full member name is simply status.prefix + username. A team can register an issuer in their own project and a different project admin can grant those identities access to their project by using the same prefix.

API design

The spec is modelled after the Gardener OpenIDConnect CRD, with usernamePrefix and groupsPrefix omitted from spec because they are system-generated and exposed in status instead.

apiVersion: core.openmcp.cloud/v1alpha1
kind: OIDCIssuer
metadata:
  name: github-actions
  namespace: project-my-team
spec:
  # Required: URL the provider signs ID tokens as (the "iss" claim).
  issuerURL: https://token.actions.githubusercontent.com

  # Required: acceptable values for the "aud" claim in ID tokens.
  audiences:
    - https://github.com/my-org

  # Required: JWT claim to use as the username.
  usernameClaim: sub

  # Optional: JWT claim to use for group membership. Omit if the provider does not issue groups.
  groupsClaim: groups

  # Optional: PEM-encoded CA bundle for validating the provider's TLS certificate.
  # caBundle: |
  #   -----BEGIN CERTIFICATE-----
  #   ...

  # Optional: key-value pairs that must be present in the ID token.
  requiredClaims:
    # repository: my-org/my-repo

  # Optional: static JWKS for offline validation (base64-encoded JSON Web Key Set).
  # jwks:
  #   keys: <base64>
status:
  # Derived as "project:<project>:issuer:<name>:". Includes the trailing colon.
  # Members from this issuer are referenced as "<prefix><username>".
  prefix: "project:my-team:issuer:github-actions:"

  conditions:
    - type: Ready
      status: "True"

The prefix is derived deterministically as project:<project-name>:issuer:<oidcissuer-name>: and written to status.prefix. Global uniqueness is guaranteed structurally: Project names are cluster-scoped and unique, and OIDCIssuer names are unique within their namespace, so no two resources can produce the same prefix.

Usage example

After creating the OIDCIssuer in project-my-team, a project admin adds members using the generated prefix:

apiVersion: core.openmcp.cloud/v1alpha1
kind: Project
metadata:
  name: my-team
spec:
  members:
    - kind: User
      name: openmcp:alice@example.com             # system IDP, unchanged
      roles: [admin]
    - kind: User
      name: project:my-team:issuer:github-actions:repo:my-org/my-repo:ref:refs/heads/main
      roles: [view]                                # GitHub Actions workflow identity
    - kind: Group
      name: project:my-team:issuer:github-actions:my-org   # GitHub org as group
      roles: [view]

Because the registered issuer is trusted globally, a different project admin can reference the same identities in their own project without registering the issuer again:

apiVersion: core.openmcp.cloud/v1alpha1
kind: Project
metadata:
  name: other-team
spec:
  members:
    - kind: User
      name: project:my-team:issuer:github-actions:repo:my-org/my-repo:ref:refs/heads/main
      roles: [view]

Constraints

  • OIDCIssuer is namespace-scoped, living in the project namespace. Only project admins can create and delete it.
  • The registered issuer is trusted globally by the onboarding API. Any principal from this issuer can be granted access to any Project or Workspace by any admin with edit access to that resource, using the generated prefix.
  • The registered issuer is not automatically trusted by ControlPlanes. Those continue to configure their own spec.iam.oidc.extraProviders independently. This feature only concerns authentication to the onboarding API (managing Projects, Workspaces, ControlPlanes).
  • OIDCIssuer cannot be created outside a project namespace.

Acceptance criteria

  • A project admin can create an OIDCIssuer in their project namespace without platform operator involvement.
  • The system generates a status.prefix of the form project:<project>:issuer:<name>: for each OIDCIssuer.
  • A token issued by the registered issuer can be used to authenticate to the onboarding API.
  • Users and groups from the custom issuer can be added to Project.spec.members and Workspace.spec.members in any project using <prefix><name>.

Open question: implementation location

The controller reconciling OIDCIssuer must register the issuer with the onboarding cluster's kube-apiserver. The mechanism depends on the cluster flavor:

Onboarding cluster flavor Mechanism
Gardener shoot Create an OpenIDConnect resource (authentication.gardener.cloud/v1alpha1) via gardener-extension-shoot-oidc-service
Vanilla Kubernetes (>= 1.30) Patch the AuthenticationConfiguration file (apiserver.config.k8s.io/v1) directly
Other managed Kubernetes Provider-specific (may not be feasible at all)

Implementing in platform-service-project-workspace is the most direct option, but would introduce a conditional dependency on gardener-extension-shoot-oidc-service when the onboarding cluster is a Gardener shoot, coupling a generic onboarding service to a specific infrastructure provider. An alternative is to introduce a separate, platform-specific adapter component: platform-service-project-workspace manages only the OIDCIssuer CRD lifecycle (prefix generation, status), while the adapter handles the actual trust registration on the underlying cluster.

Why is this needed?

Today, OIDC issuers trusted by the onboarding API are configured solely by platform operators. This blocks two common use cases:

  1. Access management: Teams that use their own OIDC issuer (a corporate SSO, a GitHub Actions issuer, a Kubernetes cluster's ServiceAccount issuer) cannot reference their own users or groups in Project.spec.members or Workspace.spec.members. Every identity must come from the system IDP.

  2. Automation bootstrap: Automated actors (CI pipelines, orchestrators) can only authenticate to the onboarding API if their issuer is trusted at platform level. There is no self-service path for a project owner to grant their own automation access. The available workaround is to create a Kubernetes ServiceAccount inside the project and generate short-lived tokens for it, but this requires manual token rotation and adds significant maintenance overhead for any team running continuous automation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions