Content Management that can withstand the plundering hoards

Website Operator

A Kubernetes controller that watches Website resources and reconciles them into infrastructure.

Responsibilities

For each Website, the operator creates or maintains:

Public frontend — public Ingress (example-public), ClusterIP Service, frontend Deployment (example-frontend), RWX published PVC (example-published) and ServiceAccount.

CMS backend — plain routing Ingress (example-cms, TLS offload only, no auth annotations), ClusterIP Service, CMS Deployment (example-cms), private PVC (example-private), the OAuth2/OIDC authentication Secret mount, ServiceAccount and the CMS status Role/RoleBinding (<site>-cms-status).

Generated NetworkPolicies are temporarily disabled. Reconciliation removes policies generated by previous operator versions.

Workload configuration is passed via environment variables (VIKING_*). Optional Ipseity integration additionally provisions retained client and cross-realm administrator ConfigMaps and a CMS auth Secret, and labels the Website namespace as an Ipseity realm.

Planned, not generated — HorizontalPodAutoscaler, PodDisruptionBudget and monitoring resources. Current generated site containers do not set CPU/memory requests/limits; platform admission policies and capacity planning must account for that. The core controller manifest does set its own requests/limits.

Reconciliation

Reconciliation is idempotent, safe to retry and resistant to partial failure. It must detect and handle missing PVCs, failed volume provisioning, invalid hostnames, hostname collisions, missing Secrets, Deployment failures, failed ingress configuration, insufficient replica availability, resource deletion and configuration changes. Unsupported ingress features must produce clear status conditions rather than silently insecure configurations.

CMS authentication (flattened CRD)

spec.cms.authentication is a single flattened reference (secretRef.name) to the Secret the CMS reads its OAuth2/OIDC client configuration from — there is no oauth2/basic mechanism node. The operator:

Ownership and deletion

Generated resources use Kubernetes owner references where appropriate. Persistent data is not destroyed automatically when a Website is deleted: the retention policy is Retain and PVCs must be removed manually. This describes retention of the claim objects; removing a claim can still delete its backing volume according to the PV/storage class reclaim policy. Ipseity namespace realm labels and all Ipseity ConfigMaps are also retained for manual administrator cleanup; these ConfigMaps have no Website owner references. Generated automatic authentication Secrets are removed, while explicitly referenced Secrets are untouched. Finalizers coordinate safe cleanup. See Security and Operations.

Permissions

RBAC follows least privilege; the operator must not require cluster-admin during normal operation. See deploy/02-operator-rbac.yaml (kept in sync with controller/config/rbac/cluster_role.yaml):

Status

The operator reports observed state through status conditions (Ready, FrontendReady, CMSReady, StorageReady, Published) and currentRelease, reflecting observed state rather than merely successful resource creation. Published=True is only reported when the published PVC is bound, the frontend Deployment is available and status.currentRelease is non-empty. The CMS writes the active release into status.currentRelease by PATCHing the websites/status subresource (granted by the generated <site>-cms-status Role); the operator reads that field. The legacy annotation cms.tlspu.com/current-release is no longer written by the CMS and is only read as a fallback when the status field is empty.

Operator runtime

controller/cmd/controller/main.go accepts:

Namespace model

The full flag/environment table is in configuration.

Website resources are namespace-scoped. Generated workloads live in the same namespace as their PVCs; cross-namespace PVC mounting is not supported. The initial implementation may host multiple websites in one namespace but must not assume all websites share a namespace.

With Ipseity integration, Websites sharing a namespace share its realm and administrator membership. Use separate namespaces for separate client realms.