Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLXXXIII · GitOps RBACRBACModel

The GitOps RBAC model — repository, controller, and cluster as three layers

Advanced⏱ ~24 mingit

What you'll learn

  • Name the three permission layers in a GitOps delivery path and what each one gates
  • Explain why the effective privilege of a change is set by the weakest of the three layers
  • Trace a merge through repository, controller, and cluster authorisation to the applied object
  • Identify the audit question each layer can answer and the ones it cannot

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

Ask an engineer who can deploy to production in a GitOps estate and you will usually get one answer: whoever can merge. That answer is a third of the truth. A merged commit still has to be read by a controller that is scoped to particular sources and destinations, and that controller still has to apply the manifests using a Kubernetes identity with particular verbs on particular resources. Three separate permission systems sit between a keystroke and a running Pod, and they are owned by three different teams.

Three layers, three owners

The delivery path from a pull request to a reconciled object crosses three authorisation boundaries. Nothing in the pipeline collapses them into a single check.

flowchart TB
    A["Engineer opens pull request"] --> B["Layer 1: repository merge gate"]
    B -->|"merged commit"| C["Layer 2: controller scope gate"]
    C -->|"rendered manifests"| D["Layer 3: cluster credential gate"]
    D --> E["Applied object in namespace"]
    B -.->|"owned by repo admins"| F["Branch protection, CODEOWNERS"]
    C -.->|"owned by platform team"| G["AppProject, Kustomization scope"]
    D -.->|"owned by cluster admins"| H["ServiceAccount, Role, ClusterRole"]
  • Layer 1 — the repository. Decides who can change desired state at all. Enforced by branch protection, required reviews, and code ownership rules on the paths that hold manifests.
  • Layer 2 — the controller. Decides which sources may become desired state and which destinations they may target. Enforced by Argo CD AppProjects or by Flux source and Kustomization scoping.
  • Layer 3 — the cluster. Decides what the reconciling identity is permitted to create, update, and delete. Enforced by ordinary Kubernetes RBAC against a ServiceAccount.

The layers are ordered but not redundant. Layer 1 knows the human, layer 2 knows the repository and the destination, layer 3 knows the verbs. No single layer knows all three, which is why an audit that reads only one of them produces a confident wrong answer.

What each layer can prove

Each layer produces evidence, and the evidence is not interchangeable:

  • The repository proves intent and review: an author, a reviewer, a timestamp, a diff, and a signature if commits are signed.
  • The controller proves provenance: which commit produced which rendered manifest, and which destination it was allowed to reach.
  • The cluster proves effect: which object changed, under which identity, at which resource version, in the API server audit log.

An incident review needs all three. “Who deployed the bad network policy” is a repository question. “Why was it allowed into the payments namespace” is a controller question. “How did it also delete a ClusterRoleBinding” is a cluster question, and only the third layer can answer it.

Where the model is usually broken

Three failure shapes account for most real findings:

  • A single repository behind every environment with one merge gate. Layer 1 collapses to one rule, so production and sandbox share a reviewer set.
  • A controller with a wildcard source list. Layer 2 collapses, because any repository becomes a legitimate source of desired state.
  • One reconciling ServiceAccount for every tenant. Layer 3 collapses, because every tenant inherits the union of every tenant permission.

Each of these is individually defensible on day one of a platform and individually indefensible by the time a second team is onboarded.

Production discipline

  1. Name an owner per layer. Repository admins own layer 1, the platform team owns layer 2, cluster admins own layer 3. A layer with no named owner is a layer nobody reviews.
  2. Review the chain, not the links. A quarterly access review that reads branch protection and stops has audited one third of the delivery path.
  3. Write down the controller identity. Every GitOps estate should have a one-page answer to “which ServiceAccount applies to which namespace, with which verbs”.
  4. Assume layer 1 will eventually fail. Tokens leak and reviewers approve tired diffs. The scoped controller and the scoped ServiceAccount are what limit the damage when it does.

Cross-course references

  • Kubernetes for Production Sysadmins - Part LVIII (RBAC) and Part LX (ServiceAccounts) cover the primitives that layer 3 is built from.
  • Git, CI/CD & GitOps for Infrastructure Engineers - Part XXXII (ProtectedBranches) is layer 1 in detail, and Part LXXVII (ArgoCD) introduced the AppProject that layer 2 is expressed with.
  • Terraform for Production Sysadmins - Part XIX (Security) covers the same layering problem where the applying identity is a cloud role rather than a ServiceAccount.

Quiz

Knowledge check · 4 questions

  1. Q1. A platform has strict branch protection, two required reviewers, and signed commits on its GitOps repository. The reconciling controller runs with cluster-admin. What is the effective privilege of anything that reaches the reconciled path?

  2. Q2. The Kubernetes API server will refuse to let the reconciling ServiceAccount create a Role that grants permissions the ServiceAccount does not itself hold.

  3. Q3. Name the three permission layers a GitOps change passes through, and state the single question each one answers.

  4. Q4. Work out which layer failed and what evidence each layer can contribute.

    A ClusterRoleBinding granting cluster-admin to a team ServiceAccount appears in a production cluster. The GitOps repository requires two reviewers on every path, and the pull request history shows no such change. The controller reconciles a directory of Kustomizations, one of which references a Kustomize remote base hosted on a public repository. The controller ServiceAccount holds cluster-admin.

Passing score: 75%. Answers are checked in this browser.