From 751d34f8cd92a220130fea5df1a9e2e7d13a7ed4 Mon Sep 17 00:00:00 2001 From: "Per G. da Silva" Date: Thu, 12 Nov 2026 09:44:14 +0100 Subject: [PATCH] docs: align guidance with ClusterObjectDeployment runtime Refresh COS examples for the discriminated object schema and document content Secret naming, ownership, reuse, and lifetime in integrated and standalone deployments. Preserve the large-bundle proposal as historical material with a current-behavior summary. Clarify privileged COD/COS access and experimental compatibility guarantees. Update architecture, contributor and agent guidance, and sample selection to distinguish standard installations from the experimental object-controller runtime. Signed-off-by: Per G. da Silva --- AGENTS.md | 38 ++++++-- README.md | 8 +- config/README.md | 47 ++++++++- docs/contribute/developer.md | 89 +++++++++++++++-- docs/draft/concepts/clusterobjectsets.md | 95 ++++++++++++++----- docs/draft/concepts/large-bundle-support.md | 38 ++++++++ docs/howto/how-to-protect-olmv1-api-access.md | 46 ++++++++- docs/project/olmv1_architecture.md | 79 +++++++++++++-- docs/project/public-api.md | 16 +++- 9 files changed, 401 insertions(+), 55 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e8d4e73fa6..050552fc03 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,15 +8,27 @@ repository. It covers the WHAT, WHY, and HOW of contributing to this codebase. ## Architecture Overview operator-controller is the central component of Operator Lifecycle Manager (OLM) v1, extending Kubernetes with APIs to -install and manage cluster extensions. The project follows a microservices architecture with two main binaries: +install and manage cluster extensions. Standard installations run operator-controller and catalogd; +the experimental runtime adds an independently deployable object-controller binary: -**operator-controller** - - manages `ClusterExtension` and `ClusterObjectSet` CRDs +**operator-controller** + - reconciles `ClusterExtension` resources - resolves bundles from configured source - unpacks bundles and renders manifests from them - - applies manifests with phase-based rollouts + - applies rendered content through Helm in standard installations + - with `BoxcutterRuntime`, creates content Secrets owned by the ClusterExtension, applies a + `ClusterObjectDeployment`, and observes its rollout status - monitors extension lifecycle +**object-controller (experimental)** + - reconciles `ClusterObjectDeployment` (COD) and `ClusterObjectSet` (COS) resources + - creates immutable COS revisions from mutable COD templates, enforces deadlines, and prunes archived history + - applies revision content in phases and handles readiness, ownership handoff, archival, and teardown + - runs in its own Deployment with its own service account and leader-election lease + - can run without ClusterExtension or ClusterCatalog APIs or controllers + - reads immutable referenced Secrets directly in their declared namespaces; standalone callers manage their lifetime + - does not delete ClusterExtension-owned content Secrets when pruning COS history + **catalogd** - manages user-defined `ClusterCatalog` resources to make references catalog metadata available to the cluster. - unpacks and serves operator catalog content via HTTP. @@ -194,9 +206,11 @@ make generate-mocks ├── api/v1/ # API definitions (CRD types) ├── cmd/ # Main entry points │ ├── operator-controller/ # Operator controller binary +│ ├── object-controller/ # Experimental COD/COS controller binary │ └── catalogd/ # Catalogd binary ├── internal/ # Private implementation │ ├── operator-controller/ # Operator controller internals +│ ├── object-controller/ # COD/COS reconciliation and status │ ├── catalogd/ # Catalogd internals │ └── shared/ # Shared utilities ├── helm/ # Helm charts @@ -213,7 +227,7 @@ make generate-mocks │ └── regression/ # Regression tests ├── docs/ # Documentation (mkdocs) ├── hack/ # Scripts and tools -├── config/samples # Example manifests for ClusterCatalog and ClusterExtension +├── config/samples # ClusterCatalog, ClusterExtension, and experimental COD examples ├── manifests/ # Generated manifests ├── .github/workflows/ # CI/CD workflows ├── OWNERS # Defines approver and reviewer groups @@ -233,7 +247,8 @@ make generate-mocks - **Primary CRDs:** - `ClusterExtension` - declares desired extension installations - - `ClusterObjectSet` - revision management (experimental) + - `ClusterObjectDeployment` - mutable desired content, rollout policy, and revision management (experimental) + - `ClusterObjectSet` - immutable revision content and phased resource reconciliation (experimental) - `ClusterCatalog` - catalog source definitions - **API domain:** `olm.operatorframework.io` - This is the API group of our user-facing CRDs @@ -244,7 +259,7 @@ make generate-mocks Two manifest variants exist: - **Standard:** Production-ready features -- **Experimental:** Features under development/testing (includes `ClusterObjectSet` API) +- **Experimental:** Features under development/testing (includes `ClusterObjectDeployment` and `ClusterObjectSet` APIs) Experimental APIs may change incompatibly between releases. We do not provide migration support for experimental API changes. @@ -408,12 +423,17 @@ ScalarField string `json:"scalarField,omitempty"` ### Key Components to Understand **operator-controller:** -- `ClusterExtension` controller - manages extension installations -- `ClusterObjectSet` controller - manages revision lifecycle +- `ClusterExtension` controller - manages extension installations; with `BoxcutterRuntime`, owns a COD with the same name - Resolver - bundle version selection - Applier - applies manifests to cluster - Content Manager - manages extension content +**object-controller (experimental):** +- `ClusterObjectDeployment` controller - creates and owns COS revisions, reports rollout status, enforces deadlines, and prunes history +- `ClusterObjectSet` controller - applies immutable content in phases, tracks readiness/completion, and handles ownership handoff and teardown +- Integrated ownership: ClusterExtension → COD → COS → managed objects; content Secrets are owned directly by ClusterExtension +- Direct COD/COS write access delegates privileged resource deployment and is not constrained by ClusterExtension-only admission policies + **catalogd:** - Catalog controllers - manage catalog unpacking - Storage - catalog storage backend diff --git a/README.md b/README.md index 9fb5b6f3c6..830f7acfc1 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,13 @@ OLM v1 consists of the following components: * operator-controller * catalogd -* object-controller (experimental): manages `ClusterObjectSet` resources independently of `ClusterExtension` +* object-controller (experimental): reconciles mutable `ClusterObjectDeployment` templates and immutable `ClusterObjectSet` revisions, independently of `ClusterExtension` and `ClusterCatalog` + +Standard installations use operator-controller and catalogd. With the experimental +`BoxcutterRuntime` enabled, operator-controller resolves and renders bundles into +ClusterObjectDeployments; object-controller creates their revisions and reconciles +the managed resources in phases. Object-controller can also be deployed standalone. +See the [architecture](docs/project/olmv1_architecture.md) for component responsibilities. For a more complete overview of OLM v1 and how it differs from OLM v0, see our [overview](docs/project/olmv1_design_decisions.md). diff --git a/config/README.md b/config/README.md index 6fe4ab8892..3bc867725d 100644 --- a/config/README.md +++ b/config/README.md @@ -2,4 +2,49 @@ ## Samples -The `config/samples` directory contains example ClusterCatalog and ClusterExtension resources. +Select examples from `config/samples` according to the APIs and controllers installed +on your cluster. Run the commands below from the repository root. Do not apply the +whole directory: it also contains an experimental ClusterObjectDeployment sample. + +### Standard extension installation + +Install operator-controller and catalogd before applying these samples: + +| Sample | Contents | Prerequisites | +| --- | --- | --- | +| `catalogd_operatorcatalog.yaml` | The `operatorhubio` ClusterCatalog | ClusterCatalog CRD, running catalogd, and access to the catalog image registry | +| `olm_v1_clusterextension.yaml` | The `argocd` namespace and ClusterExtension | ClusterExtension CRD, running operator-controller, and a serving catalog containing the requested Argo CD bundle | + +```sh +kubectl apply -f config/samples/catalogd_operatorcatalog.yaml +kubectl wait --for=condition=Serving clustercatalog/operatorhubio --timeout=180s +kubectl apply -f config/samples/olm_v1_clusterextension.yaml +``` + +The ClusterExtension sample pins a specific version. Check that it is still +available in the chosen catalog and adjust the sample if needed. +`kubectl apply -k config/samples` selects only the ClusterExtension sample through +`kustomization.yaml`; it does not install a catalog or the experimental COD sample. + +### Experimental standalone deployment + +`olm_v1_clusterobjectdeployment.yaml` creates the `cod-example` namespace and a +ClusterObjectDeployment whose template contains a ConfigMap. It requires the +experimental COD and COS CRDs and a running object-controller. It does not require +ClusterExtension or ClusterCatalog APIs or controllers. + +Follow [Manage standalone ClusterObjectDeployments](../docs/draft/tutorials/manage-clusterobjectdeployments.md) +to build and install object-controller, apply the sample, and inspect revisions. +Use a test cluster and a fresh `cod-example` namespace/group; cleanup deletes the +sample namespace and its contents. Do not apply the sample to a standard +installation, which does not provide the COD/COS APIs. + +### Cleanup + +Delete the parent ClusterExtension or COD first so its controllers and Kubernetes +garbage collection can remove the owned resources. Keep the controllers running +until teardown completes. Remove a sample's namespace only after cleanup and only +if it contains no unrelated resources. See the +[extension uninstall guide](../docs/tutorials/uninstall-extension.md) and +[COD tutorial cleanup](../docs/draft/tutorials/manage-clusterobjectdeployments.md#clean-up) +for the respective workflows. diff --git a/docs/contribute/developer.md b/docs/contribute/developer.md index 909b653c55..00c738d9f0 100644 --- a/docs/contribute/developer.md +++ b/docs/contribute/developer.md @@ -16,7 +16,23 @@ First, you need to install the CRDs and the operator-controller into a new [KIND make run ``` -This will build a local container image of the operator-controller, create a new KIND cluster and then deploy onto that cluster. This will also deploy the catalogd and cert-manager dependencies. +This builds the controller images, creates a KIND cluster, and deploys OLMv1 with +cert-manager using the standard configuration. + +To develop with the experimental configuration instead, use: + +```sh +make run-experimental +``` + +The experimental configuration enables a collection of features, not just the +object-controller runtime. See the chart's +[standard defaults](https://github.com/operator-framework/operator-controller/blob/main/helm/olmv1/values.yaml) +and [experimental overrides](https://github.com/operator-framework/operator-controller/blob/main/helm/experimental.yaml) +for the current settings rather than relying on a separate feature list here. +For controller responsibilities, see [OLMv1 architecture](../project/olmv1_architecture.md). +For standalone object-controller development, see +[Manage standalone ClusterObjectDeployments](../draft/tutorials/manage-clusterobjectdeployments.md). ### To Install Any Given Release @@ -31,24 +47,83 @@ curl -L -s https://github.com/operator-framework/operator-controller/releases/la ``` ### Manual Step-by-Step Installation -1. Install Instances of Custom Resources: + +Run these commands from the repository root against a test cluster with +cert-manager installed and ready. The chart defaults to Linux control-plane nodes; +customize `deployments.templateSpec.nodeSelector` if the target cluster does not +have schedulable nodes with that label. The cluster must be able to pull the images +from your registry. + +The chart's `namespaces.certManager.name` must match cert-manager's **cluster +resource namespace** (its `--cluster-resource-namespace` setting), which is not +necessarily the namespace of its controller Deployment. The chart defaults to +`cert-manager` and creates its CA Certificate and Secret there. If cert-manager +uses another cluster resource namespace, set `CERT_MANAGER_NAMESPACE` in step 2 +accordingly; otherwise the ClusterIssuer cannot find the CA Secret and controller +certificates will not be issued. + +1. Build and push the standard controller images. Use a registry namespace you can + push to, and choose a new tag when rebuilding. + + `make docker-build` builds Linux binaries for the build host's `GOARCH` and + does not select a container target platform. Use a build host and container + builder whose architecture matches the cluster nodes that will run the + controllers (for example, `amd64` or `arm64`). If they differ, run this + workflow on a matching build host; overriding `GOARCH` alone is not enough. ```sh - kubectl apply -f config/samples/ + export IMAGE_REGISTRY='/' + export IMAGE_TAG='dev-1' + export CONTAINER_RUNTIME='docker' # Use podman on Podman-only hosts. + export OPCON_IMAGE_REPO="${OPCON_IMAGE_REPO:-$IMAGE_REGISTRY/operator-controller}" + export CATD_IMAGE_REPO="${CATD_IMAGE_REPO:-$IMAGE_REGISTRY/catalogd}" + make docker-build CONTAINER_RUNTIME="$CONTAINER_RUNTIME" IMAGE_REGISTRY="$IMAGE_REGISTRY" IMAGE_TAG="$IMAGE_TAG" + "$CONTAINER_RUNTIME" push "$OPCON_IMAGE_REPO:$IMAGE_TAG" + "$CONTAINER_RUNTIME" push "$CATD_IMAGE_REPO:$IMAGE_TAG" ``` -2. Build and push your image to the location specified by `IMG`: + Use the same container runtime for building and pushing so both commands use + the same local image store. Export any repository overrides in your shell + before running these steps; passing them only as `make` arguments does not + make them available to the push and Helm commands. + + `make docker-build` also builds object-controller. If your configuration enables + that component, push its image with the same runtime and configure + `options.objectController.deployment.image` in addition to the other images. + Its build repository can be overridden by exporting `OBJECT_CONTROLLER_IMAGE_REPO`. + +2. Render and apply the standard chart using your images, then wait for the + controllers to be ready: ```sh - make docker-build docker-push IMG=/operator-controller:tag + export CERT_MANAGER_NAMESPACE='cert-manager' # Match cert-manager's cluster resource namespace. + go tool helm template olmv1 helm/olmv1 \ + --values helm/cert-manager.yaml \ + --set-string namespaces.certManager.name="$CERT_MANAGER_NAMESPACE" \ + --set-string options.operatorController.deployment.image="$OPCON_IMAGE_REPO:$IMAGE_TAG" \ + --set-string options.catalogd.deployment.image="$CATD_IMAGE_REPO:$IMAGE_TAG" \ + > /tmp/olmv1-standard.yaml + kubectl apply -f /tmp/olmv1-standard.yaml + kubectl -n olmv1-system rollout status deployment/catalogd-controller-manager --timeout=180s + kubectl -n olmv1-system rollout status deployment/operator-controller-controller-manager --timeout=180s ``` -3. Deploy the controller to the cluster with the image specified by `IMG`: +3. Select the samples appropriate to the installed APIs: ```sh - make deploy IMG=/operator-controller:tag + kubectl apply -f config/samples/catalogd_operatorcatalog.yaml + kubectl wait --for=condition=Serving clustercatalog/operatorhubio --timeout=180s + kubectl apply -f config/samples/olm_v1_clusterextension.yaml ``` + Do not apply the entire `config/samples/` directory. The COD sample requires + the experimental COD/COS CRDs and a running object-controller, neither of + which is part of the standard installation above. Follow the + [standalone tutorial](../draft/tutorials/manage-clusterobjectdeployments.md) + to install that controller and exercise the COD sample. See the + [sample guidance](https://github.com/operator-framework/operator-controller/blob/main/config/README.md) + for prerequisites and cleanup. + ### Modifying the API definitions If you are editing the API definitions, generate the manifests such as CRs or CRDs using: diff --git a/docs/draft/concepts/clusterobjectsets.md b/docs/draft/concepts/clusterobjectsets.md index a9749c81c6..9bc75549ee 100644 --- a/docs/draft/concepts/clusterobjectsets.md +++ b/docs/draft/concepts/clusterobjectsets.md @@ -15,7 +15,7 @@ Each ClusterObjectSet has: - A **lifecycle state** — either `Active` (being reconciled) or `Archived` (inactive); transitions from Active to Archived but not back - A list of **phases** — immutable, ordered groups of Kubernetes objects that are applied sequentially - A **collision protection** strategy — immutable, controlling how pre-existing objects are handled -- **Status conditions** — reporting rollout progress, availability, and success +- A **Ready condition** — reporting resource reconciliation, with first rollout completion recorded separately in `status.completedAt` ClusterObjectSets can be used by any controller or system that needs to manage the rollout of a set of Kubernetes resources in a controlled, phased manner. Within OLM, when `BoxcutterRuntime` is enabled, operator-controller creates and updates a ClusterObjectDeployment (COD) for each ClusterExtension. The COD controller creates the immutable ClusterObjectSet revisions that deploy and upgrade the extension. @@ -142,7 +142,7 @@ Phase names follow the DNS label standard ([RFC 1123](https://tools.ietf.org/htm ### Phase ordering in operator-controller -When operator-controller creates a ClusterObjectSet for a ClusterExtension, it automatically assigns objects to phases based on their GroupKind: +When operator-controller renders a ClusterObjectDeployment template for a ClusterExtension, it automatically assigns objects to phases based on their GroupKind. The COD controller copies those phases into each COS revision: | Order | Phase | Resource Kinds | | --- | --- | --- | @@ -163,7 +163,7 @@ When operator-controller creates a ClusterObjectSet for a ClusterExtension, it a Any resource kind not listed above defaults to the `deploy` phase. !!! note - This phase ordering is specific to how operator-controller creates ClusterObjectSets. The API itself does not enforce any particular phase ordering — phases are applied in the order they appear in the `spec.phases` list. + This phase ordering is specific to how operator-controller renders COD templates. The APIs do not enforce any particular phase ordering — phases are applied in the order they appear in the template's `spec.phases` list. ## Readiness probes @@ -211,13 +211,13 @@ The available strategies are: ## Object storage: inline vs. references -Each object in a phase can be stored in one of two ways (exactly one must be set): +Each object in a phase must set `type` and its corresponding content field. Exactly one of `inlineManifest` or `secretRef` must be set: -`object` +`type: InlineManifest` with `inlineManifest` : The full Kubernetes manifest is embedded inline in the ClusterObjectSet. Simple and self-contained, but contributes to the overall size of the ClusterObjectSet resource in etcd. -`ref` -: A reference to a Secret that holds the serialized object manifest. The `ref` specifies the Secret name, namespace, and data key containing either a JSON-encoded manifest or gzip-compressed JSON bytes. This allows ClusterObjectSets to manage bundles that would otherwise exceed etcd's 1.5 MiB object size limit. +`type: SecretReference` with `secretRef` +: A reference to an immutable Secret that holds the serialized object manifest. The `secretRef` specifies the Secret name, namespace, and data key containing either a JSON-encoded manifest or gzip-compressed JSON bytes. This allows ClusterObjectSets to manage bundles that would otherwise exceed etcd's 1.5 MiB object size limit. Object-controller reads referenced Secrets directly from the API server in their declared namespaces. When operator-controller renders ClusterObjectDeployment templates for ClusterExtensions, it automatically externalizes objects into immutable Secrets: @@ -225,7 +225,24 @@ When operator-controller renders ClusterObjectDeployment templates for ClusterEx - Objects larger than 900 KiB are gzip-compressed before storage (ref resolution auto-detects and transparently decompresses gzip-compressed values so consumers see the original JSON manifest) - Content-addressable naming (based on SHA-256 hashes of the data) ensures that Secret names and data keys are deterministic, making creation idempotent and safe to retry -For a detailed design discussion, see [Large Bundle Support](large-bundle-support.md). +### Referenced Secret lifetime + +For ClusterExtension-managed deployments, operator-controller creates the referenced +Secrets before applying the COD. Each Secret is owned by the ClusterExtension, +not by the COD or an individual COS. Secret names use the extension name and a +content hash, so unchanged packed content can be reused across revisions. +Pruning archived COS revisions does not delete these Secrets; they are garbage +collected when the owning ClusterExtension is deleted. + +Standalone COD and COS callers manage the lifetime of their referenced Secrets. +Keep each Secret available for every retained revision that references it. Do not +assign a shared Secret exclusively to one COS if deleting that COS would remove +content still needed by other revisions. A content change requires a new Secret +reference, not an in-place edit to an immutable Secret. + +For historical design alternatives, see [Large Bundle Support](large-bundle-support.md). +The current behavior is described here and in the +[standalone COD tutorial](../tutorials/manage-clusterobjectdeployments.md#inspect-history-and-referenced-content). ## Status conditions @@ -312,7 +329,7 @@ metadata: ### Inline objects -This example shows a ClusterObjectSet with objects embedded directly in the spec. This is the simplest approach and works well when the total size of all objects stays within etcd's 1.5 MiB limit. +This example shows a ClusterObjectSet with objects embedded directly in the spec. This is the simplest approach and works well when the total size of all objects stays within etcd's 1.5 MiB limit. The first phase creates the `my-app-system` namespace before the namespaced resources in later phases. Replace the illustrative controller image with one available to your cluster. ```yaml apiVersion: olm.operatorframework.io/v1 @@ -325,9 +342,18 @@ spec: lifecycleState: Active collisionProtection: Prevent phases: + - name: namespaces + objects: + - type: InlineManifest + inlineManifest: + apiVersion: v1 + kind: Namespace + metadata: + name: my-app-system - name: crds objects: - - object: + - type: InlineManifest + inlineManifest: apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -350,13 +376,15 @@ spec: type: object - name: rbac objects: - - object: + - type: InlineManifest + inlineManifest: apiVersion: v1 kind: ServiceAccount metadata: name: my-app-controller namespace: my-app-system - - object: + - type: InlineManifest + inlineManifest: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -367,7 +395,8 @@ spec: verbs: ["get", "list", "watch", "create", "update", "delete"] - name: deploy objects: - - object: + - type: InlineManifest + inlineManifest: apiVersion: apps/v1 kind: Deployment metadata: @@ -391,15 +420,27 @@ spec: ### Secret references -This example shows a ClusterObjectSet that references objects stored in Secrets. This is how operator-controller creates ClusterObjectSets, and is necessary when managing bundles with large resources like CRDs with extensive schemas. +This example shows a ClusterObjectSet that references objects stored in Secrets. +Operator-controller uses the same reference mechanism in COD templates, which the +COD controller copies into COS revisions. It is necessary when managing bundles +with large resources like CRDs with extensive schemas. + +For ClusterExtension-managed content, Secret names are content-addressable, +computed as `-<16 hex chars>` where the suffix is the first 8 bytes +of a SHA-256 digest over the Secret's sorted keys and values. Each data key is a +43-character base64url-encoded (no padding) SHA-256 hash of the stored object bytes. -Object manifests are stored in immutable Secrets. Secret names are content-addressable, computed as `-<16 hex chars>` where the suffix is the first 8 bytes of a SHA-256 digest over the Secret's sorted keys and values. Each data key is a 43-character base64url-encoded (no padding) SHA-256 hash of the stored object bytes. +The following Secrets and hashes are illustrative placeholders, not a runnable +manifest. Standalone callers may choose their own Secret names. These examples +omit owner references; a standalone producer is responsible for their cleanup. +Operator-controller instead sets a controller owner reference to the +ClusterExtension, as described in [Referenced Secret lifetime](#referenced-secret-lifetime). ```yaml apiVersion: v1 kind: Secret metadata: - name: my-app-1-3a7f1b9c0e2d4f68 + name: my-app-3a7f1b9c0e2d4f68 namespace: olmv1-system immutable: true data: @@ -410,7 +451,7 @@ data: apiVersion: v1 kind: Secret metadata: - name: my-app-1-8b2e4a6c1d3f5097 + name: my-app-8b2e4a6c1d3f5097 namespace: olmv1-system immutable: true data: @@ -435,24 +476,28 @@ spec: phases: - name: crds objects: - - ref: - name: my-app-1-3a7f1b9c0e2d4f68 + - type: SecretReference + secretRef: + name: my-app-3a7f1b9c0e2d4f68 namespace: olmv1-system key: "K8sTl2xQa0vNpR7mW4dYcJfHbE9gUiAoZX1sDj6wFCy" - name: rbac objects: - - ref: - name: my-app-1-8b2e4a6c1d3f5097 + - type: SecretReference + secretRef: + name: my-app-8b2e4a6c1d3f5097 namespace: olmv1-system key: "Pm5tRqLwXv8sCj3kFdNhYe7bUiA0oZG1x2W9acDfHJy" - - ref: - name: my-app-1-8b2e4a6c1d3f5097 + - type: SecretReference + secretRef: + name: my-app-8b2e4a6c1d3f5097 namespace: olmv1-system key: "Vn4mTsLwXp8rCk3jFdNhYe7bUiA0oZG1x2W9acDfHQy" - name: deploy objects: - - ref: - name: my-app-1-8b2e4a6c1d3f5097 + - type: SecretReference + secretRef: + name: my-app-8b2e4a6c1d3f5097 namespace: olmv1-system key: "Bq9nRtLxYw2sDk4lGePhZf8cVjB1pUiA0oZH3x5WaCdy" ``` diff --git a/docs/draft/concepts/large-bundle-support.md b/docs/draft/concepts/large-bundle-support.md index bef7b0219f..1a12a3e3c2 100644 --- a/docs/draft/concepts/large-bundle-support.md +++ b/docs/draft/concepts/large-bundle-support.md @@ -1,5 +1,43 @@ # Design: Large Bundle Support +!!! warning "Historical proposal — not the current API contract" + + The proposal below is preserved to explain the alternatives considered. Its + API fields, Secret ownership and naming, creation sequence, and cache behavior + describe an earlier design and must not be used as current implementation or + installation guidance. The Secret-chain alternative was not implemented. + +## Current implementation + +The experimental runtime uses per-object references with `type: SecretReference` +and `secretRef`, or inline content with `type: InlineManifest` and +`inlineManifest`. See [Object storage](clusterobjectsets.md#object-storage-inline-vs-references) +for current field names and semantics. + +For ClusterExtension-managed content, operator-controller: + +1. Renders the desired content into a ClusterObjectDeployment (COD) template. +2. Packs object manifests into immutable, content-addressed Secrets named + `-<16 hex chars>`. Names depend on packed content, not a COS + revision number, so unchanged packed content can be shared across revisions. +3. Creates these Secrets with controller owner references to the ClusterExtension + before applying the COD. It does not wait for a COS UID or patch COS ownership + onto the Secrets. +4. Applies the COD; object-controller creates its immutable COS revisions and reads + their referenced Secrets directly from the API server in the declared namespaces, + without caching unrelated Secrets. + +Pruning archived COS history does not delete these ClusterExtension-owned Secrets. +They are garbage collected when the ClusterExtension is deleted. Standalone COD +and COS callers manage their own referenced Secret lifetime and must retain content +needed by any retained revision. See +[Referenced Secret lifetime](clusterobjectsets.md#referenced-secret-lifetime) and +[the standalone tutorial](../tutorials/manage-clusterobjectdeployments.md#inspect-history-and-referenced-content). + +## Historical design and alternatives + +Everything below this heading is historical proposal text, including the examples. + ## Need ClusterObjectSet (COS) objects embed full Kubernetes manifests inline in diff --git a/docs/howto/how-to-protect-olmv1-api-access.md b/docs/howto/how-to-protect-olmv1-api-access.md index 8241b3b20a..fa14f6b00a 100644 --- a/docs/howto/how-to-protect-olmv1-api-access.md +++ b/docs/howto/how-to-protect-olmv1-api-access.md @@ -1,12 +1,50 @@ # Protecting OLMv1 API Access -By default, only cluster administrators have permission to read, create, modify, or delete `ClusterExtension` and `ClusterObjectSet` resources. No other users or groups have any access to these APIs unless explicitly granted by a cluster administrator. +By default, only cluster administrators have permission to read, create, modify, or delete `ClusterExtension` resources and, when the experimental APIs are installed, `ClusterObjectDeployment` (COD) and `ClusterObjectSet` (COS) resources. No other users or groups have any access to these APIs unless explicitly granted by a cluster administrator. -Because the operator-controller runs with `cluster-admin` privileges, any user granted write access to the `ClusterExtension` API is effectively being delegated cluster-admin trust. Cluster administrators are generally discouraged from delegating this access to non-admin users. If delegation is necessary, the controls described below can help limit the scope of what delegated users can do. +Because operator-controller runs with `cluster-admin` privileges, any user granted write access to the `ClusterExtension` API is effectively being delegated cluster-admin trust. Cluster administrators are generally discouraged from delegating this access to non-admin users. If delegation is necessary, the controls described below can help limit the scope of what delegated users can do. + +!!! warning "Direct access to experimental rollout APIs" + + The experimental object-controller also runs with `cluster-admin` privileges + by default and can apply arbitrary Kubernetes resources from COD templates or + COS revisions. Write access to either API delegates that trust directly; it is + not limited to installing catalog content or namespaced objects. + + Admission policies that match only `ClusterExtension` do not constrain direct + COD or COS submissions. Catalog and package allowlists, installation namespace + restrictions, and ClusterExtension preflight settings do not protect this path. + Do not grant lower-level API write access to users whose installations are + intended to be constrained through ClusterExtension policies. ## RBAC -If you must delegate `ClusterExtension` access to non-admin users, start by assigning narrowly scoped roles: +If you must delegate `ClusterExtension` access to non-admin users, start by assigning narrowly scoped roles. The installer role below grants writes only to ClusterExtensions; operator-controller and object-controller use their own service accounts to manage the underlying CODs and COSs. Users do not need write access to those APIs to request an extension installation. + +The viewer role below includes read-only access to CODs and COSs for diagnosing +experimental rollouts. Remove those resources from the viewer role if that +visibility is unnecessary. + +!!! warning "Avoid sensitive information in COD/COS" + + Shipping credentials, tokens, private keys, or other sensitive values through + COD templates or COS revision content is not recommended. These APIs are + rollout mechanisms, not a secret-distribution channel. + + Inline manifests can include `kind: Secret`. Users with `get`, `list`, or + `watch` access to a COD or COS can read those embedded Secret values even + without permission to read Kubernetes Secrets. Base64 encoding is not + encryption, and immutable COS revisions can retain old values after the COD + template is updated. + + Keep sensitive values in separately managed Kubernetes Secrets with + appropriately restricted access, and have workloads reference those Secrets + rather than embedding their values in rollout content. The object-storage + `secretRef` mechanism externalizes manifests; it is not a recommendation to + distribute sensitive information through COD/COS. + + Grant the viewer role below only to users trusted to read all inline content + stored in the CODs and COSs it exposes. ### ClusterRole ```yaml @@ -19,6 +57,7 @@ rules: - olm.operatorframework.io resources: - clusterextensions + - clusterobjectdeployments - clusterobjectsets verbs: - get @@ -34,7 +73,6 @@ rules: - olm.operatorframework.io resources: - clusterextensions - - clusterobjectsets verbs: - create - update diff --git a/docs/project/olmv1_architecture.md b/docs/project/olmv1_architecture.md index 09889cc8db..c974a3ca07 100644 --- a/docs/project/olmv1_architecture.md +++ b/docs/project/olmv1_architecture.md @@ -5,12 +5,28 @@ hide: ## OLM v1 Architecture -This document provides an overview of the architecture of OLM v1, which consists of two primary components: +A standard OLM v1 installation consists of two primary components: -1. [operator-controller](https://github.com/operator-framework/operator-controller) -2. [catalogD](https://github.com/operator-framework/operator-controller/tree/main/catalogd) +1. [operator-controller](https://github.com/operator-framework/operator-controller/tree/main/cmd/operator-controller) +2. [catalogd](https://github.com/operator-framework/operator-controller/tree/main/cmd/catalogd) -The diagram below visually represents the architecture of OLM v1, followed by descriptions of each component and its role within the system. +An optional third component, +[object-controller](https://github.com/operator-framework/operator-controller/tree/main/cmd/object-controller), +reconciles `ClusterObjectDeployment` (COD) and `ClusterObjectSet` (COS) resources. +The experimental `BoxcutterRuntime` uses this component for extension rollouts. +Object-controller can also be deployed independently, without operator-controller, +catalogd, or their APIs. + +This page describes the core controller architecture, not an exhaustive list of +experimental features. For the current feature-gate configuration, see the chart's +[standard defaults](https://github.com/operator-framework/operator-controller/blob/main/helm/olmv1/values.yaml) +and [experimental overrides](https://github.com/operator-framework/operator-controller/blob/main/helm/experimental.yaml). +Experimental runtime details below describe the current implementation and may +change; see the [API stability policy](public-api.md#experimental-apis-and-fields). + +The diagram below shows catalog and bundle discovery, which is shared by both +runtimes. The [experimental rollout flow](#object-controller-experimental) describes +how object-controller deploys the rendered content. ### Architecture Diagram @@ -65,14 +81,16 @@ The `operator-controller` is the core component of OLM v1. Its responsibilities - Managing a cache of catalog metadata provided by catalogD through its HTTP server. - Ensuring the catalog metadata cache is kept up-to-date with the latest catalog state. - Identifying the appropriate `registry+v1` bundle that meets the constraints defined in the `ClusterExtension` resource (e.g., package name, version, channel) based on the cluster's current state. -- Unpacking and applying bundle manifests (e.g., installing or updating the operator). +- Unpacking bundles and rendering their manifests. +- Applying rendered manifests through the Helm-based runtime in standard installations, or applying a COD template and observing its rollout when `BoxcutterRuntime` is enabled. The operator-controller has three key sub-components: 1. **Cluster Extension Controller**: - Queries catalogD (via its HTTP server) to retrieve catalog information. - Saves catalog information in the catalog cache and automatically updates the cache if a catalog has a new image reference. - - Downloads bundle container images from the registry, saves them to the bundle cache, unpacks them, and applies the bundle manifests to the cluster. + - Downloads bundle container images from the registry, saves them to the bundle cache, and unpacks and renders their manifests. + - In the standard runtime, applies the rendered content through Helm. With `BoxcutterRuntime`, creates immutable content Secrets and applies a COD; object-controller handles the phased rollout. - Handles bundle upgrades by determining which bundle is the correct one to apply. 2. **Resolver**: @@ -98,3 +116,52 @@ catalogd has three main sub-components: 3. **CatalogD Content Cache**: - A cache maintained by the Catalog Controller that stores unpacked catalog data, which the CatalogD HTTP Server uses to respond to client queries. + +--- + +### object-controller (experimental) + +Object-controller separates mutable deployment intent from immutable resource +revisions. It runs in its own Deployment with its own service account and +leader-election lease. The Helm chart enables it alongside operator-controller +when `BoxcutterRuntime` is enabled; standard installations do not enable it. + +It contains two controllers: + +1. **ClusterObjectDeployment Controller**: + - Creates and owns immutable COS revisions from a mutable COD template. + - Reports deployment availability and rollout progress, enforces rollout + deadlines, and prunes excess archived revision history. + +2. **ClusterObjectSet Controller**: + - Applies a revision's objects in ordered phases using server-side apply. + - Evaluates readiness and records the revision's first successful completion. + - Handles object ownership handoff between revisions, archival, and teardown. + +With `BoxcutterRuntime`, the resource ownership chain is: + +```mermaid +flowchart LR + CE[ClusterExtension] -->|owns| COD[ClusterObjectDeployment] + COD -->|owns| COS[ClusterObjectSet revisions] + COS -->|owns| Objects[Managed Kubernetes objects] + CE -->|owns| Secrets[Immutable content Secrets] + COS -.->|reads content from| Secrets +``` + +Operator-controller resolves the bundle, renders its content, creates the +ClusterExtension-owned Secrets, and applies the COD. Object-controller reconciles +COD and COS resources without performing bundle resolution or querying catalogs. +Operator-controller observes COD status to report the ClusterExtension's progress +and installation state. Pruning COS history does not delete the content Secrets; +those are garbage collected when their owning ClusterExtension is deleted. + +For standalone use, callers submit COD templates or COS revisions directly and +manage the lifetime of any referenced content Secrets themselves. The default +object-controller service account has cluster-admin privileges because it manages +arbitrary Kubernetes resources. + +See [ClusterObjectDeployments](../draft/concepts/clusterobjectdeployment.md), +[ClusterObjectSets](../draft/concepts/clusterobjectsets.md), and the +[standalone tutorial](../draft/tutorials/manage-clusterobjectdeployments.md) +for the experimental API contracts and installation instructions. diff --git a/docs/project/public-api.md b/docs/project/public-api.md index 687c14a2a5..83ffe948b5 100644 --- a/docs/project/public-api.md +++ b/docs/project/public-api.md @@ -7,5 +7,17 @@ The public API of OLM v1 is as follows: !!! warning - Only what is mentioned in the above documentation references is considered part of the public API - and follows SemVer. Anything not mentioned in the above references is prone to breaking changes. + Only the stable APIs described in the above references carry SemVer + compatibility guarantees. Anything not mentioned in those references is prone + to breaking changes. + +## Experimental APIs and fields + +The API reference documents both standard and experimental functionality. Inclusion +in that reference does not make an experimental API or field stable, even when it +uses the `olm.operatorframework.io/v1` API version. + +Experimental APIs, including `ClusterObjectDeployment` and `ClusterObjectSet`, and +fields marked as experimental may change incompatibly between releases. Migration +support is not provided for experimental API changes. Stable APIs retain their +compatibility guarantees, including for supported production upgrades and migrations.