GitOps policy for Kubernetes becomes manageable when enforcement is built into the delivery pipeline. The combination of Kyverno and Argo CD bridges this gap at the admission level.
The problem does not manifest immediately — until the moment the cluster starts accepting resources created outside the controlled process. Argo CD addresses the challenge of declarative state management but does not validate the manifests themselves against policies. As a result, misconfigurations and insecure settings make their way into production if they are syntactically correct. This is particularly noticeable in multi-tenant environments, where different teams commit changes with varying levels of maturity.
The solution revolves around Kyverno as the policy engine for Kubernetes. It operates at the admission controller level and checks each resource before its creation. A key point is that policies are described in standard Kubernetes YAML. This eliminates the gap between configuration and governance: the same GitOps processes apply to both infrastructure and rules. In conjunction with Argo CD, this provides a unified flow: policies are versioned, undergo review, and are automatically applied. The trade-off here is evident: strict policies can block deployments and slow down delivery, which is why an Audit mode is introduced as an intermediate step.
The implementation relies on the App-of-Apps pattern in Argo CD. One root application manages a set of child applications, each of which deploys a separate component via Helm. Kyverno is installed as a separate application using the official Helm chart, wrapped in a local chart. It is important that a sync-wave annotation is applied: Kyverno itself is deployed first, followed by the policies. Without this, the order is disrupted, and policies are not applied.
There are several technical nuances that affect stability:
- ServerSideApply=true is used due to the large size of the Kyverno CRD, which may exceed client-side apply limits
- IncludeMutationWebhook=true prevents false OutOfSync states, as Kyverno can mutate resources
- ServerSideDiff=true improves state comparison by considering changes on the admission side
Policies are deployed as a separate application, also via Helm. The official kyverno-policies chart is used as a dependency. The base configuration includes Pod Security Standard at the baseline level. This is a compromise choice: obvious risks such as privileged containers or host networking are blocked, but compatibility with most workloads is maintained. The validationFailureAction mode is initially set to Audit to collect signals of violations without blocking.
Additionally, a layer of custom policies is provided through the templates/ directory. This is an important architectural point: standard policies and organization-specific rules are separated but go through a single pipeline. After a commit, Argo CD automatically synchronizes changes, and Kyverno begins to apply them without manual intervention.
A good example is the prohibition of using externalIPs in Service. This is a known attack vector (CVE-2020-8554) that allows traffic interception. The Kyverno policy validates the absence of this field. In Enforce mode, such a resource simply will not be created. In Audit mode, it will appear in the report as a violation.
The result is a shift-left in control without changing the familiar GitOps flow. If a policy is violated in Enforce mode, Argo CD marks the application as OutOfSync or Degraded and shows a validation error. This makes issues visible at the synchronization stage rather than after an incident. In Audit mode, teams receive reports through PolicyReport and ClusterPolicyReport, allowing them to assess the impact before tightening the rules.
Metrics are not provided in the original material, but the behavioral effect is clear: the system stops accepting inconsistent or insecure resources. At the same time, transparency of changes through Git is maintained. This approach appears as an evolutionary enhancement of GitOps, where policy becomes part of the declarative state rather than an external control process.