Skip to main content
The Ops Playbook

Making Next-Gen Cloud-Native Primitives Repeatable with Kubernetes

Design a reversible, RBAC-scoped Kubernetes CRD and controller pattern to turn recurring operational tasks into repeatable, auditable primitives.

Making Next-Gen Cloud-Native Primitives Repeatable with Kubernetes
Elliot WardElliot Ward8 min readTier L115 min

This playbook covers

Share

#Current Method

Most Kubernetes

clusters accumulate recurring operational work that never gets expressed inside the cluster’s own control plane: certificate rotations, scheduled maintenance windows, scaling policies, or backup triggers. In practice these tasks are usually driven by ad hoc scripts, manual kubectl edit sessions, or external CI jobs that hold a long-lived kubeconfig outside the cluster’s normal trust boundary. Each of these paths bypasses the declarative reconciliation model that Kubernetes itself uses for workloads, and each one authenticates and authorises differently, which fragments the audit trail.

The documented Kubernetes security model separates concerns across the control plane, workloads, authentication, authorisation and policy controls, as described in Kubernetes’ own security documentation. Ad hoc automation typically sits awkwardly across all four: a script may authenticate with a broad kubeconfig, act with whatever RBAC that identity happens to hold, and change workload state without passing through any admission policy that governs objects created through the API server in the normal way. The result is drift between what the cluster believes is true and what has actually been applied, inconsistent recovery procedures between teams, and an audit trail that depends on whoever remembered to log their change.

Three assumptions are worth stating openly before any redesign: the reader controls a Kubernetes cluster with permission to install cluster-scoped objects such as CustomResourceDefinitions; the reader is working in an isolated or non-production validation environment, per the assignment’s prerequisite; and the exact Kubernetes version and RBAC configuration in the reader’s own environment has not been verified here and must be confirmed locally before any command in this playbook is run against a real cluster.

#Improved Workflow

The workflow below turns one recurring operational task into a native Kubernetes primitive: a CustomResourceDefinition (CRD) describing the desired end state, plus a narrowly scoped controller that reconciles it. Once the pattern exists as a primitive, every future instance of that operational task is created, audited and recovered the same way as any other Kubernetes object – through the API server, under RBAC, subject to admission control

, and visible in kubectl get events.

  • Define the schema (CRD). Input: a plain description of the desired end state for the recurring task. Output: a validated custom resource type stored in etcd via the API server, versioned like any other object. Trade-off: schema design work up front, in exchange for a single reconciled source of truth instead of scattered scripts.
  • Scope the operator’s RBAC. Input: the exact verbs and resources the controller needs. Output: a Role and RoleBinding limited to a single service account. Trade-off: more setup steps than a broad ClusterRole, in exchange for a materially smaller blast radius if the controller is compromised or misconfigured.
  • Enforce an admission policy. Input: the guardrail conditions the object must satisfy. Output: objects that fail the policy are rejected before persistence rather than discovered later. Trade-off: a small amount of write latency, in exchange for consistent enforcement that does not depend on every author remembering the rule.
  • Deploy the controller and create one instance. Input: the packaged reconciler and one real, low-risk example of the recurring task. Output: an observable reconcile loop and an auditable object lifecycle. Trade-off: initial validation effort, in exchange for a repeatable pattern with near-zero marginal setup cost for the next instance.

#Implementation

The steps below assume a validation cluster, the two assignment prerequisites, and that the reader authors both the CRD and the reconciliation logic. Confirm each stage’s evidence before moving to the next; stop and escalate rather than forcing a change through if evidence is missing.

  1. Confirm context and version. Run kubectl config current-context and kubectl version --short. Expected evidence: a context name that clearly identifies a non-production cluster, and a version you can cross-check against your own change record. Stop condition: if the context matches a production naming convention, switch context before continuing.
  2. Confirm least-privilege permissions. Run kubectl auth can-i create customresourcedefinitions --as=system:serviceaccount:<namespace>:<operator-sa> for the specific identity that will run the change. Stop condition: if a narrow service account unexpectedly returns yes, review the RoleBinding before proceeding.
  3. Validate the schema without persisting it. Run kubectl apply --dry-run=server -f primitive-crd.yaml. Stop condition: resolve any schema error locally; never force the apply.
  4. Install the CRD. Run kubectl apply -f primitive-crd.yaml. Expected evidence: kubectl get crd <name> shows Established: True. Keep the manifest under version control so the rollback in Recovery has an exact source to reapply against.
  5. Bind least-privilege RBAC. Run kubectl apply -f operator-rbac.yaml. Expected evidence: kubectl auth can-i against the operator service account returns yes only for the intended verbs and resource.
  6. Deploy the controller. Confirm with kubectl rollout status deployment/primitive-controller -n <validation-namespace>.
  7. Create one instance and observe reconciliation. Apply a single, low-risk instance. Expected evidence: kubectl logs deploy/primitive-controller -n <validation-namespace> --tail=50 shows the controller reaching its expected reconciled state.

