Platform Mesh

Identity and authorization

kcp is the enforcement point for Platform Mesh. Every API request flows through the front proxy, an authentication chain (global + per-workspace), and an authorization chain that ends with the rebac-authz-webhook calling OpenFGA.

See Identity and authorization for the conceptual model.

Primitives

Primitive Platform Mesh role Upstream
kcp-front-proxy Single TLS-terminating ingress; all clients connect here. Front proxy
--authentication-config Cluster-wide OIDC config (kcp flag, takes an AuthenticationConfiguration). Authentication
WorkspaceAuthenticationConfiguration Per-workspace OIDC config referenced by a WorkspaceType. Platform Mesh uses this to give each org its own Keycloak realm. Workspace authentication
--authorization-webhook-config-file Wires a SubjectAccessReview webhook into the kcp authorizer chain. Authorization
Built-in authorizer chain Required Groups → Workspace Content → System CRD → Maximal Permission Policy → one of {Local, Global, Bootstrap}. The webhook is configured as a sibling authorizer in AuthorizationConfiguration. Authorizers

Per-workspace OIDC

The WorkspaceAuthenticationConfiguration referenced by the orgs WorkspaceType (see Workspaces) defines the JWT issuer, audience, and claim mapping for a workspace subtree. Platform Mesh ships one per shared realm and one per organization (the security-operator provisions per-org configs dynamically):

# platform-mesh-operator/manifests/kcp/workspace-authentication-configuration.yaml
apiVersion: tenancy.kcp.io/v1alpha1
kind: WorkspaceAuthenticationConfiguration
metadata:
  name: orgs-authentication
spec:
  jwt:
    - issuer:
        url: https:///keycloak/realms/welcome
        audiences:
        - 
        audienceMatchPolicy: MatchAny
        certificateAuthority: |

      claimMappings:
        groups:
          claim: groups
          prefix: ""
        username:
          claim: email
          prefix: ""

The security-operator composes per-org issuers from AccountInfo.Spec.OIDC.Clients:

// security-operator/internal/subroutine/workspace_authorization.go
audiences := make([]string, 0, len(accountInfo.Spec.OIDC.Clients)+len(r.cfg.AdditionalAudiences))
for clientName, clientInfo := range accountInfo.Spec.OIDC.Clients {
    audiences = append(audiences, clientInfo.ClientID)
}
audiences = append(audiences, r.cfg.AdditionalAudiences...)

jwtAuth := kcptenancyv1alphav1.JWTAuthenticator{
    Issuer: kcptenancyv1alphav1.Issuer{
        URL:       fmt.Sprintf("https://%s/keycloak/realms/%s", r.cfg.BaseDomain, workspaceName),
        Audiences: audiences,
    },
}

Authorizer chain

Platform Mesh ships an AuthorizationConfiguration that runs RBACNode → a webhook into rebac-authz-webhook. The match conditions skip RBAC group requests so the webhook does not have to re-authorize standard Kubernetes RBAC traffic:

# helm-charts/local-setup/webhook-config/authorization-webhook-config.yaml
apiVersion: apiserver.config.k8s.io/v1beta1
kind: AuthorizationConfiguration
authorizers:
  - { type: RBAC, name: rbac }
  - { type: Node, name: node }
  - type: Webhook
    name: authz-webhook
    webhook:
      authorizedTTL: 30s
      unauthorizedTTL: 30s
      timeout: 3s
      subjectAccessReviewVersion: v1
      matchConditionSubjectAccessReviewVersion: v1
      failurePolicy: NoOpinion
      matchConditions:
        - expression: has(request.resourceAttributes)
        - expression: request.resourceAttributes.group != "rbac.authorization.k8s.io"
      connectionInfo:
        type: KubeConfigFile
        kubeConfigFile: /config/authz-webhook-kubeconfig.yaml

rebac-authz-webhook wiring

The webhook runs as its own deployment. It connects to OpenFGA and watches a specific APIExportEndpointSlice so it can resolve workspace identity for incoming SubjectAccessReviews:

# helm-charts/charts/rebac-authz-webhook/templates/deployment.yaml (excerpt)
args:
  - "serve"
  - "--openfga-addr="
  - "--kcp-api-export-endpoint-slice-name="
  - "--health-probe-bind-address="
  - "--webhook-cache-miss-max-retries="
  - "--webhook-cache-miss-ttl="
ports:
  - containerPort: 9443  # webhook server (SubjectAccessReview)
  - containerPort: 8080  # metrics

Maximal Permission Policy

APIExport.spec.maximalPermissionPolicy puts an upper bound on what consumers can do with the export’s resources, even via the apis.kcp.io:binding: group prefix. Platform Mesh exposes this to providers but does not centrally drive it.