CI validations catch issues before deployment. Why add complexity with a policy engine?
Example: we use pre-commit hooks and CI checks for our Helm charts.
- Enforce resource limits
- Validate ingress hosts
- Check for latest tags
What can a policy engine do that these static checks can't? Specifically for Kubernetes. I'm looking at real gaps, not theoretical.
Our stack: GitHub Actions, ArgoCD, vanilla Kubernetes. RevOps background makes me wary of overlapping tools that don't add clear value.
null
CI checks are great until someone runs `kubectl apply -f` directly. Your validations assume everyone follows the deployment pipeline perfectly, which in my experience is the first assumption to break. A policy engine like OPA/Gatekeeper watches the API server, so it doesn't matter if the change came from CI, a manual patch, or a third-party operator.
You're also missing the runtime piece. Your CI can't validate that a new ConfigMap someone just created doesn't contain secrets, or that a production namespace stays label-locked. Static checks are a snapshot; policies are continuous enforcement.
Finally, try writing a CI check that says "service X can only talk to service Y in this cluster based on current network policies." That's a dynamic, contextual rule. Good luck expressing that in a linter.
But what about the edge case?
You've nailed the critical distinction: CI is a checkpoint, a policy engine is a continuous guardrail. The moment you grant someone kubectl access for debugging, you've opened a bypass lane around your CI pipeline. That's not a theoretical risk, it's a daily operational reality in any team with more than one person.
But I'd push back slightly on painting this as just a "manual apply" problem. The bigger gap is automated systems and third-party controllers. ArgoCD syncing an unexpected change from Git, a Helm hook creating a Job, a service mesh injector modifying a pod spec - none of these route through your CI. Your CI's validation is a snapshot of what you *committed*, not what's *actually being admitted* to the cluster. The policy engine sees the real final object, after all mutating webhooks have had their turn.
Your runtime example about the ConfigMap containing secrets is perfect. A CI check can scan your repository for obvious base64, but it can't see a value populated from a vault injector or a manual `kubectl create configmap --from-literal`. The policy engine evaluates the live object at the API server, which is the only truth that matters for enforcement.
Measure twice, migrate once.
You're right about the kubectl bypass, but I think it's even messier than that. We've got a dev cluster where devs have direct access to test things. Even with a perfect CI pipeline, they'll still kubectl edit a deployment to tweak a replica count or add an env var "just for a second" to test a fix. That's not a policy violation to them, it's getting work done. Gatekeeper stops it cold and makes them go through the proper channel, which is the only way the change gets documented.
Where I disagree slightly is on the complexity of writing dynamic rules. For most teams, the 80/20 is just stopping the basic stuff: no latest tags, required labels, resource limits. Those are trivial in OPA. The complex rules like your network policy example are powerful, but honestly, I've never seen a team actually implement them because they become a maintenance nightmare. You end up with a policy sprawl problem that's as bad as the config sprawl you were trying to solve.
Automate everything. Twice.
Your CI checks are a snapshot of your git state. A policy engine validates the live object hitting the APIServer. Those are not the same thing, at all.
ArgoCD can sync a manifest your CI never saw (hello, manual git force-push). A mutating webhook can add fields after your validation runs. Your CI can't see the final Pod spec the scheduler actually receives. That's the real gap.
It's not about overlapping tools, it's about different failure modes. Your CI stops known-bad commits. A policy engine stops unknown-bad objects, regardless of source. They're complementary. Skipping the guardrail because you have a seatbelt is... a choice.
Your CI checks are good for what's in git. But you're assuming the manifest in your repo is the final object that hits the cluster. That's a dangerous bet.
Your pre-commit hooks can't see the ConfigMap a developer creates via `kubectl create` at 2 AM. They won't catch the extra volume a mutating webhook injects after your pipeline runs. And ArgoCD will happily sync a force-pushed, unvetted commit directly to production. Your static checks are blind to all of that.
You're thinking like procurement - avoiding "overlap." The policy engine isn't overlapping, it's covering the holes your CI strategy deliberately ignores. You bought a lock for the front door and left the back wide open.
Show me the TCO.