Skip to content

Virtual workspaces

A virtual workspace is a kcp-published HTTP endpoint that proxies a curated view of objects across many workspaces. Platform Mesh controllers and the rebac-authz-webhook connect to virtual workspaces to watch consumer resources without holding per-workspace credentials.

See Watch and sync for the controller-runtime layer that consumes these endpoints.

URL contracts

EndpointShapePurpose
APIExport VW/services/apiexport/<provider-path>/<export-name>/clusters/*/...Wildcard view of all consumer-bound objects for a given APIExport.
Initializing-workspace VW/services/initializingworkspaces/<initializer-name>/clusters/*/...Wildcard view of workspaces awaiting an initializer phase.
Terminating-workspace VWlisted in WorkspaceType.status.virtualWorkspaces[type=terminating]Wildcard view of workspaces in the terminating phase the type defines.

URLs are not constructed by hand. Platform Mesh reads them from kcp status objects.

Discovering APIExport URLs

APIExportEndpointSlice (created alongside each APIExport) publishes the virtual-workspace URL of every shard the export is exposed on. Platform Mesh consumes the first endpoint:

go
// platform-mesh-operator/pkg/subroutines/scoped_provider_kubeconfig.go
// virtualWorkspaceServerURLFromSlice returns status.apiExportEndpoints[0].url
// as the kubeconfig cluster server (kcp's published VirtualWorkspace URL).
func virtualWorkspaceServerURLFromSlice(slice *kcpapiv1alpha1.APIExportEndpointSlice) (string, error) {
    if len(slice.Status.APIExportEndpoints) == 0 {
        return "", fmt.Errorf("no APIExport endpoints in slice %s", slice.Name)
    }
    return slice.Status.APIExportEndpoints[0].URL, nil
}

The rebac-authz-webhook discovers its endpoint the same way, via --kcp-api-export-endpoint-slice-name.

Discovering terminating-phase URLs

WorkspaceType.status.virtualWorkspaces lists endpoints for workspaces undergoing each lifecycle phase the type opts into. The security-operator reads the terminating URLs to clean up IAM stores when a workspace is being deleted:

go
// security-operator/internal/terminatingworkspaces/provider.go
GetVWs: func(obj client.Object) ([]string, error) {
    wst := obj.(*kcptenancyv1alpha1.WorkspaceType)
    var urls []string
    for _, endpoint := range wst.Status.VirtualWorkspaces {
        if endpoint.Type != "terminating" {
            continue
        }
        urls = append(urls, endpoint.URL)
    }
    return urls, nil
},

What you see through a virtual workspace

  • Objects come back annotated with kcp.io/cluster so the consumer knows the source workspace.
  • Authorization runs through the virtual-workspace's own RBAC, not raw system:masters.
  • Identity hash on the APIExport scopes which schemas are visible — providers cannot accidentally see other providers' data of the same group/resource.

Consumers in Platform Mesh

ComponentWhat it watches
account-operatorcore.platform-mesh.io — reconciles Account and Workspace objects across consumer workspaces.
rebac-authz-webhookThe endpoint slice it's pointed at — resolves which workspace a SubjectAccessReview came from.
security-operatorcore.platform-mesh.io for IAM stores; WorkspaceType.status.virtualWorkspaces[type=terminating] for cleanup during workspace deletion.
Kubernetes GraphQL gatewayConfigurable export — exposes the bound APIs as GraphQL.
terminal-controller-manager, search-operator, gardener-syncer, extension-manager-operator, marketplace virtual-workspaces, resource-brokerEach watches its own APIExport's VW.

The Helm value naming the slice each component watches is kcp.apiExportEndpointSliceName; account-operator defaults to core.platform-mesh.io (helm-charts).

End-to-end example

The example-mongodb-multiclusterruntime repo shows the full flow. The provider controller is run with a kubeconfig whose server URL is rewritten to the value from the endpoint slice:

bash
# example-mongodb-multiclusterruntime: README.md
VW_URL="$(kubectl get apiexportendpointslices.apis.kcp.io mongodb \
  -o jsonpath='{.status.endpoints[0].url}')"
kubectl --kubeconfig=kcp-controller.kubeconfig config set-cluster \
  ... --server "${VW_URL}"

Through that single connection the controller reconciles every MongoDB object across every consumer workspace that bound the export, and writes status back through the same VW.

EU and German government funding logos

Funded by the European Union – NextGenerationEU.

The views and opinions expressed are solely those of the author(s) and do not necessarily reflect the views of the European Union or the European Commission. Neither the European Union nor the European Commission can be held responsible for them.