#Guardrails

  • Bind the controller’s service account to a Role scoped to the new custom resource and strictly necessary supporting resources – never a ClusterRole with broad or wildcard verbs.
  • Enforce admission control so invalid or unsafe specs are rejected before they reach etcd, not after.
  • Restrict primitive instances to a dedicated validation namespace during the pilot to contain the blast radius of misconfiguration.
  • Confirm the cluster’s audit policy captures create, update and delete events for the new resource type before relying on it as evidence.
  • Never place credentials or connection secrets inside the custom resource’s spec; use a bound service account token or an external secret reference.
A detailed shot of a white gaming controller on a desk surface, perfect for tech and gaming themes.
Photo by Mahavir Shah on Pexels

#Validation

Treat the pilot primitive as unproven until each of the following is independently confirmed, not assumed from a successful apply.

  • The CRD reports Established: True and rejects a deliberately malformed test object.
  • The operator’s service account passes kubectl auth can-i for its intended verbs and fails it for an unrelated resource type.
  • The admission policy rejects a test object missing a required guardrail field, with a clear error rather than a silent pass.
  • The controller’s logs show a completed reconcile cycle for the pilot instance, with no repeated error or backoff pattern.
  • kubectl get events shows the create event attributed to the correct identity.

#Common Mistakes

These are recommendations drawn from how this pattern typically fails in practice, not incident data specific to this exercise.

  • Granting the controller’s service account cluster-admin to get it working quickly, then never narrowing it before wider rollout.
  • Applying the CRD directly without a server-side dry run, turning a schema mistake into a persisted object needing separate clean-up.
  • Treating the custom resource as a disposable convenience rather than a version-controlled definition, losing the drift detection that justified building the primitive.
  • Deploying the controller without a resource request or limit, so it is evicted under memory pressure and silently stops reconciling.

#Recovery

Recovery is scoped to the isolated validation environment described in the prerequisites. Do not apply any delete step below against a cluster or namespace holding an object you did not create for this exercise.

#
Schema validation failure

Symptom: kubectl apply returns a schema validation error and nothing is created. Likely cause: a malformed OpenAPI schema. Diagnostic evidence: the exact error text from the dry run. Bounded correction: fix the schema locally and re-run the dry run until it passes cleanly. Rollback: none required – the dry run never persisted anything. Post-recovery verification: the dry run and real apply both succeed.

Close-up view of a modern gaming controller, highlighting joystick and buttons with a 'shield' design.
Photo by Johnny Mckane on Pexels

#
Controller crash-loop after deployment

Symptom: the controller pod shows CrashLoopBackOff. Likely cause: a missing RBAC verb or an incorrectly mounted service account token. Diagnostic evidence: kubectl logs --previous and kubectl describe pod. Bounded correction: patch only the missing verb and restart the deployment. Rollback: revert to the version-controlled RBAC manifest and re-diagnose before retrying. Post-recovery verification: the pod reaches Running and logs show a completed reconcile.

#
CRD scope mismatch

Symptom: instances appear outside the intended validation namespace. Likely cause: the CRD was defined with cluster scope instead of namespaced scope. Diagnostic evidence: kubectl get crd <name> -o jsonpath='{.spec.scope}'. Bounded correction: scope cannot be changed in place; a corrected namespaced definition must be reapplied. Rollback: because the CRD and instances exist solely for this exercise, remove them via the version-controlled manifests after confirming no other workload depends on them, then redeploy the namespaced version. Post-recovery verification: instances are confined to the intended namespace. Escalation: if another workload has already begun consuming the incorrectly scoped resource, stop and escalate before deleting anything.

#Measurable Outcome

  • Baseline: record how the task was previously performed – manual edits or ungoverned script runs in a fixed prior period, and whether each left an attributable audit event.
  • Success signal: the proportion of new task instances created as reconciled custom resources rather than out-of-band changes.
  • Measurement method: review kubectl get events and the cluster audit log for the pilot namespace on a fixed schedule.
  • Review cadence: weekly during the pilot, moving to fortnightly once stable.
  • Decision threshold: treat the pattern as ready for wider adoption only once a full review cycle shows zero manual out-of-band edits and complete audit coverage for the pilot task.

#Kubernetes Primitive Adoption Checklist

  • Non-production validation environment confirmed before any command was run.
  • Kubernetes version and the target identity’s permissions confirmed, not assumed.
  • CRD passed a server-side dry run before being applied.
  • Operator service account scoped to minimum verbs, verified with kubectl auth can-i.
  • Admission policy tested against at least one deliberately invalid object.
  • Controller reconcile cycle observed and logged for the pilot instance.
  • Rollback path rehearsed against version-controlled manifests, not improvised.
  • Audit log coverage confirmed for create, update and delete events.
  • Review cadence and decision threshold agreed before rollout beyond the pilot namespace.
Elliot Ward

Elliot Ward

Ops Playbook Architect

Elliot Ward is an Identity and Endpoint Engineer specialising in secure access control and Microsoft 365 environments.

Published
View Profile
Reader Interaction

Comments

Add a thoughtful note on Making Next-Gen Cloud-Native Primitives Repeatable with Kubernetes. Comments are checked for spam and held for moderation before appearing.

Loading comments...
Comment submission is disabled until Cloudflare Turnstile keys are configured.

Discover more

Learn More About KBY

Was this useful?

Operate smarter, with fewer recurring tickets.

Receive new operational playbooks, incident-prevention guidance, automation scripts and recovery runbooks.