Skip to content

Commit e4b5853

Browse files
joelanfordclaude
andcommitted
⚠ Single-tenant simplification: remove deprecated features and simplify operator model
Implement the single-tenant simplification design to re-affirm OLM v1's cluster-admin-only operational model. Changes across work items: - 01-cluster-admin: Grant operator-controller cluster-admin ClusterRole (remove custom RBAC rules) - 02-deprecate-service-account: Mark spec.serviceAccount as deprecated and optional; remove from docs/examples/tooling - 03-remove-preflight-permissions: Remove PreflightPermissions feature gate and RBAC pre-authorization code - 04-remove-synthetic-permissions: Remove SyntheticPermissions feature gate and synthetic user/group authentication - 07-simplify-contentmanager: Remove per-extension REST config and use shared manager client for content management - 09-documentation: Resolve merge conflicts, add cleanup tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4 parents 1b0a09d + 9a77787 + d88f76e + 6840525 commit e4b5853

File tree

33 files changed

+83
-3525
lines changed

33 files changed

+83
-3525
lines changed

Makefile

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,6 @@ lint-custom: custom-linter-build #EXHELP Call custom linter for the project
153153
lint-api-diff: $(GOLANGCI_LINT) #HELP Validate API changes using kube-api-linter with diff-aware analysis
154154
hack/api-lint-diff/run.sh
155155

156-
.PHONY: k8s-pin
157-
k8s-pin: #EXHELP Pin k8s staging modules based on k8s.io/kubernetes version (in go.mod or from K8S_IO_K8S_VERSION env var) and run go mod tidy.
158-
K8S_IO_K8S_VERSION='$(K8S_IO_K8S_VERSION)' go run hack/tools/k8smaintainer/main.go
159-
160156
.PHONY: tidy #HELP Run go mod tidy.
161157
tidy:
162158
go mod tidy
@@ -204,7 +200,7 @@ generate: $(CONTROLLER_GEN) #EXHELP Generate code containing DeepCopy, DeepCopyI
204200
$(CONTROLLER_GEN) --load-build-tags=$(GO_BUILD_TAGS) object:headerFile="hack/boilerplate.go.txt" paths="./..."
205201

206202
.PHONY: verify
207-
verify: k8s-pin kind-verify-versions fmt generate manifests update-tls-profiles crd-ref-docs update-registryv1-bundle-schema verify-bingo #HELP Verify all generated code is up-to-date. Runs k8s-pin instead of just tidy.
203+
verify: tidy kind-verify-versions fmt generate manifests update-tls-profiles crd-ref-docs update-registryv1-bundle-schema verify-bingo #HELP Verify all generated code is up-to-date.
208204
git diff --exit-code
209205

210206
.PHONY: verify-bingo

