Configuration¶
This page covers the manager's own configuration, the credential model, the add-on selector labels, and the cluster-wide policy knobs. The field-by-field CRD reference is auto-generated — see CRD API; every template variable is in Templates & variables.
Manager instance config¶
The manager reads two instance-level settings from its environment, sourced from the
capvco-credentials Secret in its namespace. They are deliberately independent — do not derive one
from the other (they differ on white-label deployments, and there's no fixed console./iam.
prefix):
| Env var | Secret key | Meaning | Example |
|---|---|---|---|
VCO_PORTAL_URL |
portalUrl |
whitesky.cloud portal base URL (without /api/1) |
https://<your-whitesky.cloud-portal> |
VCO_IAM_REFRESH_URL |
iamRefreshUrl |
IAM JWT-refresh endpoint | https://<your-iam-host>/v1/oauth/jwt/refresh |
Set these in the capvco-credentials Secret at
install time. Everything else
is per-cluster. The whitesky.cloud HTTP client uses
per-request deadlines (300 s default; up to 60 min for a VM-image import, which the platform serves
synchronously).
Nothing brand-specific is compiled in — the portal URL, IAM URL, customer id and credentials are all configuration, so one build serves any whitesky.cloud portal. You run one manager instance per portal.
Credential model¶
CAPVCO mints no credentials. Every VCOCluster references a Secret
(spec.credentialSecretRef, in the cluster's namespace) holding a client-supplied whitesky.cloud
credential (the Cluster API cluster-identity pattern). The controller uses it for all backend
operations for that cluster and injects it into the workload cluster for the add-ons — the manager
holds no standing credential.
Expected Secret keys:
| Key | Required | Meaning |
|---|---|---|
jwt |
yes | A self-refreshing whitesky.cloud JWT (carries a refresh_token claim). |
customer_id |
yes | The whitesky.cloud customer id. |
portal_url |
no | Per-cluster override of VCO_PORTAL_URL. |
iam_refresh_url |
no | Per-cluster override of VCO_IAM_REFRESH_URL. |
Rotating the Secret is picked up automatically (the client cache invalidates on the Secret's
resourceVersion), and the credentials injected into workload clusters are re-pushed on change. The
JWT refresh preserves scopes and cannot elevate them, so a narrowly-scoped credential stays
narrow.
Scope per cluster
Because one credential drives everything for a cluster (and is readable by that cluster's tenant admin), scope it to just what one cluster needs — see the RBAC caveat.
Operator-privileged operations¶
A few whitesky.cloud APIs are operator-privileged and return 403 for a per-cluster customer credential. They take a separate operator credential (same Secret shape):
| Operation | Field |
|---|---|
| VM-image publishing | spec.geo.imagePublishCredentialSecretRef |
| Registry TLS certificate (air-gapped) | spec.registry.certCredentialSecretRef |
DNS operations (geo endpoints, ExternalDNS, registry domains) work with the customer credential.
Injected workload Secrets¶
The controller writes these into the workload cluster as add-ons need them (a
ClusterResourceSet can't template per-cluster Secret data, so the controller injects them
directly):
| Secret (namespace) | Keys | For |
|---|---|---|
csi-driver-secret (csi-driver) |
client_jwt, customer_id |
The CSI driver (→ CSI_DRIVER_JWT, CUSTOMER_ID). |
vco-lb-credential (capvco-system) |
VCO_PORTAL_URL, VCO_IAM_REFRESH_URL, VCO_CUSTOMER_ID, VCO_JWT |
Service-LB / CCM / ExternalDNS webhook. |
An idempotent upsert of these Secrets is the rotation mechanism — when the source credential changes, the injected copies are re-pushed.
Add-on selector labels¶
Features are delivered as ClusterResourceSet add-ons selected by labels on the core CAPI
Cluster object (not the VCOCluster). All use the prefix
capvco.infrastructure.cluster.x-k8s.io/.
| Label | Value | Add-on |
|---|---|---|
…/cni |
calico |
CNI (Calico; veth_mtu pinned to 1350 so any cluster is geo/VPN-safe) |
…/csi |
vco |
whitesky.cloud CSI driver + StorageClasses |
…/csi-encryption |
openbao |
Key-backend config for encrypted volumes |
…/ccm |
enabled |
Cloud-controller-manager (node init + Service-LB) |
…/service-lb |
vco |
Standalone Service-LoadBalancer controller |
…/external-dns |
enabled |
ExternalDNS + the whitesky.cloud DNS webhook |
…/apiserver-proxy |
enabled |
Per-node internal-API proxy (geo) |
ccm and service-lb are mutually exclusive
Both run the Service-LB controller. Enable one, never both — see Load balancing.
The stock templates set the common labels for you; you only add labels to turn on optional add-ons.
Cluster-wide policy on VCOCluster.spec¶
Besides the per-feature subtrees (geo, backup, storage, registry — each covered in its
guide), a few cluster-wide knobs:
| Field | Default | Meaning |
|---|---|---|
controlPlaneExposure |
loadbalancer |
How :6443 is published: loadbalancer (HA) or portforward (single-CP). |
storage.credentialScope |
location |
How the CSI credential is scoped: location (the working default), perDisk, or cloudspace. See the RBAC caveat. |
driftPolicy |
(disabled) | Drift detection + orphan GC — see below. |
Drift policy¶
spec.driftPolicy periodically compares actual whitesky.cloud resources against desired and acts by
mode:
mode |
Behaviour |
|---|---|
Report (default) |
Detect + surface drift/orphans (condition, metric, events). Never changes the backend. |
Reconcile |
Additionally re-create/repair drifted resources still needed (detection + reporting today; repair incremental). |
GC |
Additionally delete orphans (resources whose owner is gone), subject to resources opt-in and dryRun. |
spec:
driftPolicy:
mode: GC
dryRun: true # log what GC would do, touch nothing
resources: ["vms"] # empty = GC nothing; destructive action is always narrow + explicit
dryRun: true and an empty resources list mean even GC mode does nothing destructive until you
opt in per resource type — a deliberate safety design.