A Kubernetes operator is a privileged non-human identity that runs continuously inside your cluster, and a badly scoped operator turns one compromised pod into cluster-wide control. Operators combine a controller, custom resource definitions (CRDs) and often admission or conversion webhooks, and each of those pieces needs its own permissions, network path and failure behaviour. This guide is for teams who write operators with Kubebuilder, Operator SDK or controller-runtime, and for platform teams who must decide whether to install third-party operators. It goes deeper than our Kubernetes Security Guide on one question: how to build and run controllers, CRDs and webhooks so that their access matches what they actually do.
This is an independent guide from NHI Mgmt Group, based on the Kubernetes project's public documentation as of November 2026. It is not sponsored or reviewed by the Kubernetes project. Product features change, so confirm settings against the Kubernetes project's current documentation.
Key takeaways
- The operator's service account is the real attack surface. Whatever its ClusterRole allows, anyone who compromises the operator pod, its image or its supply chain can do too.
- Some RBAC verbs are escalation paths, not permissions. Kubernetes documentation lists list and watch on Secrets, workload creation, escalate, bind, impersonate, serviceaccounts/token and webhook configuration control as privilege escalation risks.
- Prefer namespace scope and narrow caches. A namespace-scoped operator with a restricted manager cache limits both what it can read and what an attacker inherits.
- Validate in the CRD before you reach for a webhook. Kubernetes recommends CRD schema validation, CEL rules and defaulting over webhooks, and CEL-based admission policy where possible.
- Webhooks are availability and security dependencies. Timeouts, failurePolicy, scoping selectors and who can edit webhook configurations decide whether a webhook protects the cluster or breaks it.
What an operator is, and why it is a security boundary
The Kubernetes documentation describes operators as software extensions that use custom resources to manage applications and their components, following the control loop principle. In practice an operator consists of:
- CRDs: cluster-scoped API extensions that define the custom resource kinds users create.
- Controllers: reconciliation loops, usually in one Deployment, that watch custom resources and create or change native objects such as Deployments, Services, Secrets and RBAC objects.
- Webhooks (optional): mutating or validating admission webhooks and CRD conversion webhooks, served over TLS by the operator or a sidecar and called by the API server.
- Identity: a ServiceAccount bound to Roles or ClusterRoles, plus any external credentials the operator uses to reach cloud APIs, databases or secret stores.
Operators often need to create the very objects that Kubernetes treats as sensitive. A database operator creates Secrets with credentials; a certificate operator writes TLS keys; a platform operator may create RoleBindings for tenants. That makes the operator a high-value non-human identity. See the Kubernetes NHI Security Guide.
RBAC scoping for operators
Kubebuilder generates the operator's ClusterRole from +kubebuilder:rbac markers placed next to the controller code, which keeps permissions close to the code that uses them. The trade-off is that markers are easy to widen during development and rarely narrowed afterwards. Review the generated config/rbac/role.yaml as a security artefact in every pull request.
Escalation-prone permissions to challenge
| Permission | Why it is dangerous (Kubernetes RBAC good practices) | Narrower alternative |
|---|---|---|
get, list or watch on secrets | list and watch effectively reveal Secret contents, not just names | Namespaced Role; restrict the cache to labelled Secrets; use resourceNames for fixed names |
| create on Pods or workload resources | Grants access to Secrets, ConfigMaps and volumes mountable in the namespace and to every service account there | Limit to the operand namespace; enforce Baseline or Restricted Pod Security Standards there |
| create on PersistentVolumes | Allows hostPath volumes and therefore node filesystem access | Create PersistentVolumeClaims and let the storage provisioner create volumes |
escalate or bind on roles | Bypass the built-in protection that stops users granting rights they do not hold | Pre-create the Roles tenants need; let the operator bind only those by resourceNames |
impersonate | Gains the rights of other users or service accounts | Avoid entirely in operators |
create on serviceaccounts/token | Issues tokens for existing service accounts | Rely on projected tokens mounted by the kubelet |
create or update on certificatesigningrequests/approval for the kube-apiserver-client signer | Mints client certificates with arbitrary names, including system components | Use a dedicated signer and an external issuer with policy |
| write on validating or mutating webhook configurations | Controls webhooks that can read, and for mutating webhooks change, every admitted object | Install webhook configurations at deploy time, not from the running operator |
get on nodes/proxy | Reaches the kubelet API, including exec, bypassing audit logging and admission control; get is not read-only here | Never grant to an operator unless it is a node agent you fully trust |
| patch on Namespaces | Changing labels can relax Pod Security Admission or NetworkPolicy selection | Separate namespace provisioning from the operator |
Wildcards (*) on resources or verbs | Also cover resource types added to the cluster in future | Enumerate resources and verbs explicitly |
Scoping techniques
- Namespace-scoped operators: Operator SDK scaffolds a cluster-scoped operator by default, but documents converting it by setting
Cache.DefaultNamespaceson the manager so it watches and caches only named namespaces. Pair that with Roles and RoleBindings instead of a ClusterRole. Its guidance says cluster scope is right when the operator must watch resources created in any namespace, as a cluster-wide certificate issuer does. - Configurable watch namespaces: Operator SDK best practices say operators should not hard code the namespaces they watch and should make this configurable, which lets platform teams install with the narrowest scope.
- No self-registered CRDs: the same guidance says operators should not register their own CRDs, because CRDs are global and self-registration requires global privileges. Install CRDs through the deployment pipeline or Operator Lifecycle Manager.
- Own ServiceAccount, no root: operators should come with their own ServiceAccount, not rely on
default, and should not run as root unless absolutely necessary. - Split identities: if one part of the operator needs a powerful right (for example, binding Roles in tenant namespaces), run that controller under a separate service account so the rest of the code does not carry it.
- Isolate powerful pods: Kubernetes advises limiting the nodes that run powerful pods and keeping them away from untrusted or publicly exposed workloads using taints, tolerations and affinity rules.
See the Kubernetes RBAC Guide for the general model and the Kubernetes Service Account Token Guide for token handling.
Designing CRDs defensively
A CRD is the operator's public API, and every field a user can set is input to privileged code. Push validation into the API server where it is enforced consistently.
- Structural schemas:
apiextensions.k8s.io/v1requires a structural OpenAPI v3 schema. Violations are reported in the CRD'sNonStructuralcondition. Define types, required fields, enums, patterns, minimums and maximums for every field rather than accepting free-form objects. - CEL validation rules: the
x-kubernetes-validationsextension validates custom resources with Common Expression Language rules, including cross-field checks and transition rules usingoldSelfto make fields immutable. - Defaulting in the schema: set defaults in the CRD instead of a mutating webhook, as the Kubernetes webhook good practices recommend.
- Do not reflect privilege from the spec: fields such as image, serviceAccountName, hostNetwork, securityContext or arbitrary pod templates let any user who can create the custom resource ask the operator to create a privileged workload. Allow-list images and registries, fix the service account the operator assigns, and refuse privileged settings unless a separate, tightly bound field enables them.
- Cross-namespace references: a spec field that names a Secret or ConfigMap in another namespace lets a tenant read data through the operator's permissions. Resolve references only within the custom resource's own namespace unless an administrator has granted the reference explicitly.
- Status as the output channel: Operator SDK and Kubebuilder recommend writing meaningful status conditions. Keep secrets and tokens out of status and events, which many more users can read.
- Versioning and conversion: follow Kubernetes API versioning conventions, and use conversion webhooks when changing API versions so older stored objects are handled correctly.
Securing admission and conversion webhooks
Kubernetes recommends CEL-based admission control where possible and webhooks only when logic needs to be extensible or call external systems. ValidatingAdmissionPolicy is stable from Kubernetes v1.30. If you keep a webhook, the configuration fields carry most of the security and availability risk.
| Setting | Behaviour | Secure choice |
|---|---|---|
timeoutSeconds | Default 10 seconds; must be between 1 and 30; on timeout the failure policy applies | A small value, typically a few seconds, and webhook logic that responds in milliseconds |
failurePolicy | Default Fail rejects requests if the webhook errors | Ignore for mutating webhooks with a validating control that checks final state, as Kubernetes recommends; Fail only for validating webhooks that enforce security and run highly available |
namespaceSelector and objectSelector | Limit which objects are sent to the webhook | Exclude kube-system and the webhook's own namespace to avoid self-dependency and loops |
matchConditions | CEL filters, up to 64 per webhook, evaluated before calling the webhook | Filter to the requests you actually need to see |
sideEffects | Declares whether the webhook changes anything outside the admitted object | None, or NoneOnDryRun with dry-run handling |
caBundle and service TLS | API server verifies the webhook's certificate | Certificates issued and rotated automatically; never disable verification |
| API server authentication to the webhook | Configurable through AdmissionConfiguration and a kubeconfig file; newer releases can issue short-lived, scoped service account tokens for webhook calls | Authenticate the API server where the webhook endpoint is reachable from other workloads |
- Lock down who can edit webhooks: Kubernetes advises restricting create, update, patch, delete and deletecollection on MutatingWebhookConfigurations to trusted entities, and limiting who can change resources in the webhook server's namespace.
- Run webhooks highly available: multiple replicas behind a ClusterIP Service and a design that ignores events caused by Kubernetes reacting to outages, so node failures do not cascade into webhook timeouts.
- Mutate minimally and idempotently: patch only required fields, do not overwrite arrays, avoid self-mutation and do not rely on mutating webhook order; use a reinvocation policy if you need to see other plugins' changes.
- Protect the network path: NetworkPolicy should allow the webhook port only from the API server's address range where your platform supports it.
See the Kubernetes Admission Control Guide for cluster-wide policy design.
Runtime hardening of the controller
- Pod security: run the manager as non-root with a read-only root filesystem, dropped capabilities and a RuntimeDefault seccomp profile, in a namespace enforcing the Restricted Pod Security Standard.
- Protected metrics: Kubebuilder projects created with v4.1.0 or later serve metrics over HTTPS on port 8443 with authentication and authorisation enabled by default through controller-runtime's
WithAuthenticationAndAuthorizationfilter, and grant access through a metrics-reader ClusterRole. Keep that protection and use managed certificates rather than the self-signed default in production. - Leader election and least data: leader election needs Lease permissions in the operator's own namespace only. Restrict the manager's cache by label or field selectors so it does not hold every Secret in memory.
- External credentials: where the operator calls cloud APIs, use workload identity federation rather than static keys in Secrets. See the Workload Identity Federation Guide.
- Clean up: Operator SDK best practices ask operators to clean up the objects they create. Use owner references and finalizers so deleted custom resources do not leave orphaned Secrets or RBAC bindings behind.
- Supply chain: sign operator images, pin by digest, and generate an SBOM for each release; the operator image is effectively a cluster administrator binary.
Evaluating third-party operators
| Question | Good answer | Red flag |
|---|---|---|
| What does the ClusterRole grant? | Enumerated resources and verbs, namespaced where possible | Wildcards, or cluster-admin binding in the install manifest |
| Can watch namespaces be restricted? | Configurable single or multi-namespace mode | Cluster-wide only, with Secret list and watch |
| Who installs CRDs and webhooks? | The install pipeline or OLM | The operator registers them at runtime |
| Which custom resource fields reach pod specs? | A small, validated set; images allow-listed | Arbitrary pod templates passed through |
| How are webhooks configured? | Short timeout, scoped selectors, documented failure policy | Matches all resources in all namespaces with Fail |
| How are releases built and signed? | Signed images, SBOM, published security advisories | Mutable tags, no disclosure process |
Detection and measurement
Kubernetes audit logs record every request the operator's service account makes. Baseline them and alert on deviations. See the Kubernetes Audit Log Detection Guide.
- Unexpected verbs or resources: the operator service account calling APIs outside its generated role, being denied (403) repeatedly, or appearing from an IP or user agent other than its pod.
- Privilege changes: creation of ClusterRoleBindings or RoleBindings by an operator that does not normally create them, mapped to ATT&CK T1098.006 Additional Container Cluster Roles.
- Workload creation anomalies: pods created by the operator with images, service accounts or security contexts outside its normal pattern (T1610 Deploy Container), or privileged pods that could lead to T1611 Escape to Host.
- Webhook changes: any change to webhook configurations, failurePolicy or caBundle outside a release.
- Secret reads: list or watch of Secrets across namespaces by any operator, which may indicate credential harvesting through the API (T1552.007 Container API).
| Metric | Target |
|---|---|
| Operators bound to cluster-admin or wildcard roles | 0 |
| Operators with cluster-wide list or watch on Secrets | Only those with a documented exception |
| Webhooks without namespaceSelector excluding kube-system | 0 |
| Webhooks with timeoutSeconds above 10 | 0 |
| Operator role changes reviewed by security before merge | 100% |
Common failure patterns
- Development ClusterRole shipped to production: wildcard markers added to get past a permission error are never removed, so the operator holds rights to every current and future resource type.
- Operator-provisioned identities that are too powerful: operators often create service accounts for the workloads they manage. In the Kubeflow cryptomining attacks, attackers who reached exposed dashboards used the notebook's mounted service account, which by default could deploy containers in its namespace, to run cryptominers across tens of clusters.
- Webhook outage takes down the cluster: a validating webhook with failurePolicy Fail and no namespace exclusion blocks pod creation in
kube-systemwhen its own pods are rescheduled. - Pass-through pod templates: a custom resource field that accepts a full pod spec lets any user who can create the custom resource run privileged pods with the operator's permissions.
- Secrets in status or events: generated passwords or connection strings written to status fields, readable by everyone who can read the custom resource.
- Two operators, one CRD: Operator SDK guidance says only one operator should control a CRD; two controllers fighting over the same objects produce reconciliation loops and unpredictable security settings.
Framework mapping
| Framework | Reference | Operator relevance |
|---|---|---|
| NIST SP 800-53 Rev. 5 | AC-6, CM-7, SA-8, SA-11, AU-12 | Least privilege roles, least functionality, secure design and developer testing of controllers, audit record generation |
| NIST CSF 2.0 | PR.AA-05 | Permissions defined, enforced and reviewed with least privilege |
| MITRE ATT&CK v20 | T1098.006, T1610, T1611, T1552.007, T1609 | Cluster role abuse, container deployment, escape to host, credential access through the container API, container administration commands |
Practitioner checklist
- Review the generated operator role in every pull request and remove wildcards.
- Run namespace-scoped with a restricted manager cache unless cluster scope is genuinely required.
- Challenge every escalation-prone permission in the table above and document exceptions.
- Install CRDs and webhook configurations from the pipeline, never from the running operator.
- Validate custom resources with structural schemas and CEL rules; default in the schema.
- Allow-list images and refuse privileged pod settings arriving through custom resource fields.
- Configure webhooks with short timeouts, scoped selectors and a deliberate failure policy.
- Keep metrics behind authentication and authorisation, and secrets out of status and events.
- Baseline the operator's audit log behaviour and alert on new verbs, bindings and Secret reads.
- Apply the third-party evaluation table before installing any community operator.
Standards and references
- Kubernetes: Operator pattern
- Kubernetes: Role Based Access Control Good Practices
- Kubernetes: Admission Webhook Good Practices
- Kubernetes: Dynamic Admission Control
- Kubernetes: Extend the Kubernetes API with CustomResourceDefinitions
- Operator SDK: Operator Best Practices
- Kubebuilder: Metrics
- MITRE ATT&CK: Additional Container Cluster Roles
Related NHI Mgmt Group resources: Kubernetes Security Guide · Kubernetes RBAC Guide · Kubernetes Admission Control Guide · Kubernetes Cluster Compromise Playbook