cmd/operator-controller/main.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ import (
5959
ocv1 "github.com/operator-framework/operator-controller/api/v1"
6060
"github.com/operator-framework/operator-controller/internal/operator-controller/action"
6161
"github.com/operator-framework/operator-controller/internal/operator-controller/applier"
62-
"github.com/operator-framework/operator-controller/internal/operator-controller/authorization"
6362
"github.com/operator-framework/operator-controller/internal/operator-controller/catalogmetadata/cache"
6463
catalogclient "github.com/operator-framework/operator-controller/internal/operator-controller/catalogmetadata/client"
6564
"github.com/operator-framework/operator-controller/internal/operator-controller/contentmanager"
@@ -598,12 +597,6 @@ func (c *boxcutterReconcilerConfigurator) Configure(ceReconciler *controllers.Cl
598597
return err
599598
}
600599

601-
// determine if PreAuthorizer should be enabled based on feature gate
602-
var preAuth authorization.PreAuthorizer
603-
if features.OperatorControllerFeatureGate.Enabled(features.PreflightPermissions) {
604-
preAuth = authorization.NewRBACPreAuthorizer(c.mgr.GetClient())
605-
}
606-
607600
// TODO: better scheme handling - which types do we want to support?
608601
_ = apiextensionsv1.AddToScheme(c.mgr.GetScheme())
609602
rg := &applier.SimpleRevisionGenerator{
@@ -616,7 +609,6 @@ func (c *boxcutterReconcilerConfigurator) Configure(ceReconciler *controllers.Cl
616609
Scheme: c.mgr.GetScheme(),
617610
RevisionGenerator: rg,
618611
Preflights: c.preflights,
619-
PreAuthorizer: preAuth,
620612
FieldOwner: fieldOwner,
621613
}
622614
revisionStatesGetter := &controllers.BoxcutterRevisionStatesGetter{Reader: c.mgr.GetClient()}
@@ -701,17 +693,6 @@ func (c *helmReconcilerConfigurator) Configure(ceReconciler *controllers.Cluster
701693
return fmt.Errorf("unable to create helm action client getter: %w", err)
702694
}
703695

704-
// determine if PreAuthorizer should be enabled based on feature gate
705-
var preAuth authorization.PreAuthorizer
706-
if features.OperatorControllerFeatureGate.Enabled(features.PreflightPermissions) {
707-
preAuth = authorization.NewRBACPreAuthorizer(
708-
c.mgr.GetClient(),
709-
// Additional verbs / bundle manifest that are expected by the content manager to watch those resources
710-
authorization.WithClusterCollectionVerbs("list", "watch"),
711-
authorization.WithNamespacedCollectionVerbs("create"),
712-
)
713-
}
714-
715696
cm, err := contentmanager.NewManager(c.mgr.GetConfig(), c.mgr.GetRESTMapper())
716697
if err != nil {
717698
setupLog.Error(err, "unable to create content manager")
@@ -726,15 +707,13 @@ func (c *helmReconcilerConfigurator) Configure(ceReconciler *controllers.Cluster
726707
return err
727708
}
728709

729-
// now initialize the helmApplier, assigning the potentially nil preAuth
730710
appl := &applier.Helm{
731711
ActionClientGetter: acg,
732712
Preflights: c.preflights,
733713
HelmChartProvider: &applier.RegistryV1HelmChartProvider{
734714
ManifestProvider: c.regv1ManifestProvider,
735715
},
736716
HelmReleaseToObjectsConverter: &applier.HelmReleaseToObjectsConverter{},
737-
PreAuthorizer: preAuth,
738717
Watcher: c.watcher,
739718
Manager: cm,
740719
}

docs/concepts/permission-model.md

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,23 @@
11
#### OLMv1 Permission Model
22

3-
> **Deprecated:** The permission model described below is no longer accurate.
4-
> operator-controller now runs with cluster-admin privileges and uses its own ServiceAccount
5-
> for all extension lifecycle operations. The `spec.serviceAccount` field on ClusterExtension
6-
> is deprecated and ignored.
3+
OLM v1's permission model is built on a simple principle: **operator-controller runs as cluster-admin**, and the security boundary is defined by who can create and modify `ClusterExtension` and `ClusterCatalog` resources.
74

8-
Here we aim to describe the OLMv1 permission model. OLMv1 itself does not have cluster-wide admin permissions. Therefore, each cluster extension must specify a service account with sufficient permissions to install and manage it. While this service account is distinct from any service account defined in the bundle, it will need sufficient privileges to create and assign the required RBAC. Therefore, the cluster extension service account's privileges would be a superset of the privileges required by the service account in the bundle.
5+
#### How It Works
96

10-
To understand the permission model, lets see the scope of the the service accounts associated with ClusterExtension deployment:
7+
1. **operator-controller** runs with `cluster-admin` privileges, giving it full authority to install and manage extension lifecycle resources (CRDs, Deployments, RBAC, etc.) on behalf of `ClusterExtension` objects.
8+
2. **Security is enforced via RBAC on the OLM APIs themselves.** Only cluster administrators should have `create`, `update`, or `delete` permissions on `ClusterExtension` and `ClusterCatalog` resources.
9+
3. **Creating a `ClusterExtension` is equivalent to having cluster-admin privileges**, because it instructs operator-controller to install arbitrary workloads and RBAC. Cluster administrators must not grant non-admin users write access to these APIs.
1110

12-
#### Service Account associated with the ClusterExtension CR
11+
#### Security Considerations
1312

14-
1) The ClusterExtension CR defines a service account to deploy and manage the ClusterExtension lifecycle and can be derived using the [document](../howto/derive-service-account.md). It is specified in the ClusterExtension [yaml](../tutorials/install-extension#L71) while deploying a ClusterExtension.
15-
2) The purpose of the service account specified in the ClusterExtension spec is to manage the cluster extension lifecycle. Its permissions are the cumulative of the permissions required for managing the cluster extension lifecycle and any RBAC that maybe included in the extension bundle.
16-
3) Since the extension bundle contains its own RBAC, it means the ClusterExtension service account requires either:
17-
- the same set of permissions that are defined in the RBAC that it is trying to create.
18-
- bind/escalate verbs for RBAC, see https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping
13+
!!! warning
14+
`ClusterExtension` and `ClusterCatalog` are **cluster-admin-only APIs**. Granting non-admin users
15+
`create`, `update`, or `delete` access on these resources is equivalent to granting them cluster-admin
16+
privileges.
1917

20-
#### Service Account/(s) part of the Extension Bundle
21-
1) The contents of the extension bundle may contain more service accounts and RBAC.
22-
2) The OLMv1 operator-controller creates the service account/(s) defined as part of the extension bundle with the required RBAC for the controller business logic.
18+
- Cluster admins must audit RBAC to ensure only trusted users can manage `ClusterExtension` and `ClusterCatalog` resources.
19+
- The rationale for this model is explained in the [Design Decisions](../project/olmv1_design_decisions.md) document.
2320

24-
##### Example:
21+
#### Extension Resources
2522

26-
Lets consider deployment of the ArgoCD operator. The ClusterExtension ClusterResource specifies a service account as part of its spec, usually denoted as the ClusterExtension installer service account.
27-
The ArgoCD operator specifies the `argocd-operator-controller-manager` [service account](https://github.com/argoproj-labs/argocd-operator/blob/da6b8a7e68f71920de9545152714b9066990fc4b/deploy/olm-catalog/argocd-operator/0.6.0/argocd-operator.v0.6.0.clusterserviceversion.yaml#L1124) with necessary RBAC for the bundle resources and OLMv1 creates it as part of this extension bundle deployment.
28-
29-
The extension bundle CSV contains the [permissions](https://github.com/argoproj-labs/argocd-operator/blob/da6b8a7e68f71920de9545152714b9066990fc4b/deploy/olm-catalog/argocd-operator/0.6.0/argocd-operator.v0.6.0.clusterserviceversion.yaml#L1091) and [cluster permissions](https://github.com/argoproj-labs/argocd-operator/blob/da6b8a7e68f71920de9545152714b9066990fc4b/deploy/olm-catalog/argocd-operator/0.6.0/argocd-operator.v0.6.0.clusterserviceversion.yaml#L872) allow the operator to manage and run the controller logic. These permissions are assigned to the `argocd-operator-controller-manager` service account when the operator bundle is deployed.
30-
31-
OLM v1 will assign all the RBAC specified in the extension bundle to the above service account.
32-
The ClusterExtension installer service account will need all the RBAC specified for the `argocd-operator-controller-manager` and additional RBAC for deploying the ClusterExtension.
33-
34-
**Note**: The ClusterExtension permissions are not propogated to the deployment. The ClusterExtension service account and the bundle's service accounts have different purposes and naming conflicts between the two service accounts can lead to failure of ClusterExtension deployment.
23+
operator-controller installs and manages all resources declared in an extension's bundle, including any ServiceAccounts, RBAC, Deployments, and other Kubernetes objects. These resources are distinct from operator-controller's own service account and are scoped to whatever the bundle declares.

docs/draft/howto/configure-bundles.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ metadata:
147147
spec:
148148
namespace: operators
149149
# No config provided = Operator watches the entire cluster (AllNamespaces)
150+
serviceAccount:
151+
name: global-operator-installer
150152
source:
151153
sourceType: Catalog
152154
catalog:

docs/draft/howto/rbac-permissions-checking.md

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)