# Technical Documentation: open-policy-agent/gatekeeper

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/open-policy-agent/gatekeeper)

### Overview (`README.md`)

# Gatekeeper



## How is Gatekeeper different from OPA?

Compared to using [OPA with its sidecar kube-mgmt](https://www.openpolicyagent.org/docs/kubernetes-admission-control.html) (aka Gatekeeper v1.0), Gatekeeper introduces the following functionality:

   * An extensible, parameterized [policy library](https://open-policy-agent.github.io/gatekeeper-library/website/)
   * Native Kubernetes CRDs for instantiating the policy library (aka "constraints")
   * Native Kubernetes CRDs for extending the policy library (aka "constraint templates")
   * Native Kubernetes CRDs for [mutation](https://open-policy-agent.github.io/gatekeeper/website/docs/mutation/) support
   * Audit functionality
   * External data support

## Getting started

Check out the [installation instructions](https://open-policy-agent.github.io/gatekeeper/website/docs/install) to deploy Gatekeeper components to your Kubernetes cluster.

## Documentation

Please see the [Gatekeeper website](https://open-policy-agent.github.io/gatekeeper/website/docs/howto) for more in-depth information.

## Policy Library

See the [Gatekeeper policy library](https://open-policy-agent.github.io/gatekeeper-library/website/) for a collection of constraint templates and sample constraints that you can use with Gatekeeper.

## Community & Contributing

Please refer to [Gatekeeper's contribution guide](https://open-policy-agent.github.io/gatekeeper/website/docs/help) to find out how you can help.

## Code of conduct

This project is governed by the [CNCF Code of conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).

## Security

For details on how to report vulnerabilities and security release process, please refer to [Gatekeeper Security](https://open-policy-agent.github.io/gatekeeper/website/docs/security) for more information.

---

### Overview (`deprecated/README.md`)

# DEPRECATED

This directory contains Rego source for old-style (Kubernetes Policy Controller)
rules. This source is being preserved as a potential reference for writing
constraints for a future constraint library and should be deleted after
conversion.

It should be noted that for the Gatekeeper admission controller, this Rego
source is not functional as-written.

---

### Overview (`library/README.md`)

# Gatekeeper policy library

[The Gatekeeper policy library has moved to a separate repository.](https://www.github.com/open-policy-agent/gatekeeper-library)

---

### Overview (`website/README.md`)

# Website

This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator.

## Installation

```console
yarn install
```

## Local Development

```console
yarn start
```

This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.

## Build

```console
yarn build
```

This command generates static content into the `build` directory and can be served using any static contents hosting service.

## Deployment

```console
GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy
```

If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.

## Search

Gatekeeper docs website uses Algolia DocSearch service. Please see [here](https://docusaurus.io/docs/search) for more information.

If the search index has any issues:

1. Go to [Algolia search dashboard](https://www.algolia.com/apps/PT2IX43ZFM/explorer/browse/gatekeeper)
1. Click manage index and export configuration
1. Delete the index
1. Import saved configuration
1. Go to [Algolia crawler](https://crawler.algolia.com/admin/crawlers/a953b469-c85a-4dc6-8a1c-16028abc1936/overview) and restart crawling manually (takes about a few minutes to crawl). This is scheduled to run every week automatically.

---

### Overview (`charts/gatekeeper/README.md`)

# Gatekeeper Helm Chart

## Get Repo Info

```console
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
```

_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._

## Install Chart

```console
# Helm install with gatekeeper-system namespace already created
$ helm install -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper

# Helm install and create namespace
$ helm install -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper --create-namespace

```

_See [parameters](#parameters) below._

_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._

## Upgrade Chart

**Upgrading from < v3.4.0**
Chart 3.4.0 deprecates support for Helm 2 and also removes the creation of the `gatekeeper-system` Namespace from within
the chart. This follows Helm 3 Best Practices.

Option 1:
A simple way to upgrade is to uninstall first and re-install with 3.4.0 or greater.

```console
$ helm uninstall gatekeeper
$ helm install -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper --create-namespace

```

Option 2:
Run the `helm_migrate.sh` script before installing the 3.4.0 or greater chart. This will remove the Helm secret for the
original release, while keeping all of the resources. It then updates the annotations of the resources so that the new
chart can import and manage them.

```console
$ helm_migrate.sh
$ helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper
```

**Upgrading from >= v3.4.0**

```console
$ helm upgrade -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper
```

_See [helm 2 to 3](https://helm.sh/docs/topics/v2_v3_migration/) for Helm 2 migration documentation._

## Exempting Namespace

The Helm chart automatically sets the Gatekeeper flag `--exempt-namespace={{ .Release.Namespace }}` in order to exempt
the namespace where the chart is installed, and adds the `admission.gatekeeper.sh/ignore` label to the namespace during
a post-install hook.

_See [Exempting Namespaces](https://open-policy-agent.github.io/gatekeeper/website/docs/exempt-namespaces) for more
information._

## Parameters

| Parameter                                                  | Description                                                                                                                                                                                                                                                                                    | Default                                                                                                                                                               |
|:-----------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| postInstall.labelNamespace.enabled                         | Add labels to the namespace during post install hooks                                                                                                                                                                                                                                          | `true`                                                                                                                                                                |
| postInstall.labelNamespace.extraNamespaces                 | The extra namespaces that need to have the label during post install hooks                                                                                                                                                                                                                     | `[]`                                                                                                                                                                  |
| postInstall.labelNamespace.extraAnnotations                | Extra annotations added to the post install Job                                                                                                                                                                                                                                                | `{}`                                                                                                                                                                  |
| postInstall.labelNamespace.image.repository                | Image with kubectl to label the namespace                                                                                                                                                                                                                                                      | `openpolicyagent/gatekeeper-crds`                                                                                                                                     |
| postInstall.labelNamespace.image.tag                       | Image tag                                                                                                                                                                                                                                                                                      | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| postInstall.labelNamespace.image.pullPolicy                | Image pullPolicy                                                                                                                                                                                                                                                                               | `IfNotPresent`                                                                                                                                                        |
| postInstall.labelNamespace.image.pullSecrets               | Image pullSecrets                                                                                                                                                                                                                                                                              | `[]`                                                                                                                                                                  |
| postInstall.labelNamespace.extraRules                      | Extra rules for the gatekeeper-update-namespace-label Role                                                                                                                                                                                                                                     | `[]`                                                                                                                                                                  |
| postInstall.labelNamespace.priorityClassName               | Priority class name for gatekeeper-update-namespace-label Job                                                                                                                                                                                                                                  | ``                                                                                                                                                                    |
| postInstall.probeWebhook.enabled                           | Probe webhook API post install. When enabled along with `postInstall.labelNamespace.enabled`, this probe will run as part of `postInstall.labelNamespace` Job as an initContainer                                                                                                              | `true`                                                                                                                                                                |
| postInstall.probeWebhook.image.repository                  | Image with curl to probe the webhook API                                                                                                                                                                                                                                                       | `curlimages/curl`                                                                                                                                                     |
| postInstall.probeWebhook.image.tag                         | Image tag                                                                                                                                                                                                                                                                                      | `8.20.0`                                                                                                                                                              |
| postInstall.probeWebhook.image.pullPolicy                  | Image pullPolicy                                                                                                                                                                                                                                                                               | `IfNotPresent`                                                                                                                                                        |
| postInstall.probeWebhook.image.pullSecrets                 | Image pullSecrets                                                                                                                                                                                                                                                                              | `[]`                                                                                                                                                                  |
| postInstall.probeWebhook.waitTimeout                       | Total time to wait for the webhook API to become available                                                                                                                                                                                                                                     | `60`                                                                                                                                                                  |
| postInstall.probeWebhook.httpTimeout                       | HTTP client timeout                                                                                                                                                                                                                                                                            | `2`                                                                                                                                                                   |
| postInstall.probeWebhook.insecureHTTPS                     | Ignore server SSL certificate                                                                                                                                                                                                                                                                  | `false`                                                                                                                                                               |
| postInstall.probeWebhook.priorityClassName                 | Priority class name for gatekeeper-probe-webhook-post-install Job                                                                                                                                                                                                                              | ``                                                                                                                                                                    |
| postInstall.affinity                                       | The affinity to use for pod scheduling in postInstall hook jobs                                                                                                                                                                                                                                | `{}`                                                                                                                                                                  |
| postInstall.tolerations                                    | The tolerations to use for pod scheduling in postInstall hook jobs                                                                                                                                                                                                                             | `[]`                                                                                                                                                                  |
| postInstall.nodeSelector                                   | The node selector to use for pod scheduling in postInstall hook jobs                                                                                                                                                                                                                           | `kubernetes.io/os: linux`                                                                                                                                             |
| postInstall.resources                                      | The resource request/limits for the container image in postInstall hook jobs                                                                                                                                                                                                                   | `{}`                                                                                                                                                                  |
| postInstall.securityContext                                | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| postUpgrade.labelNamespace.enabled                         | Add labels to the namespace during post upgrade hooks                                                                                                                                                                                                                                          | `false`                                                                                                                                                               |
| postUpgrade.labelNamespace.extraNamespaces                 | The extra namespaces that need to have the label during post upgrade hooks                                                                                                                                                                                                                     | `[]`                                                                                                                                                                  |
| postUpgrade.labelNamespace.extraAnnotations                | Extra annotations added to the post upgrade Job                                                                                                                                                                                                                                                | `{}`                                                                                                                                                                  |
| postUpgrade.labelNamespace.image.repository                | Image with kubectl to label the namespace                                                                                                                                                                                                                                                      | `openpolicyagent/gatekeeper-crds`                                                                                                                                     |
| postUpgrade.labelNamespace.image.tag                       | Image tag                                                                                                                                                                                                                                                                                      | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| postUpgrade.labelNamespace.image.pullPolicy                | Image pullPolicy                                                                                                                                                                                                                                                                               | `IfNotPresent`                                                                                                                                                        |
| postUpgrade.labelNamespace.image.pullSecrets               | Image pullSecrets                                                                                                                                                                                                                                                                              | `[]`                                                                                                                                                                  |
| postUpgrade.labelNamespace.priorityClassName               | Priority class name for gatekeeper-update-namespace-label-post-upgrade Job                                                                                                                                                                                                                     | ``                                                                                                                                                                    |
| postUpgrade.affinity                                       | The affinity to use for pod scheduling in postUpgrade hook jobs                                                                                                                                                                                                                                | `{}`                                                                                                                                                                  |
| postUpgrade.tolerations                                    | The tolerations to use for pod scheduling in postUpgrade hook jobs                                                                                                                                                                                                                             | `[]`                                                                                                                                                                  |
| postUpgrade.nodeSelector                                   | The node selector to use for pod scheduling in postUpgrade hook jobs                                                                                                                                                                                                                           | `kubernetes.io/os: linux`                                                                                                                                             |
| postUpgrade.resources                                      | The resource request/limits for the container image in postUpgrade hook jobs                                                                                                                                                                                                                   | `{}`                                                                                                                                                                  |
| postUpgrade.securityContext                                | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| preInstall.crdRepository.image.repository                  | Image with kubectl to update the CRDs. If not set, the `image.crdRepository` is used instead.                                                                                                                                                                                                  | `null`                                                                                                                                                                |
| preInstall.crdRepository.image.tag                         | Image tag                                                                                                                                                                                                                                                                                      | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| preUninstall.deleteWebhookConfigurations.enabled           | Delete webhooks before gatekeeper itself is uninstalled                                                                                                                                                                                                                                        | `false`                                                                                                                                                               |
| preUninstall.deleteWebhookConfigurations.image.repository  | Image with kubectl to delete the webhooks                                                                                                                                                                                                                                                      | `openpolicyagent/gatekeeper-crds`                                                                                                                                     |
| preUninstall.deleteWebhookConfigurations.image.tag         | Image tag                                                                                                                                                                                                                                                                                      | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| preUninstall.deleteWebhookConfigurations.image.pullPolicy  | Image pullPolicy                                                                                                                                                                                                                                                                               | `IfNotPresent`                                                                                                                                                        |
| preUninstall.deleteWebhookConfigurations.image.pullSecrets | Image pullSecrets                                                                                                                                                                                                                                                                              | `[]`                                                                                                                                                                  |
| preUninstall.deleteWebhookConfigurations.extraRules        | Extra rules for the gatekeeper-delete-webhook-configs Role                                                                                                                                                                                                                                     | `[]`                                                                                                                                                                  |
| preUninstall.deleteWebhookConfigurations.priorityClassName | Priority class name for gatekeeper-delete-webhook-configs Job                                                                                                                                                                                                                                  | ``                                                                                                                                                                    |
| preUninstall.affinity                                      | The affinity to use for pod scheduling in preUninstall hook jobs                                                                                                                                                                                                                               | `{}`                                                                                                                                                                  |
| preUninstall.tolerations                                   | The tolerations to use for pod scheduling in preUninstall hook jobs                                                                                                                                                                                                                            | `[]`                                                                                                                                                                  |
| preUninstall.nodeSelector                                  | The node selector to use for pod scheduling in preUninstall hook jobs                                                                                                                                                                                                                          | `kubernetes.io/os: linux`                                                                                                                                             |
| preUninstall.resources                                     | The resource request/limits for the container image in preUninstall hook jobs                                                                                                                                                                                                                  | `{}`                                                                                                                                                                  |
| preUninstall.securityContext                               | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| upgradeCRDs.enabled                                        | Upgrade CRDs using pre-install/pre-upgrade hooks                                                                                                                                                                                                                                               | `true`                                                                                                                                                                |
| upgradeCRDs.extraRules                                     | Extra rules for the gatekeeper-admin-upgrade-crds ClusterRole                                                                                                                                                                                                                                  | `[]`                                                                                                                                                                  |
| upgradeCRDs.priorityClassName                              | Priority class name for gatekeeper-update-crds-hook Job                                                                                                                                                                                                                                        | ``                                                                                                                                                                    |
| crds.affinity                                              | The affinity to use for pod scheduling in crds hook jobs                                                                                                                                                                                                                                       | `{}`                                                                                                                                                                  |
| crds.tolerations                                           | The tolerations to use for pod scheduling in crds hook jobs                                                                                                                                                                                                                                    | `[]`                                                                                                                                                                  |
| crds.nodeSelector                                          | The node selector to use for pod scheduling in crds hook jobs                                                                                                                                                                                                                                  | `kubernetes.io/os: linux`                                                                                                                                             |
| crds.resources                                             | The resource request/limits for the container image in crds hook jobs                                                                                                                                                                                                                          | `{}`                                                                                                                                                                  |
| crds.securityContext                                       | Security context applied to the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 65532, "runAsNonRoot": true, "runAsUser": 65532 }` |
| auditInterval                                              | The frequency with which audit is run                                                                                                                                                                                                                                                          | `60`                                                                                                                                                                  |
| constraintViolationsLimit                                  | The maximum # of audit violations reported on a constraint                                                                                                                                                                                                                                     | `20`                                                                                                                                                                  |
| auditFromCache                                             | Take the roster of resources to audit from the audit cache                                                                                                                                                                                                                                     | `false`                                                                                                                                                               |
| auditChunkSize                                             | (alpha) Chunk size for listing cluster resources for audit                                                                                                                                                                                                                             | `500`                                                                                                                                                                 |
| auditMatchKindOnly                                         | Only check resources of the kinds specified in all constraints defined in the cluster.                                                                                                                                                                                                         | `false`                                                                                                                                                               |
| disableAudit                                               | Disable audit controller                                                                                                                                                                                                                                                                       | `false`                                                                                                                                                               |
| disableMutation                                            | Disable mutation                                                                                                                                                                                                                                                                               | `false`                                                                                                                                                               |
| disableValidatingWebhook                                   | Disable the validating webhook                                                                                                                                                                                                                                                                 | `false`                                                                                                                                                               |
| validatingWebhookName                                      | The name of the `ValidatingWebhookConfiguration`                                                                                                                                                                                                                                               | `gatekeeper-validating-webhook-configuration`                                                                                                                         |
| validatingWebhookTimeoutSeconds                            | The timeout for the validating webhook in seconds                                                                                                                                                                                                                                              | `3`                                                                                                                                                                   |
| validatingWebhookFailurePolicy                             | The failurePolicy for the validating webhook                                                                                                                                                                                                                                                   | `Ignore`                                                                                                                                                              |
| validatingWebhookAnnotations                               | The annotations to add to the ValidatingWebhookConfiguration                                                                                                                                                                                                                                   | `{}`                                                                                                                                                                  |
| validatingWebhookObjectSelector                            | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's validation webhook unless measures are taken to control how exemption labels can be set.                          | `{}`                                                                                                                                                                  |
| validatingWebhookMatchConditions                           | The match conditions written in CEL to further refine which resources will be selected by the webhook. All match conditions must evaluate to true for the webhook to be called                                                                                                                 | `[]`                                                                                                                                                                  |
| validatingWebhookCheckIgnoreFailurePolicy                  | The failurePolicy for the check-ignore-label validating webhook                                                                                                                                                                                                                                | `Fail`                                                                                                                                                                |
| validatingWebhookExemptNamespacesLabels                    | Additional namespace labels that will be exempt from the validating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace.                                            | `{}`                                                                                                                                                                  |
| validatingWebhookCustomRules                               | Custom rules for selecting which API resources trigger the webhook. Mutually exclusive with `enableDeleteOperations`. NOTE: If you change this, ensure all your constraints are still being enforced.                                                                                          | `{}`                                                                                                                                                                  |
| validatingWebhookSubResources                                        | Rule for selecting which API subresources trigger the webhook.                                                                                                                                                                                             | `['pods/ephemeralcontainers', 'pods/exec', 'pods/log', 'pods/eviction', 'pods/portforward', 'pods/proxy', 'pods/attach', 'pods/binding', 'pods/resize', 'deployments/scale', 'replicasets/scale', 'statefulsets/scale', 'replicationcontrollers/scale', 'services/proxy', 'nodes/proxy', 'services/status']`                                                                                                                           |
| validatingWebhookURL                                       | Custom URL for Kubernetes API server to use to reach the validating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used.                                                                                                                            | `null`                                                                                                                                                                |
| validatingWebhookScope                                     | The scope for the validating webhook. Does not work with `validatingWebhookCustomRules`                                                                                                                                                                                                        | `*`                                                                                                                                                                   |
| additionalValidatingWebhookConfigsToRotateCerts                                      | The name of additional `ValidatingWebhookConfiguration`s that the gatekeeper cert rotator should manage certs for                                                                                                                                                                                                                                               | `[]`                                                                                                                         |
| enableDeleteOperations                                     | Enable validating webhook for delete operations. Does not work with `validatingWebhookCustomRules`                                                                                                                                                                                             | `false`                                                                                                                                                               |
| enableConnectOperations                                    | Enable validating webhook for connect operations.                                                                                                                                                                                                                                              | `false`                                                                                                                                                               |
| enableExternalData                                         | Enable external data                                                                                                                                                                                                                                                                           | `true`                                                                                                                                                                |
| enableGeneratorResourceExpansion                           | Enable generator resource expansion (beta feature)                                                                                                                                                                                                                                             | `true`                                                                                                                                                                |
| enableTLSHealthcheck                                       | Enable probing webhook API with certificate stored in certDir                                                                                                                                                                                                                                  | `false`                                                                                                                                                               |
| maxServingThreads                                          | Limit the number of concurrent calls the validation backend made by the validation webhook. -1 limits this value to GOMAXPROCS. Configuring this value may lower max RAM usage and limit CPU throttling, Tuning it can optimize serving capacity.                                              | `-1`                                                                                                                                                                  |
| metricsBackends                                            | Metrics exporters to use. Valid exporters are: `prometheus`, `stackdriver`, and `opentelemetry` starting from Gatekeeper 3.15                                                                                                                                                                  | `["prometheus"]`                                                                                                                                                      |                                                                                        |
| otlpEndpoint                                               | The OTLP endpoint for the OpenTelemetry metric exporter                                                                                                                                                                                                                                        | `""`                                                                                                                                                                  |
| otlpMetricInterval                                         | The interval to read metrics for the OpenTelemetry exporter                                                                                                                                                                                                                                    | `"10s"`                                                                                                                                                                 |
| stackdriverOnlyWhenAvailable                               | Only attempt to start the stackdriver exporter if credentials are available                                                                                                                                                                                                                    | `false`                                                                                                                                                               |
| stackdriverMetricInterval                                  | Interval to read metrics for stackdriver exporter                                                                                                                                                                                                                                              | `"10s"`                                                                                                                                                                 |
| mutatingWebhookName                                        | The name of the `MutatingWebhookConfiguration`                                                                                                                                                                                                                                                 | `gatekeeper-mutating-webhook-configuration`                                                                                                                           |
| mutatingWebhookFailurePolicy                               | The failurePolicy for the mutating webhook                                                                                                                                                                                                                                                     | `Ignore`                                                                                                                                                              |
| mutatingWebhookReinvocationPolicy                          | The reinvocationPolicy for the mutating webhook                                                                                                                                                                                                                                                | `Never`                                                                                                                                                               |
| mutatingWebhookAnnotations                                 | The annotations to add to the MutatingWebhookConfiguration                                                                                                                                                                                                                                     | `{}`                                                                                                                                                                  |
| mutatingWebhookExemptNamespacesLabels                      | Additional namespace labels that will be exempt from the mutating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace.                                              | `{}`                                                                                                                                                                  |
| mutatingWebhookObjectSelector                              | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's mutation webhook unless measures are taken to control how exemption labels can be set.                            | `{}`                                                                                                                                                                  |
| mutatingWebhookMatchConditions                             | The match conditions written in CEL to further refine which resources will be selected by the webhook. All match conditions must evaluate to true for the webhook to be called                                                                                                                 | `[]`                                                                                                                                                                  |
| mutatingWebhookTimeoutSeconds                              | The timeout for the mutating webhook in seconds                                                                                                                                                                                                                                                | `3`                                                                                                                                                                   |
| mutatingWebhookCustomRules                                 | Custom rules for selecting which API resources trigger the webhook. NOTE: If you change this, ensure all your constraints are still being enforced.                                                                                                                                            | `{}`                                                                                                                                                                  |
| mutatingWebhookSubResources                                        | Rule for selecting which API subresources trigger the webhook.                                                                                                                                                                                             | `['pods/ephemeralcontainers', 'pods/exec', 'pods/log', 'pods/eviction', 'pods/portforward', 'pods/proxy', 'pods/attach', 'pods/binding', 'deployments/scale', 'replicasets/scale', 'statefulsets/scale', 'replicationcontrollers/scale', 'services/proxy', 'nodes/proxy', 'services/status']`                                                                                                                           |
| mutatingWebhookURL                                         | Custom URL for Kubernetes API server to use to reach the mutating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used.                                                                                                                              | `null`                                                                                                                                                                |
| mutatingWebhookScope                                       | The scope for the mutating webhook. Does not work with `mutatingWebhookCustomRules`                                                                                                                                                                                                            | `*`                                                                                                                                                                   |
| additionalMutatingWebhookConfigsToRotateCerts                                      | The name of additional `MutatingWebhookConfiguration`s that the gatekeeper cert rotator should manage certs for                                                                                                                                                                                                                                               | `[]`                                                                                                                         |
| emitAdmissionEvents                                        | (alpha) Emit K8s events in configurable namespace for admission violations                                                                                                                                                                                                              | `false`                                                                                                                                                               |
| emitAuditEvents                                            | (alpha) Emit K8s events in configurable namespace for audit violations                                                                                                                                                                                                                  | `false`                                                                                                                                                               |
| logStatsAdmission                                          | (alpha) Log stats for admission webhook                                                                                                                                                                                                                                                 | `false`                                                                                                                                                               |
| logStatsAudit                                              | (alpha) Log stats metrics for the audit run                                                                                                                                                                                                                                             | `false`                                                                                                                                                               |
| enableK8sNativeValidation                                  | Enable the K8s Native Validating driver to allow constraint templates to use rules written in VAP-style CEL                                                                                                                                                                                                                 | `true`                                                                                                                                                               |
| defaultCreateVAPForTemplates                                      | (beta) Create VAP resource for template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy unless generateVAP: true is set on constraint template explicitly, true: create Validating Admission Policy unless generateVAP: false is set on constraint template explicitly.                                                                                                                                                                                                                  | `true`                                                                                                                                                               |
| defaultCreateVAPBindingForConstraints                             | (beta) Create VAPBinding resource for constraint of the template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy Binding, true: create Validating Admission Policy Binding.                                                                                                                                                                                                                  | `true`                                                                                                                                                               |
| defaultWaitForVAPBGeneration                             | (beta) Wait time in seconds before generating a ValidatingAdmissionPolicyBinding after a constraint CRD is created.                                                                                                                                                                                                                 | `30`                                                                                                                                                               |
| auditEventsInvolvedNamespace                               | Emit audit events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Audit events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in         | `false`                                                                                                                                                               |
| admissionEventsInvolvedNamespace                           | Emit admission events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Admission events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in | `false`                                                                                                                                                               |
| logDenies                                                  | Log detailed info on each deny                                                                                                                                                                                                                                                                 | `false`                                                                                                                                                               |
| logLevel                                                   | Minimum log level                                                                                                                                                                                                                                                                              | `INFO`                                                                                                                                                                |
| image.pullPolicy                                           | The image pull policy                                                                                                                                                                                                                                                                          | `IfNotPresent`                                                                                                                                                        |
| image.repository                                           | Image repository                                                                                                                                                                                                                                                                               | `openpolicyagent/gatekeeper`                                                                                                                                          |
| image.release                                              | The image release tag to use                                                                                                                                                                                                                                                                   | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| image.pullSecrets                                          | Specify an array of imagePullSecrets                                                                                                                                                                                                                                                           | `[]`                                                                                                                                                                  |
| resources                                                  | The resource request/limits for the container image                                                                                                                                                                                                                                            | limits: 1 CPU, 512Mi, requests: 100mCPU, 256Mi                                                                                                                        |
| nodeSelector                                               | The node selector to use for pod scheduling                                                                                                                                                                                                                                                    | `kubernetes.io/os: linux`                                                                                                                                             |
| controllerManager.containerName                            | Container name for controller manager                                                                                                                                                      | `manager`                                                                                                                                                             |
| controllerManager.podLabels                                | The labels to add to the controller manager pod                                                                                                                                                                                                                                                       | `{}`                                                                                                                                                                  |
| controllerManager.affinity                                 | The node affinity to use for controller manager pod scheduling                                                                                                                                                                                                                                 | `{}`                                                                                                                                                                  |
| controllerManager.topologySpreadConstraints                | The topology spread constraints to use for controller manager pod scheduling                                                                                                                                                                                                                   | `[]`                                                                                                                                                                  |
| controllerManager.tolerations                              | The tolerations to use for controller manager pod scheduling                                                                                                                                                                                                                                   | `[]`                                                                                                                                                                  |
| controllerManager.healthPort                               | Health port for controller manager                                                                                                                                                                                                                                                             | `9090`                                                                                                                                                                |
| controllerManager.port                                     | Webhook-server port for controller manager                                                                                                                                                                                                                                                     | `8443`                                                                                                                                                                |
| controllerManager.metricsPort                              | Metrics port for controller manager                                                                                                                                                                                                                                                            | `8888`                                                                                                                                                                |
| controllerManager.readinessTimeout                         | Timeout in seconds for the controller manager's readiness probe                                                                                                                                                                                                                                | `1`                                                                                                                                                                   |
| controllerManager.livenessTimeout                          | Timeout in seconds for the controller manager's liveness probe                                                                                                                                                                                                                                 | `1`                                                                                                                                                                   |
| controllerManager.logLevel                                 | The minimum log level for the controller manager, takes precedence over `logLevel` when specified                                                                                                                                                                                              | `null`                                                                                                                                                                |
| controllerManager.priorityClassName                        | Priority class name for controller manager                                                                                                                                                                                                                                                     | `system-cluster-critical`                                                                                                                                             |
| controllerManager.podSecurityContext                       | Security context on pod level for controller manager                                                                                                                                                                                                                                           | {fsGroup: 999, suplementalGroups: [999]}                                                                                                                              |
| controllerManager.exemptNamespaces                         | The exact namespaces to exempt by the admission webhook                                                                                                                                                                                                                                        | `[]`                                                                                                                                                                  |
| controllerManager.exemptNamespacePrefixes                  | The namespace prefixes to exempt by the admission webhook                                                                                                                                                                                                                                      | `[]`                                                                                                                                                                  |
| controllerManager.hostNetwork                              | Enables controllerManager to be deployed on hostNetwork                                                                                                                                                                                                                                        | `false`                                                                                                                                                               |
| controllerManager.dnsPolicy                                | Set the dnsPolicy for controllerManager pods                                                                                                                                                                                                                                                   | `ClusterFirst`                                                                                                                                                        |
| controllerManager.securityContext                          | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| controllerManager.tlsMinVersion                            | Set the minimum supported TLS version for validating and mutating webhook servers                                                                                                                                                                                                              | `1.3`                                                                                                                                                                 |
| controllerManager.extraRules                               | Extra rules for the gatekeeper-manager-role Role                                                                                                                                                                                                                                               | `[]`                                                                                                                                                                  |
| controllerManager.networkPolicy.enabled                    | Should a network policy for the controller manager be created                                                                                                                                                                                                                                  | `false`                                                                                                                                                               |
| controllerManager.networkPolicy.ingress                    | Additional ingress rules to be added to the controller manager network policy                                                                                                                                                                                                                  | `{}`                                                                                                                                                                  |
| controllerManager.strategyType                             | The strategy type to use for Controller Manager deployment                                                                                                                                                                                                                                     | `RollingUpdate`                                                                                                                                                       |
| controllerManager.strategyRollingUpdate                    | [RollingUpdate](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-update-deployment) configuration for Controller Manager deployment                                                                                                                               | `{}`                                                                                                                                                                  |
| controllerManager.disableWebhookOperation                                       | Disable webhook operation for controller manager                                                                                                                                                    | `false`                                                                                                                                                             |
| controllerManager.disableGenerateOperation                                       | Disable generate operation for controller manager                                                                                                                                                    | `true`                                                                                                                                                             |
| audit.containerName                                        | Container name for audit                                                                                                                                                                                                                                                     | `manager`                                                                                                                                                             |
| audit.podLabels                                            | The labels to add to the audit pod                                                                                                                                                                                                                                                       | `{}`                                                                                                                                                                  |
| audit.affinity                                             | The node affinity to use for audit pod scheduling                                                                                                                                                                                                                                              | `{}`                                                                                                                                                                  |
| audit.topologySpreadConstraints                            | The topology spread constraints to use for audit pod scheduling                                                                                                                                                                                                                                | `[]`                                                                                                                                                                  |
| audit.tolerations                                          | The tolerations to use for audit pod scheduling                                                                                                                                                                                                                                                | `[]`                                                                                                                                                                  |
| audit.priorityClassName                                    | Priority class name for audit controller                                                                                                                                                                                                                                                       | `system-cluster-critical`                                                                                                                                             |
| audit.podSecurityContext                                   | Security context for audit on pod level                                                                                                                                                                                                                                                        | {fsGroup: 999, suplementalGroups: [999]}                                                                                                                              |
| audit.hostNetwork                                          | Enables audit to be deployed on hostNetwork                                                                                                                                                                                                                                                    | `false`                                                                                                                                                               |
| audit.dnsPolicy                                            | Set the dnsPolicy for audit pods                                                                                                                                                                                                                                                               | `ClusterFirst`                                                                                                                                                        |
| audit.securityContext                                      | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| audit.healthPort                                           | Health port for audit                                                                                                                                                                                                                                                                          | `9090`                                                                                                                                                                |
| audit.metricsPort                                          | Metrics port for audit                                                                                                                                                                                                                                                                         | `8888`                                                                                                                                                                |
| audit.readinessTimeout                                     | Timeout in seconds for audit's readiness probe                                                                                                                                                                                                                                                 | `1`                                                                                                                                                                   |
| audit.livenessTimeout                                      | Timeout in seconds for the audit's liveness probe                                                                                                                                                                                                                                              | `1`                                                                                                                                                                   |
| audit.logLevel                                             | The minimum log level for audit, takes precedence over `logLevel` when specified                                                                                                                                                                                                               | `null`                                                                                                                                                                |
| audit.disableGenerateOperation                            | Disable generate operation for audit                                                                                                                                                                                                                                                           | `false`                                                                                                                                                                |
| audit.disableAuditOperation                               | Disable audit operation for audit                                                                                                                                                                                                                                                              | `false`                                                                                                                                                                |
| audit.disableAuditSidecar                                 | Disable audit sidecar                                                                                                                                                                                                                                                              | `false`                                                                                                                                                                |
| audit.disableStatusOperation                              | Disable status operation for audit                                                                                                                                                                                                                                                             | `false`                                                                                                                                                                |
| enableViolationExport                                      | (alpha) Enable exporting violations to external systems                                                                                                                                                                                                                                                     | `false`                                                                                                                                                               |
| audit.connection                                           | (alpha) Connection name for exporting audit violation messages                                                                                                                                                                                                                                | `audit-connection`                                                                                                                                                    |
| audit.channel                                              | (alpha) Channel name for exporting audit violation messages                                                                                                                                                                                                                                   | `audit-channel`                                                                                                                                                       |
| audit.exportVolume                                         | (alpha) Volume for audit pod to export violations.                                                                                                                                                                                                                                   | `{"name":"tmp-violations","emptyDir":{}}`                                                                                                                                                       |
| audit.exportVolumeMount.path                                         | (alpha) VolumeMount for audit pod manager container to export violations and sidecar container to read from.                                                                                                                                                                                                                                   | `/tmp/violations`                                                                                                                                                       |
| audit.exportSidecar                                        | (alpha) Sidecar container to read violations from disk.                                                                                                                                                                                                                                   | `{"name":"reader","image":"ghcr.io/open-policy-agent/fake-reader:latest","imagePullPolicy":"Always","securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsGroup":999,"runAsNonRoot":true,"runAsUser":1000,"seccompProfile":{"type":"RuntimeDefault"}},"volumeMounts":[{"mountPath":"/tmp/violations","name":"tmp-violations"}]}`                                                                                                                                                       |
| audit.exportConnection.path                                         | (alpha) Path for audit pod manager container to export violations and sidecar container to read from. Must be a child of volume mount path so the parent is writable.                                                                                                                                                                                                                          | `/tmp/violations/topics`                                                                                                                                                       |
| audit.exportConnection.maxAuditResults                         | (alpha) Maximum number of audit results that can be stored in the export path.                                                                                                                                                                                                                                   | 3                                                                                                                                                       |
| exportBackend                                              | (alpha) Backend to use for exporting violations, i.e. dapr, disk.                                                                                                                                                                                                                              | ""                                                                                                                                                                    | 
| replicas                                                   | The number of Gatekeeper replicas to deploy for the webhook                                                                                                                                                                                                                                    | `3`                                                                                                                                                                   |
| podAnnotations                                             | The annotations to add to the Gatekeeper pods                                                                                                                                                                                                                                                  | `container.seccomp.security.alpha.kubernetes.io/manager: runtime/default`                                                                                             |
| podLabels                                                  | The labels to add to the Gatekeeper pods                                                                                                                                                                                                                                                       | `{}`                                                                                                                                                                  |
| podCountLimit                                              | The maximum number of Gatekeeper pods to run                                                                                                                                                                                                                                                   | `100`                                                                                                                                                                 |
| secretAnnotations                                          | The annotations to add to the Gatekeeper secrets                                                                                                                                                                                                                                               | `{}`                                                                                                                                                                  |
| pdb.controllerManager.minAvailable                         | The number of controller manager pods that must still be available after an eviction                                                                                                                                                                                                           | `1`                                                                                                                                                                   |
| service.type                                               | Service type                                                                                                                                                                                                                                                                                   | `ClusterIP`                                                                                                                                                           |
| service.loadBalancerIP                                     | The IP address of LoadBalancer service                                                                                                                                                                                                                                                         | ``                                                                                                                                                                    |
| service.ipFamilyPolicy                                     | The IP family policy used for the service, for more information see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services).                                                                                                                      | ``                                                                                                                                                                    |
| service.ipFamilies                                         | List of IP families for the service. Can be "IPv4" and/or "IPv6"                                                                                                                                                                                                                               | ``                                                                                                                                                                    |
| service.healthzPort                                        | Service port to gatekeeper Webhook health port                                                                                                                                                                                                                                                 | `9090`                                                                                                                                                                |
| rbac.create                                                | Enable the creation of RBAC resources                                                                                                                                                                                                                                                          | `true`                                                                                                                                                                |
| externalCertInjection.enabled                              | Enable the injection of an external certificate. This disables automatic certificate generation and rotation                                                                                                                                                                                   | `false`                                                                                                                                                               |
| externalCertInjection.secretName                           | Name of secret for injected certificate                                                                                                                                                                                                                                                        | `gatekeeper-webhook-server-cert`                                                                                                                                      |
| externaldataProviderResponseCacheTTL                       | TTL for the external data provider response cache. Specify the duration in 'h', 'm', or 's' for hours, minutes, or seconds respectively.                                                                                                                                                       | `3m`                                                                                                                                                                  |
| commonAnnotations                                           | Additional annotations added to manager and audit Deployments only                                                                                                                                                                                                                              | `{}`                                                                                                                                                                  |
| extraVolumeMounts                                           | Extra volumeMounts injected into controller-manager and audit containers                                                                                                                                                                                                                        | `[]`                                                                                                                                                                  |
| extraVolumes                                                | Extra volumes injected into controller-manager and audit pods                                                                                                                                                                                                                                   | `[]`                                                                                                                                                                  |
| controllerManager.serviceAccount.automountServiceAccountToken | Whether to automount the service account token for controller-manager pods                                                                                                                                                                                                                      | `true`                                                                                                                                                                |
| audit.serviceAccount.automountServiceAccountToken           | Whether to automount the service account token for audit pods                                                                                                                                                                                                                                   | `true`                                                                                                                                                                |
| syncVAPEnforcementScope           | (beta) Synchronize ValidatingAdmissionPolicy enforcement scope with Gatekeeper's admission validation scope. When enabled, VAP resources inherit match criteria, conditions, and namespace exclusions from Gatekeeper's webhook configuration, Config resource and exempt namespace flags. This ensures consistent policy enforcement between Gatekeeper and VAP but triggers constraint template reconciliation on scope changes in Config resource or webhook configuration. This flag is set to true by default. It is deprecated and will be removed in Gatekeeper v3.24.                                                                                                                                                                                                               | `true`                                                                                                                                                                |
| logLevelKey                                                | JSON key for the log level field. Only set when specified.                                                                                                                                                                                                                                     | Not set (default: `level`)                                                                                                                                            |
| logLevelEncoder                                            | Encoder for the value of the log level field. Valid values: `lower`, `capital`, `color`, `capitalcolor`. Only set when specified.                                                                                                                                                              | Not set (default: `lower`)                                                                                                                                            |
| metricsAddr                                                | The address the metric endpoint binds to. Only set when specified.                                                                                                                                                                                                                             | Not set (default: `0`)                                                                                                                                                |
| readinessRetries                                           | The number of resource ingestion attempts allowed before the resource is disregarded. A value of -1 will retry indefinitely. Only set when specified.                                                                                                                                          | Not set (default: `0`)                                                                                                                                                |
| enablePprof                                                | Enable pprof profiling. Only set when specified.                                                                                                                                                                                                                                               | Not set (default: `false`)                                                                                                                                            |
| pprofPort                                                  | Port for pprof profiling. Only set when specified.                                                                                                                                                                                                                                             | Not set (default: `6060`)                                                                                                                                             |
| disableEnforcementActionValidation                         | Disable validation of the enforcementAction and scopedEnforcementActions field of a constraint. Only set when specified.                                                                                                                                                                       | Not set (default: `false`)                                                                                                                                            |
| enableReferentialRules                                     | Enable referential rules. Set to false to disallow referential constraints. Referential constraints read objects other than the object-under-test and may be subject to race conditions. Only set when specified.                                                                              | Not set (default: `true`)                                                                                                                                             |
| controllerManager.host                                     | The host address the webhook server listens on. Only set when specified.                                                                                                                                                       | Not set (default: all addresses)                                                                                                                                      |
| controllerManager.certDir                                  | The directory where certs are stored.                                                                                                                                                | Not set (default: `/certs`)                                                                                                                                           |
| controllerManager.certServiceName                          | The service name used to generate the TLS cert's hostname.                                                            | Not set (default: `gatekeeper-webhook-service`)                                                                                                                       |
| controllerManager.clientCAName                             | Name of the certificate authority bundle to authenticate the Kubernetes API server requests against. Only set when specified.                                                                                                                                                                  | Not set                                                                                                                                                               |
| controllerManager.clientCNName                             | Expected CN name on the client certificate attached by apiserver in requests to the webhook. Only set when specified.                                                                                                                                                                          | Not set (default: `kube-apiserver`)                                                                                                                                   |
| audit.apiCacheDir                                          | The directory where audit from api server cache are stored. Only set when specified.                                                                                                                                                                                                           | Not set (default: `/tmp/audit`)                                                                                                                                       |
| shutdownDelay                                              | Time in seconds the controller runtime shutdown gets delayed after receiving a pod termination event. Prevents failing webhooks on pod shutdown. Only set when specified.                                                                                                                       | Not set (default: `10`)                                                                                                                                               |
| enableRemoteCluster                                        | (alpha) Enable remote cluster mode where Gatekeeper operates against a target cluster specified via kubeconfig while running in the local cluster. Requires `kubeconfig` to also be set, and the kubeconfig file to be mounted via `extraVolumes`/`extraVolumeMounts`. Only set when specified. | Not set (default: `false`)                                                                                                                                            |
| kubeconfig                                                 | Path to kubeconfig file inside the container for remote cluster mode. The file must be mounted into the container using `extraVolumes` and `extraVolumeMounts`. Only set when specified.                                                                                                       | Not set                                                                                                                                                               |

## Contributing Changes

Please refer
to [Contributing to Helm Chart](https://open-policy-agent.github.io/gatekeeper/website/docs/help#contributing-to-helm-chart)
for modifying the Helm chart.

---

### Overview (`demo/agilebank/README.md`)

> [!NOTE]
> Be sure to look at the [prerequisite](https://open-policy-agent.github.io/gatekeeper/website/docs/install#prerequisites) and Gatekeeper [installation](https://open-policy-agent.github.io/gatekeeper/website/docs/install#installation) steps before attempting to run the script. 

> [!NOTE]
> Use the latest version of Gatekeeper as some of the features are only available in the latest Gatekeeper release and some of the features are only compatible with Kubernetes v1.19+.

> [!TIP]
> If you are new to k8s, you can stand up a simple cluster using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/): `kind create cluster`.

This is a demo involving a fictitious bank named Agile Bank.

To run, execute `demo.sh` and press enter.

---

### Overview (`demo/basic/README.md`)

> [!NOTE]
> Be sure to look at the [prerequisite](https://open-policy-agent.github.io/gatekeeper/website/docs/install#prerequisites) and Gatekeeper [installation](https://open-policy-agent.github.io/gatekeeper/website/docs/install#installation) steps before attempting to run the script.

> [!TIP]
> If you are new to k8s, you can stand up a simple cluster using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/): `kind create cluster`.

Demo of basic Gatekeeper functionality.

To run, execute `demo.sh` and press enter.

---

### Overview (`demo/k8s-validating-admission-policy/README.md`)

> [!WARNING]
> This is a demo of an alpha and a beta feature and is subject to change.

This demo shows two new capabilities:
1. [beta] Together with Gatekeeper and gator CLI, you can get admission, audit, and shift left validations for both Validating Admission Policy style CEL-based and OPA Rego policies, even for clusters that do not support Kubernetes Validating Admission Policy feature yet.
1. [alpha] Gatekeeper can be enabled to generate Kubernetes Validating Admission Policy and Binding resources such that admission validation can be handled by [Kubernetes's in-process Validating Admission Policy Controller](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/) instead of the Gatekeeper admission webhook. In the event the Validating Admission Policy Controller fails open, then Gatekeeper admission webhook can act as a fallback. This requires clusters with the Kubernetes Validating Admission Policy feature enabled.

Please refer to https://open-policy-agent.github.io/gatekeeper/website/docs/next/validating-admission-policy for pre-requisites and configuration steps. 

## Demo

<img width= "900" height="500" src="demo.gif" alt="vap demo">

---

### Overview (`demo/scoped-enforcement-actions/README.md`)

> [!WARNING]
> This is a demo of an alpha feature and is subject to change.

This demo shows:

1. Configuring different validation actions for different enforcement points.
2. Integration with VAP as enforcement point such that admission validation can be handled by [Kubernetes's in-process Validating Admission Policy Controller](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/) instead of the Gatekeeper admission webhook. In the event the Validating Admission Policy Controller fails open, then Gatekeeper admission webhook can act as a fallback. This requires clusters with the Kubernetes Validating Admission Policy feature enabled.

Please refer to <https://open-policy-agent.github.io/gatekeeper/website/docs/next/validating-admission-policy> for pre-requisites and configuration steps.

## Demo

<img width= "900" height="500" src="demo.gif" alt="vap demo">

---

### Overview (`docs/design/README.md`)

# Design Docs
Generally, design docs are on Google docs:

## In Development

## Proposed
* [Admission Violation Export](admission-violation-export.md)
* [Namespace-Scoped Constraints](https://docs.google.com/document/d/1-pY7B5C6R0fjUbDu8izlcP7MSUDVDHv5XK16BFyTGRc/edit#heading=h.w8j68o8vjdts)
* [Sync Resource](https://docs.google.com/document/d/1ZbXaEh7v_HcgrRu7N-kEucU2pXyq1Rt7cSmmFOBN2q8/edit)
* [External Data Response Cache](https://docs.google.com/document/d/1nl6iWMmh9CRT0A6cr-Nkfofv9wp210Bkf6ilLq9LLBo/edit)
* [Gator SyncSet Support](https://docs.google.com/document/d/1mBvy6Y7TDyZswdYlFBHB3Mi2irLVqga_7ZoZvfPIU0A/edit)
* [Connection config CRD and controller for Pubsub](https://docs.google.com/document/d/12P3LCaOAQO9Uts4cVljHXkRgukEyWqyLketDP0rFq8A/edit#heading=h.9oaxevykg8w6)
* [Export Audit Violations without pubsub](https://docs.google.com/document/d/19sguUYd_VVhf2Gmy2SLMx1fwaxvrdqLxes3hTVH0DhU/edit)

## Implemented
* [Gatekeeper V3 Accepted Design](https://docs.google.com/document/d/1qsfeCx-Rx61Xm6JqJK-i67Gk_y__lNebdakmnhCdM7w/edit)
   * [Initial v3 Design Proposal](https://docs.google.com/document/d/1GgebCUkQ6WiS_DFk24jAnS51hQz6kpIRjfkzVW3J2Cs/edit)
   * [Initial v3 Design Proposal -- Detailed Design](https://docs.google.com/document/d/1VykioikDtcEtGIMQ_jsgCPEQDt5pecbEaDgA-hGryMo/edit)
* [Dynamic Watch Design for OPA/Gatekeeper](https://docs.google.com/document/d/1WWtYajE-Vfr1TDetWktjpYeMarx2PTogmIr_2Gmhkt0/edit)
* [Architecture Diagram](https://docs.google.com/document/d/1-0J8XV3Yavb7LiMkNIoyBp9MY021TrtKyu_GlpCNBU8/edit)
* [Audit Design Doc](https://docs.google.com/document/d/1VGXXb9i3-CETJvuiskLMahGceFQZh1wUffMXHdqRtck/edit)
* [Dry-Run Design Doc](https://docs.google.com/document/d/1H-JS4pJZvN_zpdfrwnu5Drsq8_qhHvk0El2s5a_SrWI/edit)
* [Constraint Framework Client Interface](https://docs.google.com/document/d/1QwqRO0D5MQsNM1D6SuH8yWACa5nSZKjI7PGzl7F0a_g/edit)
* [Logging Design Doc](https://docs.google.com/document/d/1jPl8sqZU2AEE-lxEQ-8Q2kKFS5OD93CuMm9y-htzUf8/edit)
* [Namespace Exclusion Design doc](https://docs.google.com/document/d/1PjpFrhiQu2DNl3wFS5Ts-z8yx9EwQnafhNIp1PJvFQQ/edit)
* [Metrics Design Issue](https://github.com/open-policy-agent/gatekeeper/issues/157#issuecomment-553015292)
* [Gatekeeper v1beta1 CRD Deprecation](https://docs.google.com/document/d/1quP6ScoPiKDJrykOaReP8xRFdl66LO0586P_v5lfnQY/edit)
* [Compiler Sharding Design](https://docs.google.com/document/d/1CV9HCp8TG-q_B6TltufHIkXcTrb03LTPWzD2Vr4R_ec/edit)
* [Template e2e Testing Design](https://docs.google.com/document/d/1_DDhxDYjVxyZk090F-GznHTeT5jFMpwjEXLLhzR3AoU/edit)
* [ByPod Status Design](https://docs.google.com/document/d/1kPb3B1I6FBsthpR6hp0Q3SEB11iXoSSuWbj9t1q-_58/edit)
* [Mutation Design - 4th Edition (current approach)](https://docs.google.com/document/d/1FGJ8A9_JnGJu-pU0u6hh37JKWw7j7GhMfrvTFL9sfUA/edit)
   * [Mutation Interfaces (for the current approach)](https://docs.google.com/document/d/1ihhUKly1YFJfvmTKjJLAOkQlrM1Oexr147IJbSHu5Ao/edit)
   * [OPA Gatekeeper Mutation (alternate proposal)](https://docs.google.com/document/d/11V3zfQ75ugxUy_I2o6AqjWbhw1PKcMh8v3Cf8_uuwdU/edit)
   * [Mutation Revised Design Doc (June 2019)](https://docs.google.com/document/d/1jluk3xL3dLxsE_9C69XWVOrSyLqzsySY0W7r9Yl0i68/edit&resourcekey=0-A4jzI3xwwxfggM9uvwctAw)
   * [Mutation Initial Design Doc (April 2019)](https://docs.google.com/document/d/1-TRvdND3Q-HPzIg8pe2ZtYNkOBDnQ2CxC7SWhA0lP6g/edit)
* [External Data](https://docs.google.com/document/d/1tXsoXWFzoCdWY8BqxXCNr5qXkTbGgEf2-sEpvGSE4ZQ/edit)
* [gator validate](https://docs.google.com/document/d/1LG-GfOlXjWzz0wNCb8jdzIMplZqkyrkMmTLYx05CKY4/edit)
* [External Data TLS Support](https://docs.google.com/document/d/1z43LI38twxPiUHPuktWPB1xMnsYr7SaVgczq-WsBhck/edit)
* [Export violations using pub-sub](https://docs.google.com/document/d/1xu6c99m_qBOpztAc8uUnoY6ST8UiXyyJzrXOmMmJQ9I/edit)
* [Versioning of Constraint Templates](https://docs.google.com/document/d/1Sg4HrNl9EYkNbn6wSGcyxULELrIrNbqS28djvNtHYoY/edit)
* [Gatekeeper-to-VAP User Flow](https://docs.google.com/document/d/1UELB0dmt10K5jBwETUnSKKQN7qeivOjvi-AvzFTOsHw/edit#heading=h.557kq3533dz3)
* [Gatekeeper Enforcement Actions](https://docs.google.com/document/d/1qEzDVcmwPysb3ejvTYKPkHJm3Db3Yr7zShwmgFOsR_k/edit#heading=h.6ewsycnqnfl)

## Roadmap (in development)
* See [milestones](https://github.com/open-policy-agent/gatekeeper/milestones?direction=asc&sort=due_date)

## Roadmap (complete)
* [GA Development Path](https://docs.google.com/document/d/19iMT3CQ_DFKfSy9Ypxty4QEFyNH5U_ZO3RF056NtL00/edit)
* [Post-MVP Features Doc](https://docs.google.com/document/d/1xtfrEGcA7MxRlMox-WSOQEpZ58gXWUU4S-Jeg47fQ6s/edit)
* [MVP for Alpha](https://docs.google.com/document/d/18xonIGw5iM_U4wbgl18O6G4xSpShnZA3rM8vyRPGLfg/edit)

## Discussions

These docs may not be design docs in themselves, but seek to influence design
decisions

* [Mutation Convergence Proof](https://docs.google.com/document/d/1ZGV9H0xpafogtpMy_GnZVSHygwa01VsBtxyD3nWd_BA/edit)
   * This looks at the elements of mutation that allow us to assert that any combination of mutators should converge
     and should serve as a guide when considering changes in behavior to mutation.
* [Mutation Dynamics](https://docs.google.com/document/d/1VkNIWPrHnaPbMRfkjyhyAPWoloiOq0lpTIHbTvBhVUA/edit)
   * A dissection of the mutation problem space, attempting to break down the
     salient behavioral elements and figure out what's needed for a
     user-friendly set of mutation primitives.
* [Mutation Transience](https://docs.google.com/document/d/1cKK1LQDm5LYu3Iqbi0HXrK5nacjEB88xGEJF8qwH708/edit)
   * Looking at how a mutation webhook may behave during configuration changes and discussing what that might mean in terms
     of necessary status fields and best practices for writing mutators.
* [Finalizers in OPA Gatekeeper](https://docs.google.com/document/d/179uwLOU_t8TjUyxRagDN6qKJsJqJirIS7HDvg2ft1yw/edit)
   * This doc discusses the impact the existence of finalizers has on running
     OPA Gatekeeper. Its points have either been addressed or are on track
     to being addressed.

---

### Overview (`third_party/demo-magic/README.md`)

# Demo Magic

demo-magic.sh is a handy shell script that enables you to script repeatable demos in a bash environment so you don't have to type as you present. Rather than trying to type commands when presenting you simply script them and let demo-magic.sh run them for you.

## Features
- Simulates typing. It looks like you are actually typing out commands
- Allows you to actually run commands or pretend to do so.
- Can hide commands from presentation. Useful for behind the scenes stuff that doesn't need to be shown.

## Functions

### pe
Print and Execute. This function will simulate typing whatever you give it. It will then pause until you press <kbd>ENTER</kbd>. After your keypress it will run the command.

```bash
#!/bin/bash

pe "ls -l"
```

### p
Print only. This function will simulate typing whatever you give it. It will not run the command. After typing it will pause until you press <kbd>ENTER</kbd>. After your keypress it will move on to the next instruction in your script.

```bash
#!/bin/bash

p "ls -l"
```

### wait
Waits for the user to press <kbd>ENTER</kbd>.

If `PROMPT_TIMEOUT` is defined and > 0 the demo will automatically proceed after the amount of seconds has passed.

```bash
#!/bin/bash

# Will wait until user presses enter
PROMPT_TIMEOUT=0
wait

# Will wait max 5 seconds until user presses
PROMPT_TIMEOUT=5
wait

```

### cmd
Enters script into interactive mode and allows newly typed commands to be executed within the script
```
#!/bin/bash

cmd
```

## Getting Started
Create a shell script and include demo-magic.sh

```bash
#!/bin/bash

########################
# include the magic
########################
. demo-magic.sh

# hide the evidence
clear

# Put your stuff here
```

Then use the handy functions to run through your demo.

## Command line usage
demo-magic.sh exposes 3 options out of the box to your script.
- `-d` - disable simulated typing. Useful for debugging
- `-h` - prints the usage text
- `-n` - set no default waiting after `p` and `pe` functions
- `-w` - set no wait timeout after `p` and `pe` functions

```bash
$ ./my-demo.sh -h

Usage: ./my-demo.sh [options]

  Where options is one or more of:
  -h  Prints Help text
  -d  Debug mode. Disables simulated typing
  -n  No wait
  -w  Waits max the given amount of seconds before proceeding with demo (e.g. `-w5`)
```

## Useful Tricks

### Faking network connections
Network connections during demos are often unreliable. Try and fake whatever commands would rely on a network connection. For example: Instead of trying to install node modules in a node.js application you can fake it. You can install the node_modules at home on your decent network. Then rename the directory and pretend to install it later by symlinking. If you want to be thorough you can capture the output of npm install into a log file then cat it out later to simulate the install.

```bash
#!/bin/bash

########################
# include the magic
########################
. demo-magic.sh

# hide the evidence
clear

# this command is typed and executed
pe "cd my-app"

# this command is merely typed. Not executed
p "npm install"

# this command runs behind the scenes
ln -s cached_node_modules node_modules

# cat out a log file that captures a previous successful node modules install
cat node-modules-install.log

# now type and run the command to start your app
pe "node index.js"
```

### No waiting
The -n _no wait_ option can be useful if you want to print and execute multiple commands.

```bash
# include demo-magic
. demo-magic.sh -n

# add multiple commands
pe 'git status'
pe 'git log --oneline --decorate -n 20'
```

However this will oblige you to define your waiting points manually e.g.
```bash
...
# define waiting points
pe 'git status'
pe 'git log --oneline --decorate -n 20'
wait
pe 'git pull'
pe 'git log --oneline --decorate -n 20'
wait
```

---

### Overview (`third_party/k8s.io/README.md`)

# k8s.io/kubernetes

Forked from k8s.io/kubernetes@139c6daf302442aa19fed6cba8732a1b5c0eb1e0

This is a light fork to use scripts from kubernetes/kubernetes for gatekeeper's use cases.

The original code can be found at https://github.com/kubernetes/kubernetes/tree/139c6daf302442aa19fed6cba8732a1b5c0eb1e0.

---

### Overview (`manifest_staging/charts/gatekeeper/README.md`)

# Gatekeeper Helm Chart

## Get Repo Info

```console
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
```

_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._

## Install Chart

```console
# Helm install with gatekeeper-system namespace already created
$ helm install -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper

# Helm install and create namespace
$ helm install -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper --create-namespace

```

_See [parameters](#parameters) below._

_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._

## Upgrade Chart

**Upgrading from < v3.4.0**
Chart 3.4.0 deprecates support for Helm 2 and also removes the creation of the `gatekeeper-system` Namespace from within
the chart. This follows Helm 3 Best Practices.

Option 1:
A simple way to upgrade is to uninstall first and re-install with 3.4.0 or greater.

```console
$ helm uninstall gatekeeper
$ helm install -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper --create-namespace

```

Option 2:
Run the `helm_migrate.sh` script before installing the 3.4.0 or greater chart. This will remove the Helm secret for the
original release, while keeping all of the resources. It then updates the annotations of the resources so that the new
chart can import and manage them.

```console
$ helm_migrate.sh
$ helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper
```

**Upgrading from >= v3.4.0**

```console
$ helm upgrade -n gatekeeper-system [RELEASE_NAME] gatekeeper/gatekeeper
```

_See [helm 2 to 3](https://helm.sh/docs/topics/v2_v3_migration/) for Helm 2 migration documentation._

## Exempting Namespace

The Helm chart automatically sets the Gatekeeper flag `--exempt-namespace={{ .Release.Namespace }}` in order to exempt
the namespace where the chart is installed, and adds the `admission.gatekeeper.sh/ignore` label to the namespace during
a post-install hook.

_See [Exempting Namespaces](https://open-policy-agent.github.io/gatekeeper/website/docs/exempt-namespaces) for more
information._

## Parameters

| Parameter                                                  | Description                                                                                                                                                                                                                                                                                    | Default                                                                                                                                                               |
|:-----------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| postInstall.labelNamespace.enabled                         | Add labels to the namespace during post install hooks                                                                                                                                                                                                                                          | `true`                                                                                                                                                                |
| postInstall.labelNamespace.extraNamespaces                 | The extra namespaces that need to have the label during post install hooks                                                                                                                                                                                                                     | `[]`                                                                                                                                                                  |
| postInstall.labelNamespace.extraAnnotations                | Extra annotations added to the post install Job                                                                                                                                                                                                                                                | `{}`                                                                                                                                                                  |
| postInstall.labelNamespace.image.repository                | Image with kubectl to label the namespace                                                                                                                                                                                                                                                      | `openpolicyagent/gatekeeper-crds`                                                                                                                                     |
| postInstall.labelNamespace.image.tag                       | Image tag                                                                                                                                                                                                                                                                                      | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| postInstall.labelNamespace.image.pullPolicy                | Image pullPolicy                                                                                                                                                                                                                                                                               | `IfNotPresent`                                                                                                                                                        |
| postInstall.labelNamespace.image.pullSecrets               | Image pullSecrets                                                                                                                                                                                                                                                                              | `[]`                                                                                                                                                                  |
| postInstall.labelNamespace.extraRules                      | Extra rules for the gatekeeper-update-namespace-label Role                                                                                                                                                                                                                                     | `[]`                                                                                                                                                                  |
| postInstall.labelNamespace.priorityClassName               | Priority class name for gatekeeper-update-namespace-label Job                                                                                                                                                                                                                                  | ``                                                                                                                                                                    |
| postInstall.probeWebhook.enabled                           | Probe webhook API post install. When enabled along with `postInstall.labelNamespace.enabled`, this probe will run as part of `postInstall.labelNamespace` Job as an initContainer                                                                                                              | `true`                                                                                                                                                                |
| postInstall.probeWebhook.image.repository                  | Image with curl to probe the webhook API                                                                                                                                                                                                                                                       | `curlimages/curl`                                                                                                                                                     |
| postInstall.probeWebhook.image.tag                         | Image tag                                                                                                                                                                                                                                                                                      | `8.20.0`                                                                                                                                                              |
| postInstall.probeWebhook.image.pullPolicy                  | Image pullPolicy                                                                                                                                                                                                                                                                               | `IfNotPresent`                                                                                                                                                        |
| postInstall.probeWebhook.image.pullSecrets                 | Image pullSecrets                                                                                                                                                                                                                                                                              | `[]`                                                                                                                                                                  |
| postInstall.probeWebhook.waitTimeout                       | Total time to wait for the webhook API to become available                                                                                                                                                                                                                                     | `60`                                                                                                                                                                  |
| postInstall.probeWebhook.httpTimeout                       | HTTP client timeout                                                                                                                                                                                                                                                                            | `2`                                                                                                                                                                   |
| postInstall.probeWebhook.insecureHTTPS                     | Ignore server SSL certificate                                                                                                                                                                                                                                                                  | `false`                                                                                                                                                               |
| postInstall.probeWebhook.priorityClassName                 | Priority class name for gatekeeper-probe-webhook-post-install Job                                                                                                                                                                                                                              | ``                                                                                                                                                                    |
| postInstall.affinity                                       | The affinity to use for pod scheduling in postInstall hook jobs                                                                                                                                                                                                                                | `{}`                                                                                                                                                                  |
| postInstall.tolerations                                    | The tolerations to use for pod scheduling in postInstall hook jobs                                                                                                                                                                                                                             | `[]`                                                                                                                                                                  |
| postInstall.nodeSelector                                   | The node selector to use for pod scheduling in postInstall hook jobs                                                                                                                                                                                                                           | `kubernetes.io/os: linux`                                                                                                                                             |
| postInstall.resources                                      | The resource request/limits for the container image in postInstall hook jobs                                                                                                                                                                                                                   | `{}`                                                                                                                                                                  |
| postInstall.securityContext                                | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| postUpgrade.labelNamespace.enabled                         | Add labels to the namespace during post upgrade hooks                                                                                                                                                                                                                                          | `false`                                                                                                                                                               |
| postUpgrade.labelNamespace.extraNamespaces                 | The extra namespaces that need to have the label during post upgrade hooks                                                                                                                                                                                                                     | `[]`                                                                                                                                                                  |
| postUpgrade.labelNamespace.extraAnnotations                | Extra annotations added to the post upgrade Job                                                                                                                                                                                                                                                | `{}`                                                                                                                                                                  |
| postUpgrade.labelNamespace.image.repository                | Image with kubectl to label the namespace                                                                                                                                                                                                                                                      | `openpolicyagent/gatekeeper-crds`                                                                                                                                     |
| postUpgrade.labelNamespace.image.tag                       | Image tag                                                                                                                                                                                                                                                                                      | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| postUpgrade.labelNamespace.image.pullPolicy                | Image pullPolicy                                                                                                                                                                                                                                                                               | `IfNotPresent`                                                                                                                                                        |
| postUpgrade.labelNamespace.image.pullSecrets               | Image pullSecrets                                                                                                                                                                                                                                                                              | `[]`                                                                                                                                                                  |
| postUpgrade.labelNamespace.priorityClassName               | Priority class name for gatekeeper-update-namespace-label-post-upgrade Job                                                                                                                                                                                                                     | ``                                                                                                                                                                    |
| postUpgrade.affinity                                       | The affinity to use for pod scheduling in postUpgrade hook jobs                                                                                                                                                                                                                                | `{}`                                                                                                                                                                  |
| postUpgrade.tolerations                                    | The tolerations to use for pod scheduling in postUpgrade hook jobs                                                                                                                                                                                                                             | `[]`                                                                                                                                                                  |
| postUpgrade.nodeSelector                                   | The node selector to use for pod scheduling in postUpgrade hook jobs                                                                                                                                                                                                                           | `kubernetes.io/os: linux`                                                                                                                                             |
| postUpgrade.resources                                      | The resource request/limits for the container image in postUpgrade hook jobs                                                                                                                                                                                                                   | `{}`                                                                                                                                                                  |
| postUpgrade.securityContext                                | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| preInstall.crdRepository.image.repository                  | Image with kubectl to update the CRDs. If not set, the `image.crdRepository` is used instead.                                                                                                                                                                                                  | `null`                                                                                                                                                                |
| preInstall.crdRepository.image.tag                         | Image tag                                                                                                                                                                                                                                                                                      | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| preUninstall.deleteWebhookConfigurations.enabled           | Delete webhooks before gatekeeper itself is uninstalled                                                                                                                                                                                                                                        | `false`                                                                                                                                                               |
| preUninstall.deleteWebhookConfigurations.image.repository  | Image with kubectl to delete the webhooks                                                                                                                                                                                                                                                      | `openpolicyagent/gatekeeper-crds`                                                                                                                                     |
| preUninstall.deleteWebhookConfigurations.image.tag         | Image tag                                                                                                                                                                                                                                                                                      | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| preUninstall.deleteWebhookConfigurations.image.pullPolicy  | Image pullPolicy                                                                                                                                                                                                                                                                               | `IfNotPresent`                                                                                                                                                        |
| preUninstall.deleteWebhookConfigurations.image.pullSecrets | Image pullSecrets                                                                                                                                                                                                                                                                              | `[]`                                                                                                                                                                  |
| preUninstall.deleteWebhookConfigurations.extraRules        | Extra rules for the gatekeeper-delete-webhook-configs Role                                                                                                                                                                                                                                     | `[]`                                                                                                                                                                  |
| preUninstall.deleteWebhookConfigurations.priorityClassName | Priority class name for gatekeeper-delete-webhook-configs Job                                                                                                                                                                                                                                  | ``                                                                                                                                                                    |
| preUninstall.affinity                                      | The affinity to use for pod scheduling in preUninstall hook jobs                                                                                                                                                                                                                               | `{}`                                                                                                                                                                  |
| preUninstall.tolerations                                   | The tolerations to use for pod scheduling in preUninstall hook jobs                                                                                                                                                                                                                            | `[]`                                                                                                                                                                  |
| preUninstall.nodeSelector                                  | The node selector to use for pod scheduling in preUninstall hook jobs                                                                                                                                                                                                                          | `kubernetes.io/os: linux`                                                                                                                                             |
| preUninstall.resources                                     | The resource request/limits for the container image in preUninstall hook jobs                                                                                                                                                                                                                  | `{}`                                                                                                                                                                  |
| preUninstall.securityContext                               | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| upgradeCRDs.enabled                                        | Upgrade CRDs using pre-install/pre-upgrade hooks                                                                                                                                                                                                                                               | `true`                                                                                                                                                                |
| upgradeCRDs.extraRules                                     | Extra rules for the gatekeeper-admin-upgrade-crds ClusterRole                                                                                                                                                                                                                                  | `[]`                                                                                                                                                                  |
| upgradeCRDs.priorityClassName                              | Priority class name for gatekeeper-update-crds-hook Job                                                                                                                                                                                                                                        | ``                                                                                                                                                                    |
| crds.affinity                                              | The affinity to use for pod scheduling in crds hook jobs                                                                                                                                                                                                                                       | `{}`                                                                                                                                                                  |
| crds.tolerations                                           | The tolerations to use for pod scheduling in crds hook jobs                                                                                                                                                                                                                                    | `[]`                                                                                                                                                                  |
| crds.nodeSelector                                          | The node selector to use for pod scheduling in crds hook jobs                                                                                                                                                                                                                                  | `kubernetes.io/os: linux`                                                                                                                                             |
| crds.resources                                             | The resource request/limits for the container image in crds hook jobs                                                                                                                                                                                                                          | `{}`                                                                                                                                                                  |
| crds.securityContext                                       | Security context applied to the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 65532, "runAsNonRoot": true, "runAsUser": 65532 }` |
| auditInterval                                              | The frequency with which audit is run                                                                                                                                                                                                                                                          | `60`                                                                                                                                                                  |
| constraintViolationsLimit                                  | The maximum # of audit violations reported on a constraint                                                                                                                                                                                                                                     | `20`                                                                                                                                                                  |
| auditFromCache                                             | Take the roster of resources to audit from the audit cache                                                                                                                                                                                                                                     | `false`                                                                                                                                                               |
| auditChunkSize                                             | (alpha) Chunk size for listing cluster resources for audit                                                                                                                                                                                                                             | `500`                                                                                                                                                                 |
| auditMatchKindOnly                                         | Only check resources of the kinds specified in all constraints defined in the cluster.                                                                                                                                                                                                         | `false`                                                                                                                                                               |
| disableAudit                                               | Disable audit controller                                                                                                                                                                                                                                                                       | `false`                                                                                                                                                               |
| disableMutation                                            | Disable mutation                                                                                                                                                                                                                                                                               | `false`                                                                                                                                                               |
| disableValidatingWebhook                                   | Disable the validating webhook                                                                                                                                                                                                                                                                 | `false`                                                                                                                                                               |
| validatingWebhookName                                      | The name of the `ValidatingWebhookConfiguration`                                                                                                                                                                                                                                               | `gatekeeper-validating-webhook-configuration`                                                                                                                         |
| validatingWebhookTimeoutSeconds                            | The timeout for the validating webhook in seconds                                                                                                                                                                                                                                              | `3`                                                                                                                                                                   |
| validatingWebhookFailurePolicy                             | The failurePolicy for the validating webhook                                                                                                                                                                                                                                                   | `Ignore`                                                                                                                                                              |
| validatingWebhookAnnotations                               | The annotations to add to the ValidatingWebhookConfiguration                                                                                                                                                                                                                                   | `{}`                                                                                                                                                                  |
| validatingWebhookObjectSelector                            | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's validation webhook unless measures are taken to control how exemption labels can be set.                          | `{}`                                                                                                                                                                  |
| validatingWebhookMatchConditions                           | The match conditions written in CEL to further refine which resources will be selected by the webhook. All match conditions must evaluate to true for the webhook to be called                                                                                                                 | `[]`                                                                                                                                                                  |
| validatingWebhookCheckIgnoreFailurePolicy                  | The failurePolicy for the check-ignore-label validating webhook                                                                                                                                                                                                                                | `Fail`                                                                                                                                                                |
| validatingWebhookExemptNamespacesLabels                    | Additional namespace labels that will be exempt from the validating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace.                                            | `{}`                                                                                                                                                                  |
| validatingWebhookCustomRules                               | Custom rules for selecting which API resources trigger the webhook. Mutually exclusive with `enableDeleteOperations`. NOTE: If you change this, ensure all your constraints are still being enforced.                                                                                          | `{}`                                                                                                                                                                  |
| validatingWebhookSubResources                                        | Rule for selecting which API subresources trigger the webhook.                                                                                                                                                                                             | `['pods/ephemeralcontainers', 'pods/exec', 'pods/log', 'pods/eviction', 'pods/portforward', 'pods/proxy', 'pods/attach', 'pods/binding', 'pods/resize', 'deployments/scale', 'replicasets/scale', 'statefulsets/scale', 'replicationcontrollers/scale', 'serviceaccounts/token', 'services/proxy', 'nodes/proxy', 'certificatesigningrequests/approval', 'services/status']`                                                                                                                           |
| validatingWebhookURL                                       | Custom URL for Kubernetes API server to use to reach the validating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used.                                                                                                                            | `null`                                                                                                                                                                |
| validatingWebhookScope                                     | The scope for the validating webhook. Does not work with `validatingWebhookCustomRules`                                                                                                                                                                                                        | `*`                                                                                                                                                                   |
| additionalValidatingWebhookConfigsToRotateCerts                                      | The name of additional `ValidatingWebhookConfiguration`s that the gatekeeper cert rotator should manage certs for                                                                                                                                                                                                                                               | `[]`                                                                                                                         |
| enableDeleteOperations                                     | Enable validating webhook for delete operations. Does not work with `validatingWebhookCustomRules`                                                                                                                                                                                             | `false`                                                                                                                                                               |
| enableConnectOperations                                    | Enable validating webhook for connect operations.                                                                                                                                                                                                                                              | `false`                                                                                                                                                               |
| enableExternalData                                         | Enable external data                                                                                                                                                                                                                                                                           | `true`                                                                                                                                                                |
| enableGeneratorResourceExpansion                           | Enable generator resource expansion (beta feature)                                                                                                                                                                                                                                             | `true`                                                                                                                                                                |
| enableTLSHealthcheck                                       | Enable probing webhook API with certificate stored in certDir                                                                                                                                                                                                                                  | `false`                                                                                                                                                               |
| maxServingThreads                                          | Limit the number of concurrent calls the validation backend made by the validation webhook. -1 limits this value to GOMAXPROCS. Configuring this value may lower max RAM usage and limit CPU throttling, Tuning it can optimize serving capacity.                                              | `-1`                                                                                                                                                                  |
| metricsBackends                                            | Metrics exporters to use. Valid exporters are: `prometheus`, `stackdriver`, and `opentelemetry` starting from Gatekeeper 3.15                                                                                                                                                                  | `["prometheus"]`                                                                                                                                                      |                                                                                        |
| otlpEndpoint                                               | The OTLP endpoint for the OpenTelemetry metric exporter                                                                                                                                                                                                                                        | `""`                                                                                                                                                                  |
| otlpMetricInterval                                         | The interval to read metrics for the OpenTelemetry exporter                                                                                                                                                                                                                                    | `"10s"`                                                                                                                                                                 |
| stackdriverOnlyWhenAvailable                               | Only attempt to start the stackdriver exporter if credentials are available                                                                                                                                                                                                                    | `false`                                                                                                                                                               |
| stackdriverMetricInterval                                  | Interval to read metrics for stackdriver exporter                                                                                                                                                                                                                                              | `"10s"`                                                                                                                                                                 |
| mutatingWebhookName                                        | The name of the `MutatingWebhookConfiguration`                                                                                                                                                                                                                                                 | `gatekeeper-mutating-webhook-configuration`                                                                                                                           |
| mutatingWebhookFailurePolicy                               | The failurePolicy for the mutating webhook                                                                                                                                                                                                                                                     | `Ignore`                                                                                                                                                              |
| mutatingWebhookReinvocationPolicy                          | The reinvocationPolicy for the mutating webhook                                                                                                                                                                                                                                                | `Never`                                                                                                                                                               |
| mutatingWebhookAnnotations                                 | The annotations to add to the MutatingWebhookConfiguration                                                                                                                                                                                                                                     | `{}`                                                                                                                                                                  |
| mutatingWebhookExemptNamespacesLabels                      | Additional namespace labels that will be exempt from the mutating webhook. Please note that anyone in the cluster capable to manage namespaces will be able to skip all Gatekeeper validation by setting one of these labels for their namespace.                                              | `{}`                                                                                                                                                                  |
| mutatingWebhookObjectSelector                              | The label selector to further refine which namespaced resources will be selected by the webhook. Please note that an exemption label means users can circumvent Gatekeeper's mutation webhook unless measures are taken to control how exemption labels can be set.                            | `{}`                                                                                                                                                                  |
| mutatingWebhookMatchConditions                             | The match conditions written in CEL to further refine which resources will be selected by the webhook. All match conditions must evaluate to true for the webhook to be called                                                                                                                 | `[]`                                                                                                                                                                  |
| mutatingWebhookTimeoutSeconds                              | The timeout for the mutating webhook in seconds                                                                                                                                                                                                                                                | `3`                                                                                                                                                                   |
| mutatingWebhookCustomRules                                 | Custom rules for selecting which API resources trigger the webhook. NOTE: If you change this, ensure all your constraints are still being enforced.                                                                                                                                            | `{}`                                                                                                                                                                  |
| mutatingWebhookSubResources                                        | Rule for selecting which API subresources trigger the webhook.                                                                                                                                                                                             | `['pods/ephemeralcontainers', 'pods/exec', 'pods/log', 'pods/eviction', 'pods/portforward', 'pods/proxy', 'pods/attach', 'pods/binding', 'pods/resize', 'deployments/scale', 'replicasets/scale', 'statefulsets/scale', 'replicationcontrollers/scale', 'serviceaccounts/token', 'services/proxy', 'nodes/proxy', 'certificatesigningrequests/approval', 'services/status']`                                                                                                                           |
| mutatingWebhookURL                                         | Custom URL for Kubernetes API server to use to reach the mutating webhook pod. If not set, the default of connecting via the kubernetes service endpoint is used.                                                                                                                              | `null`                                                                                                                                                                |
| mutatingWebhookScope                                       | The scope for the mutating webhook. Does not work with `mutatingWebhookCustomRules`                                                                                                                                                                                                            | `*`                                                                                                                                                                   |
| additionalMutatingWebhookConfigsToRotateCerts                                      | The name of additional `MutatingWebhookConfiguration`s that the gatekeeper cert rotator should manage certs for                                                                                                                                                                                                                                               | `[]`                                                                                                                         |
| emitAdmissionEvents                                        | (alpha) Emit K8s events in configurable namespace for admission violations                                                                                                                                                                                                              | `false`                                                                                                                                                               |
| emitAdmissionAuditAnnotations                              | (alpha) Add bounded violation details to API server audit events for Gatekeeper validation webhook and native validation-failure annotations for generated VAPs                                                                                                                          | `false`                                                                                                                                                               |
| admissionAuditAnnotationsIncludeSuccess                    | (alpha) When admission audit annotations are enabled, also annotate zero-violation webhook requests and add evaluation markers to generated VAPs. Deny, warn, and dryrun violations remain audited regardless of this setting.                                                             | `false`                                                                                                                                                               |
| emitAuditEvents                                            | (alpha) Emit K8s events in configurable namespace for audit violations                                                                                                                                                                                                                  | `false`                                                                                                                                                               |
| logStatsAdmission                                          | (alpha) Log stats for admission webhook                                                                                                                                                                                                                                                 | `false`                                                                                                                                                               |
| logStatsAudit                                              | (alpha) Log stats metrics for the audit run                                                                                                                                                                                                                                             | `false`                                                                                                                                                               |
| enableK8sNativeValidation                                  | Enable the K8s Native Validating driver to allow constraint templates to use rules written in VAP-style CEL                                                                                                                                                                                                                 | `true`                                                                                                                                                               |
| defaultK8sNativeValidationFailurePolicy                    | (beta) Failure policy to use when a K8sNativeValidation source omits failurePolicy. Allowed values are Fail or Ignore. This is separate from validatingWebhookFailurePolicy, which controls the Kubernetes webhook configuration failure policy.                                                                                                                     | `Fail`                                                                                                                                                               |
| defaultCreateVAPForTemplates                                      | (beta) Create VAP resource for template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy unless generateVAP: true is set on constraint template explicitly, true: create Validating Admission Policy unless generateVAP: false is set on constraint template explicitly.                                                                                                                                                                                                                  | `true`                                                                                                                                                               |
| defaultCreateVAPBindingForConstraints                             | (beta) Create VAPBinding resource for constraint of the template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy Binding, true: create Validating Admission Policy Binding.                                                                                                                                                                                                                  | `true`                                                                                                                                                               |
| vapGenerationMode                                         | (alpha) VAP generation topology. `template` creates one parameterized VAP per ConstraintTemplate. `constraint` creates one VAP with inlined parameters per Constraint. | `template` |
| defaultWaitForVAPBGeneration                             | (beta) Wait time in seconds before generating a ValidatingAdmissionPolicyBinding after a constraint CRD is created.                                                                                                                                                                                                                 | `30`                                                                                                                                                               |
| auditEventsInvolvedNamespace                               | Emit audit events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Audit events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in         | `false`                                                                                                                                                               |
| admissionEventsInvolvedNamespace                           | Emit admission events for each violation in the involved objects namespace, the default (false) generates events in the namespace Gatekeeper is installed in. Admission events from cluster-scoped resources will continue to generate events in the namespace that Gatekeeper is installed in | `false`                                                                                                                                                               |
| logDenies                                                  | Log detailed info on each deny                                                                                                                                                                                                                                                                 | `false`                                                                                                                                                               |
| logLevel                                                   | Minimum log level                                                                                                                                                                                                                                                                              | `INFO`                                                                                                                                                                |
| image.pullPolicy                                           | The image pull policy                                                                                                                                                                                                                                                                          | `IfNotPresent`                                                                                                                                                        |
| image.repository                                           | Image repository                                                                                                                                                                                                                                                                               | `openpolicyagent/gatekeeper`                                                                                                                                          |
| image.release                                              | The image release tag to use                                                                                                                                                                                                                                                                   | Current release version: `v3.24.0-beta.0`                                                                                                                             |
| image.pullSecrets                                          | Specify an array of imagePullSecrets                                                                                                                                                                                                                                                           | `[]`                                                                                                                                                                  |
| resources                                                  | The resource request/limits for the container image                                                                                                                                                                                                                                            | limits: 1 CPU, 512Mi, requests: 100mCPU, 256Mi                                                                                                                        |
| nodeSelector                                               | The node selector to use for pod scheduling                                                                                                                                                                                                                                                    | `kubernetes.io/os: linux`                                                                                                                                             |
| controllerManager.containerName                            | Container name for controller manager                                                                                                                                                      | `manager`                                                                                                                                                             |
| controllerManager.podLabels                                | The labels to add to the controller manager pod                                                                                                                                                                                                                                                       | `{}`                                                                                                                                                                  |
| controllerManager.affinity                                 | The node affinity to use for controller manager pod scheduling                                                                                                                                                                                                                                 | `{}`                                                                                                                                                                  |
| controllerManager.topologySpreadConstraints                | The topology spread constraints to use for controller manager pod scheduling                                                                                                                                                                                                                   | `[]`                                                                                                                                                                  |
| controllerManager.tolerations                              | The tolerations to use for controller manager pod scheduling                                                                                                                                                                                                                                   | `[]`                                                                                                                                                                  |
| controllerManager.healthPort                               | Health port for controller manager                                                                                                                                                                                                                                                             | `9090`                                                                                                                                                                |
| controllerManager.port                                     | Webhook-server port for controller manager                                                                                                                                                                                                                                                     | `8443`                                                                                                                                                                |
| controllerManager.metricsPort                              | Metrics port for controller manager                                                                                                                                                                                                                                                            | `8888`                                                                                                                                                                |
| controllerManager.readinessTimeout                         | Timeout in seconds for the controller manager's readiness probe                                                                                                                                                                                                                                | `1`                                                                                                                                                                   |
| controllerManager.livenessTimeout                          | Timeout in seconds for the controller manager's liveness probe                                                                                                                                                                                                                                 | `1`                                                                                                                                                                   |
| controllerManager.logLevel                                 | The minimum log level for the controller manager, takes precedence over `logLevel` when specified                                                                                                                                                                                              | `null`                                                                                                                                                                |
| controllerManager.priorityClassName                        | Priority class name for controller manager                                                                                                                                                                                                                                                     | `system-cluster-critical`                                                                                                                                             |
| controllerManager.podSecurityContext                       | Security context on pod level for controller manager                                                                                                                                                                                                                                           | {fsGroup: 999, suplementalGroups: [999]}                                                                                                                              |
| controllerManager.exemptNamespaces                         | The exact namespaces to exempt by the admission webhook                                                                                                                                                                                                                                        | `[]`                                                                                                                                                                  |
| controllerManager.exemptNamespacePrefixes                  | The namespace prefixes to exempt by the admission webhook                                                                                                                                                                                                                                      | `[]`                                                                                                                                                                  |
| controllerManager.hostNetwork                              | Enables controllerManager to be deployed on hostNetwork                                                                                                                                                                                                                                        | `false`                                                                                                                                                               |
| controllerManager.dnsPolicy                                | Set the dnsPolicy for controllerManager pods                                                                                                                                                                                                                                                   | `ClusterFirst`                                                                                                                                                        |
| controllerManager.securityContext                          | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| controllerManager.tlsMinVersion                            | Set the minimum supported TLS version for validating and mutating webhook servers                                                                                                                                                                                                              | `1.3`                                                                                                                                                                 |
| controllerManager.extraRules                               | Extra rules for the gatekeeper-manager-role Role                                                                                                                                                                                                                                               | `[]`                                                                                                                                                                  |
| controllerManager.networkPolicy.enabled                    | Should a network policy for the controller manager be created                                                                                                                                                                                                                                  | `false`                                                                                                                                                               |
| controllerManager.networkPolicy.ingress                    | Additional ingress rules to be added to the controller manager network policy                                                                                                                                                                                                                  | `{}`                                                                                                                                                                  |
| controllerManager.strategyType                             | The strategy type to use for Controller Manager deployment                                                                                                                                                                                                                                     | `RollingUpdate`                                                                                                                                                       |
| controllerManager.strategyRollingUpdate                    | [RollingUpdate](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-update-deployment) configuration for Controller Manager deployment                                                                                                                               | `{}`                                                                                                                                                                  |
| controllerManager.disableWebhookOperation                                       | Disable webhook operation for controller manager                                                                                                                                                    | `false`                                                                                                                                                             |
| controllerManager.disableGenerateOperation                                       | Disable generate operation for controller manager                                                                                                                                                    | `true`                                                                                                                                                             |
| audit.containerName                                        | Container name for audit                                                                                                                                                                                                                                                     | `manager`                                                                                                                                                             |
| audit.podLabels                                            | The labels to add to the audit pod                                                                                                                                                                                                                                                       | `{}`                                                                                                                                                                  |
| audit.affinity                                             | The node affinity to use for audit pod scheduling                                                                                                                                                                                                                                              | `{}`                                                                                                                                                                  |
| audit.topologySpreadConstraints                            | The topology spread constraints to use for audit pod scheduling                                                                                                                                                                                                                                | `[]`                                                                                                                                                                  |
| audit.tolerations                                          | The tolerations to use for audit pod scheduling                                                                                                                                                                                                                                                | `[]`                                                                                                                                                                  |
| audit.priorityClassName                                    | Priority class name for audit controller                                                                                                                                                                                                                                                       | `system-cluster-critical`                                                                                                                                             |
| audit.podSecurityContext                                   | Security context for audit on pod level                                                                                                                                                                                                                                                        | {fsGroup: 999, suplementalGroups: [999]}                                                                                                                              |
| audit.hostNetwork                                          | Enables audit to be deployed on hostNetwork                                                                                                                                                                                                                                                    | `false`                                                                                                                                                               |
| audit.dnsPolicy                                            | Set the dnsPolicy for audit pods                                                                                                                                                                                                                                                               | `ClusterFirst`                                                                                                                                                        |
| audit.securityContext                                      | Security context applied on the container                                                                                                                                                                                                                                                      | `{ "allowPrivilegeEscalation": false, "capabilities": "drop": [all], "readOnlyRootFilesystem": true, "runAsGroup": 999, "runAsNonRoot": true, "runAsUser": 1000 }`    |
| audit.healthPort                                           | Health port for audit                                                                                                                                                                                                                                                                          | `9090`                                                                                                                                                                |
| audit.metricsPort                                          | Metrics port for audit                                                                                                                                                                                                                                                                         | `8888`                                                                                                                                                                |
| audit.readinessTimeout                                     | Timeout in seconds for audit's readiness probe                                                                                                                                                                                                                                                 | `1`                                                                                                                                                                   |
| audit.livenessTimeout                                      | Timeout in seconds for the audit's liveness probe                                                                                                                                                                                                                                              | `1`                                                                                                                                                                   |
| audit.logLevel                                             | The minimum log level for audit, takes precedence over `logLevel` when specified                                                                                                                                                                                                               | `null`                                                                                                                                                                |
| audit.disableGenerateOperation                            | Disable generate operation for audit                                                                                                                                                                                                                                                           | `false`                                                                                                                                                                |
| audit.disableAuditOperation                               | Disable audit operation for audit                                                                                                                                                                                                                                                              | `false`                                                                                                                                                                |
| audit.disableAuditSidecar                                 | Disable audit sidecar                                                                                                                                                                                                                                                              | `false`                                                                                                                                                                |
| audit.disableStatusOperation                              | Disable status operation for audit                                                                                                                                                                                                                                                             | `false`                                                                                                                                                                |
| enableViolationExport                                      | (alpha) Enable exporting audit violations to external systems                                                                                                                                                                                                                                               | `false`                                                                                                                                                               |
| enableAdmissionViolationExport                             | (alpha) Enable best-effort export of admission violations using the disk driver; Dapr and other backends are not supported                                                                                                                                                                                   | `false`                                                                                                                                                               |
| admission.exportSidecar                                    | Optional sidecar that streams and removes completed admission disk segments from the audit export volume                                                                                                                                                                                                   | See `values.yaml`                                                                                                                                                     |
| admission.disableExportSidecar                             | Disable the admission disk reader sidecar                                                                                                                                                                                                                                                                  | `true`                                                                                                                                                                |
| audit.connection                                           | (alpha) Connection name shared by audit and admission violation export                                                                                                                                                                                                                                      | `audit-connection`                                                                                                                                                    |
| audit.channel                                              | (alpha) Channel name shared by audit and admission violation export                                                                                                                                                                                                                                         | `audit-channel`                                                                                                                                                       |
| audit.exportVolume                                         | (alpha) Volume for audit pod to export violations.                                                                                                                                                                                                                                   | `{"name":"tmp-violations","emptyDir":{}}`                                                                                                                                                       |
| audit.exportVolumeMount.path                                         | (alpha) VolumeMount for audit pod manager container to export violations and sidecar container to read from.                                                                                                                                                                                                                                   | `/tmp/violations`                                                                                                                                                       |
| audit.exportSidecar                                        | (alpha) Sidecar container to read violations from disk.                                                                                                                                                                                                                                   | `{"name":"reader","image":"ghcr.io/open-policy-agent/fake-reader:latest","imagePullPolicy":"Always","securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsGroup":999,"runAsNonRoot":true,"runAsUser":1000,"seccompProfile":{"type":"RuntimeDefault"}},"volumeMounts":[{"mountPath":"/tmp/violations","name":"tmp-violations"}]}`                                                                                                                                                       |
| audit.exportConnection.path                                         | (alpha) Path for audit pod manager container to export violations and sidecar container to read from. Must be a child of volume mount path so the parent is writable.                                                                                                                                                                                                                          | `/tmp/violations/topics`                                                                                                                                                       |
| audit.exportConnection.maxAuditResults                         | (alpha) Maximum number of audit results that can be stored in the export path.                                                                                                                                                                                                                                   | 3                                                                                                                                                       |
| exportBackend                                              | (alpha) Backend to use for exporting violations, i.e. dapr, disk.                                                                                                                                                                                                      | ""                                                                                                                                                                    |
| replicas                                                   | The number of Gatekeeper replicas to deploy for the webhook                                                                                                                                                                                                                                    | `3`                                                                                                                                                                   |
| podAnnotations                                             | The annotations to add to the Gatekeeper pods                                                                                                                                                                                                                                                  | `container.seccomp.security.alpha.kubernetes.io/manager: runtime/default`                                                                                             |
| podLabels                                                  | The labels to add to the Gatekeeper pods                                                                                                                                                                                                                                                       | `{}`                                                                                                                                                                  |
| podCountLimit                                              | The maximum number of Gatekeeper pods to run                                                                                                                                                                                                                                                   | `100`                                                                                                                                                                 |
| secretAnnotations                                          | The annotations to add to the Gatekeeper secrets                                                                                                                                                                                                                                               | `{}`                                                                                                                                                                  |
| pdb.controllerManager.minAvailable                         | The number of controller manager pods that must still be available after an eviction                                                                                                                                                                                                           | `1`                                                                                                                                                                   |
| service.type                                               | Service type                                                                                                                                                                                                                                                                                   | `ClusterIP`                                                                                                                                                           |
| service.loadBalancerIP                                     | The IP address of LoadBalancer service                                                                                                                                                                                                                                                         | ``                                                                                                                                                                    |
| service.ipFamilyPolicy                                     | The IP family policy used for the service, for more information see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services).                                                                                                                      | ``                                                                                                                                                                    |
| service.ipFamilies                                         | List of IP families for the service. Can be "IPv4" and/or "IPv6"                                                                                                                                                                                                                               | ``                                                                                                                                                                    |
| service.healthzPort                                        | Service port to gatekeeper Webhook health port                                                                                                                                                                                                                                                 | `9090`                                                                                                                                                                |
| rbac.create                                                | Enable the creation of RBAC resources                                                                                                                                                                                                                                                          | `true`                                                                                                                                                                |
| externalCertInjection.enabled                              | Enable the injection of an external certificate. This disables automatic certificate generation and rotation                                                                                                                                                                                   | `false`                                                                                                                                                               |
| externalCertInjection.secretName                           | Name of secret for injected certificate                                                                                                                                                                                                                                                        | `gatekeeper-webhook-server-cert`                                                                                                                                      |
| externaldataProviderResponseCacheTTL                       | TTL for the external data provider response cache. Specify the duration in 'h', 'm', or 's' for hours, minutes, or seconds respectively.                                                                                                                                                       | `3m`                                                                                                                                                                  |
| commonAnnotations                                           | Additional annotations added to manager and audit Deployments only                                                                                                                                                                                                                              | `{}`                                                                                                                                                                  |
| extraVolumeMounts                                           | Extra volumeMounts injected into controller-manager and audit containers                                                                                                                                                                                                                        | `[]`                                                                                                                                                                  |
| extraVolumes                                                | Extra volumes injected into controller-manager and audit pods                                                                                                                                                                                                                                   | `[]`                                                                                                                                                                  |
| controllerManager.serviceAccount.automountServiceAccountToken | Whether to automount the service account token for controller-manager pods                                                                                                                                                                                                                      | `true`                                                                                                                                                                |
| audit.serviceAccount.automountServiceAccountToken           | Whether to automount the service account token for audit pods                                                                                                                                                                                                                                   | `true`                                                                                                                                                                |
| syncVAPEnforcementScope           | (beta) Synchronize ValidatingAdmissionPolicy enforcement scope with Gatekeeper's admission validation scope. When enabled, VAP resources inherit match criteria, conditions, and namespace exclusions from Gatekeeper's webhook configuration, Config resource and exempt namespace flags. This ensures consistent policy enforcement between Gatekeeper and VAP but triggers constraint template reconciliation on scope changes in Config resource or webhook configuration. This flag is set to true by default. It is deprecated and will be removed in Gatekeeper v3.24.                                                                                                                                                                                                               | `true`                                                                                                                                                                |
| logLevelKey                                                | JSON key for the log level field. Only set when specified.                                                                                                                                                                                                                                     | Not set (default: `level`)                                                                                                                                            |
| logLevelEncoder                                            | Encoder for the value of the log level field. Valid values: `lower`, `capital`, `color`, `capitalcolor`. Only set when specified.                                                                                                                                                              | Not set (default: `lower`)                                                                                                                                            |
| metricsAddr                                                | The address the metric endpoint binds to. Only set when specified.                                                                                                                                                                                                                             | Not set (default: `0`)                                                                                                                                                |
| readinessRetries                                           | The number of resource ingestion attempts allowed before the resource is disregarded. A value of -1 will retry indefinitely. Only set when specified.                                                                                                                                          | Not set (default: `0`)                                                                                                                                                |
| enablePprof                                                | Enable pprof profiling. Only set when specified.                                                                                                                                                                                                                                               | Not set (default: `false`)                                                                                                                                            |
| pprofPort                                                  | Port for pprof profiling. Only set when specified.                                                                                                                                                                                                                                             | Not set (default: `6060`)                                                                                                                                             |
| disableEnforcementActionValidation                         | Disable validation of the enforcementAction and scopedEnforcementActions field of a constraint. Only set when specified.                                                                                                                                                                       | Not set (default: `false`)                                                                                                                                            |
| enableReferentialRules                                     | Enable referential rules. Set to false to disallow referential constraints. Referential constraints read objects other than the object-under-test and may be subject to race conditions. Only set when specified.                                                                              | Not set (default: `true`)                                                                                                                                             |
| controllerManager.host                                     | The host address the webhook server listens on. Only set when specified.                                                                                                                                                       | Not set (default: all addresses)                                                                                                                                      |
| controllerManager.certDir                                  | The directory where certs are stored.                                                                                                                                                | Not set (default: `/certs`)                                                                                                                                           |
| controllerManager.certServiceName                          | The service name used to generate the TLS cert's hostname.                                                            | Not set (default: `gatekeeper-webhook-service`)                                                                                                                       |
| controllerManager.clientCAName                             | Name of the certificate authority bundle to authenticate the Kubernetes API server requests against. Only set when specified.                                                                                                                                                                  | Not set                                                                                                                                                               |
| controllerManager.clientCNName                             | Expected CN name on the client certificate attached by apiserver in requests to the webhook. Only set when specified.                                                                                                                                                                          | Not set (default: `kube-apiserver`)                                                                                                                                   |
| audit.apiCacheDir                                          | The directory where audit from api server cache are stored. Only set when specified.                                                                                                                                                                                                           | Not set (default: `/tmp/audit`)                                                                                                                                       |
| shutdownDelay                                              | Time in seconds the controller runtime shutdown gets delayed after receiving a pod termination event. Prevents failing webhooks on pod shutdown. Only set when specified.                                                                                                                       | Not set (default: `10`)                                                                                                                                               |
| enableRemoteCluster                                        | (alpha) Enable remote cluster mode where Gatekeeper operates against a target cluster specified via kubeconfig while running in the local cluster. Requires `kubeconfig` to also be set, and the kubeconfig file to be mounted via `extraVolumes`/`extraVolumeMounts`. Only set when specified. | Not set (default: `false`)                                                                                                                                            |
| kubeconfig                                                 | Path to kubeconfig file inside the container for remote cluster mode. The file must be mounted into the container using `extraVolumes` and `extraVolumeMounts`. Only set when specified.                                                                                                       | Not set                                                                                                                                                               |

## Contributing Changes

Please refer
to [Contributing to Helm Chart](https://open-policy-agent.github.io/gatekeeper/website/docs/help#contributing-to-helm-chart)
for modifying the Helm chart.

---

### Intro (`website/docs/intro.md`)

---
id: intro
title: Introduction
sidebar_label: Introduction
slug: /
---

## Goals

Every organization has policies. Some are essential to meet governance and legal requirements. Others help ensure adherence to best practices and institutional conventions. Attempting to ensure compliance manually would be error-prone and frustrating. Automating policy enforcement ensures consistency, lowers development latency through immediate feedback, and helps with agility by allowing developers to operate independently without sacrificing compliance.

Kubernetes allows decoupling policy decisions from the inner workings of the API Server by means of [admission controller webhooks](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/), which are executed whenever a resource is created, updated or deleted. Gatekeeper is a validating and mutating webhook that enforces CRD-based policies executed by [Open Policy Agent](https://github.com/open-policy-agent/opa), a policy engine for Cloud Native environments hosted by CNCF as a [graduated project](https://www.cncf.io/projects/open-policy-agent-opa/).

In addition to the `admission` scenario, Gatekeeper's audit functionality allows administrators to see what resources are currently violating any given policy.

Finally, Gatekeeper's engine is designed to be portable, allowing administrators to detect and reject non-compliant commits to an infrastructure-as-code system's source-of-truth, further strengthening compliance efforts and preventing bad state from slowing down the organization.

## Validation and mutation

Gatekeeper supports both validation and mutation, but they are configured with different policy resources and have different effects:

| Area | Policy resources | Effect |
| --- | --- | --- |
| Validation | [`ConstraintTemplate`](constrainttemplates.md) and `Constraint` resources | Evaluates resources and can deny, warn, dry-run, audit, or report violations without changing the resource. |
| Mutation | [`AssignMetadata`, `Assign`, `ModifySet`, and `AssignImage`](mutation.md) mutator resources | Changes matching resources during admission before validation evaluates the final object. |

Some concepts apply to both areas, such as match criteria and namespace exclusions. Other concepts are specific to validation constraints, including `enforcementAction`, audit results, and violation status.

## Looking for sample policies?

Please visit Gatekeeper [policy library](https://open-policy-agent.github.io/gatekeeper-library/website/) to find a collection of sample policies.

## How is Gatekeeper different from OPA?

Compared to using [OPA with its sidecar kube-mgmt](https://www.openpolicyagent.org/docs/kubernetes-admission-control.html) (aka Gatekeeper v1.0), Gatekeeper introduces the following functionality:

   * An extensible, parameterized [policy library](https://open-policy-agent.github.io/gatekeeper-library/website/)
   * Native Kubernetes CRDs for instantiating the policy library (aka "constraints")
   * Native Kubernetes CRDs for extending the policy library (aka "constraint templates")
   * Native Kubernetes CRDs for [mutation](mutation.md) support
   * Audit functionality
   * External data support

---

### Backwards Compatibility (`docs/Backwards_Compatibility.md`)

# Gatekeeper Backwards Compatibility

## Background
The Gatekeeper project specified a formalization of its backwards compatibility
goals as one of its requirements for reaching its GA milestone. Specifying a
strong stance on backwards compatibility is necessary for establishing a degree
of confidence as to what features users can rely on as they seek to use the
product and avoid churn. This document assumes
[Kubernetes' API compatibility guidelines](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md#on-compatibility)
as the default stance and explores exceptions unique to the Gatekeeper project.

## Exclusions
The following areas are out-of-scope for backwards compatibility as Gatekeeper
either has no control over their implementation, does not consider them to be
part of its API, or (in the case of security incidents), must be pragmatic in
weighing risk over convenience.

   * Rego/OPA
      * Gatekeeper does not control the design or implementation of Rego or OPA,
         rather it is a consumer of the project. As such, Gatekeeper will be
         subject to any backwards-incompatible changes to the Rego language.
   * Internal-only resources
      * These resources are intended only for consumption by the Gatekeeper
         project itself and are not intended for consumption by the user.
         These resources are subject to change at any time.
   * Constraint Template Library
      * The library is a consumer of Gatekeeper. As such, it is not bound by
         Gatekeeper's development constraints. That being said, the constraint
         template library should also establish its own philosophy on backwards
         compatibility. The documentation on
         [constraint template versioning](https://docs.google.com/document/d/1vB_2wm60WCVLXoegMrupqwqKAuW6gbwEIxg3vBQj6cs/edit#heading=h.t8fo692xfexq)
         would be a good place to start.
   * Gatekeeper Manifest / Helm template
      * The Gatekeeper manifest and Helm templates are reference deployment
      configurations for Gatekeeper, they are not themselves part of
      Gatekeeper's API. The ability to cleanly upgrade Gatekeeper by re-applying
      the manifest without additional work is subject to breakage. Examples of
      breaking manifest changes include: adding, removing or modifying resource
      kinds, names and contents. Such changes should be highlighted in the
      release notes for the version that creates them. The Gatekeeper binary is
      intended to be written in such a way that it is always possible to upgrade
      from version N to version N+1 without downtime, but the specifics for how
      to do so are out-of-scope for the project.
   * Security Incidents
      * In the event that there is a security incident that is impossible to fix
        without breaking either the schema or the behavior of the Gatekeeper
        API, we would not maintain 100% backwards compatibility at the cost of
        compromising security. We would expect such changes to be rare and
        limited in scope to only what is necessary to address the underlying
        security issue.

## Compatibility of the API
As of GA, Gatekeeper will adopt Kubernetes'
[guidelines on compatibility](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md#on-compatibility)
where possible for user-facing resources. The following section discusses places
where Gatekeeper intentionally deviates due to the above exceptions as well as
extra compatibility requirements it is adopting.

### Constraint Templates
Because the constraint template embeds Rego source code as an opaque string
which is then interpreted by OPA under-the-hood, it is possible for the meaning
of that string to change between releases if Rego itself makes a
non-backwards-compatible release. However, the Rego interface that Gatekeeper
controls is expected to remain stable. This means:

   * The expected rule signature for `violation[{"msg": "string", "details": <object>}]`
     should be backwards compatible across releases.
   * The data provided to constraint template source code via the `input` variable
     should be backwards compatible.
   * The storage location of objects in `data.inventory` should be backwards
     compatible, though the backwards compatibility of the schema of the objects
     themselves is not controlled by Gatekeeper and is therefore out-of-scope.

### Constraints
Because constraints are partially defined by constraint templates, it is always
possible for an applied change to a constraint template to break an existing
constraint. Constraints also have a transitive dependency on Rego, so any
backwards-incompatible changes to the language could lead to changes in the
behaviour of the constraint it backs.

However, absent any user-initiated changes to the backing constraint template
or changes to Rego, constraints should have a stable interface. Specifically
this means:

   * The `parameters` schema
   * The `match` schema
      * Note that there is an implicit assumption that the match schema is
        defined for Kubernetes. This will need to be accounted for if we pursue
        multi-target constraints per
        [Expanding the Constraint Framework](https://docs.google.com/document/d/12bmUm2cWuIf3DTENX7yXMfvt_vDKBIHrqJ0on5V5sJo/edit)
   * `enforcementAction`

`enforcementAction` is an interesting beast. It is not an enum, though it looks
like one at first glance. It is an opaque string whose value is given meaning by
the particular enforcement point evaluating the constraint. Its behavior is:

   * the default value is "deny"
   * unknown values should be ignored

The upshot of these differences (particularly "unknown values should be ignored")
is that unlike enums, which have a bounded set of allowed values, the set of
valid enforcement actions is unbounded. This makes it more akin to a
[union set](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#unions).

Current Gatekeeper is deviating slightly from the `enforcementAction` spec by
defaulting to rejecting constraints with an unknown enforcement action (this
behavior can be disabled via the `--disable-enforcementaction-validation` flag).
This should be a non-issue as a missing constraint and an ignored constraint are
functionally equivalent. The reason for rejection is to make typos more visible
to the user. Ultimately, unrecognized values should be returned to the user as a
warning once it is possible for validating webhooks to do so.

### Internal-Only Resources
The following resources are for intended for internal use only and are therefore
not subject to the backwards compatibility design:

   * ConstraintPodStatus
   * ConstraintTemplatePodStatus
   
### Semantic Logging
[Semantic logging](https://docs.google.com/document/d/1ap7AKOupNcR_42s8mkSh5FV9eteXTd4VCqelKst73VY/edit)
should be considered part of our API and subject to backwards compatibility
requirements.

## Practical Effects

### Project velocity
Adopting this stance on backwards compatibility will necessarily constrain
project velocity wherever its API is concerned. Because we are now attempting to
provide a stable API, changes to our API become either very expensive or
impossible to undo.

This means that any changes to non-alpha resources should be thoroughly vetted
before they are approved.

### Contributions
Our backwards compatibility requirements should be made readily available to
contributors as part of our contributor guide. Reviewers should be on guard
against any changes that may affect backward compatibility.

---

### Metrics (`docs/Metrics.md`)

This document has been moved to https://open-policy-agent.github.io/gatekeeper/website/docs/metrics.

---

### RELEASE (`docs/RELEASE.md`)

# Release Process

## Overview

The release process consists of three phases: versioning, building, and publishing.

Versioning involves maintaining the following files:

- **Makefile** - the Makefile contains a VERSION variable that defines the version of the project.
- **manager.yaml** - the controller-manager deployment yaml contains the latest release tag image of the project.
- **gatekeeper.yaml** - the gatekeeper.yaml contains all gatekeeper resources to be deployed to a cluster including the latest release tag image of the project.

The steps below explain how to update these files. In addition, the repository should be tagged with the semantic version identifying the release.

Building involves obtaining a copy of the repository and triggering a build as part of the GitHub Actions CI pipeline.

Publishing involves creating a release tag and creating a new *Release* on GitHub.

## Cherry-picking

There is an optional script for cherry-picking PRs that should make the process easier.

Prerequisites:

- `hub` binary is installed. If not, `hub` can be installed by `go get github.com/github/hub`.
- Set GitHub username with `export GITHUB_USER=<your GitHub username>`
- Set fork remote with `export FORK_REMOTE=<your fork remote name, by default it is "origin">`
- Set upstream remote with `export UPSTREAM_REMOTE=<upstream remote name, by default it is "upstream">`

Usage: `./third_party/k8s.io/kubernetes/hack/cherry_pick_pull.sh upstream/release-3.1 123`
For example, this will cherry-pick PR #123 into `upstream/release-3.1` branch and will create a PR for you.

You can also combine multiple PRs by separating them with spaces (`./third_party/k8s.io/kubernetes/hack/cherry_pick_pull.sh upstream/release-3.1 123 456`)

If you want to run the script with dry run mode, set `DRY_RUN` to `true`.

Cherry-pick script is copied over from https://github.com/kubernetes/kubernetes/blob/master/hack/cherry_pick_pull.sh. For more information, see https://github.com/kubernetes/community/blob/master/contributors/devel/sig-release/cherry-picks.md

## Release Cadence

There are three version tracks for the Gatekeeper project:

1. Beta (`vX.Y.Z-beta.A`)
1. Release Candidate (`vX.Y.Z-rc.B`)
1. Stable (`vX.Y.Z`)

After a minor release (`vX.Y.0`) has been released, we will immediately tag the master branch with `vX.Y+1.Z-beta.0` in preparation for our next minor release (`vX.Y+1.0`). We will periodically increment the beta version (e.g. `vX.Y+1.Z-beta.0` -> `vX.Y+1.Z-beta.1`) to give the users a chance to test bug fixes and experimental features we introduce to the master branch. However, we do not recommend using beta versions of Gatekeeper in a production environment.

Once we are ready to release the new minor version, we will create a release branch (`release-X.Y+1`) from the master branch and create a release candidate tag (`vX.Y+1.Z-rc.0`) based on the release branch. This allows us to isolate the release candidates in its own branch so that future pull requests that are being merged to the master branch will not cause any regressions. Unlike beta, we only increment our release candidates (e.g. `vX.Y+1.Z-rc.0` -> `vX.Y+1.Z-rc.1`) when we decided to cherry-pick merged pull requests to the release branch. We also do not recommend using release candidates of Gatekeeper in a production environment.

Once we are confident in our latest release candidate, we will tag the release branch with a stable release (`vX.Y+1.0`), and the development cycle will start all over again. We recommend using stable releases of Gatekeeper in a production environment. We also encourage users to upgrade to the latest stable patch releases (`vX.Y+1.Z`) for bug fixes, security fixes, and performance improvements.

For patch releases (e.g. `vX.Y.1`), refer to the [cherry-picking](#cherry-picking) section on how to cherry-pick merged pull requests to an existing release branch.

## Release Pull Requests

Before we cut a release, we need to create a release pull request against the HEAD of the release branch. Once it is merged, we will create the release tag on the latest commit. We have a [GitHub Actions workflow](https://github.com/open-policy-agent/gatekeeper/actions/workflows/release-pr.yaml) that automates the creation of release pull requests.



1. Click the "Actions" tab.

1. Click the "create_release_pull_request" workflow.

1. Click "Run workflow" and input the version you would like to create a release pull request for.

During the workflow, it will create the release manifests, promote the manifests from `manifest_staging/charts` and `manifest_staging/deploy` to `charts` and `deploy` folders respectively, and create the release pull request on behalf of the release author.

## Additional Pre-Release Checklist

Before creating a release pull request, ensure the following steps are completed:

1. **Dependabot PRs**
   - Ensure all [Dependabot PRs](https://github.com/open-policy-agent/gatekeeper/pulls?q=is%3Apr+author%3Aapp%2Fdependabot) are reviewed and merged. This keeps dependencies up to date and secure.

2. **Dependency Updates**
   - Confirm that the following dependencies are updated to their latest stable versions or commits:
     - [OPA](https://github.com/open-policy-agent/opa)
     - [cert-controller](https://github.com/open-policy-agent/cert-controller)
     - [Constraint Framework](https://github.com/open-policy-agent/frameworks/tree/master/constraint)
   - Reference the relevant repositories and check for new releases.

3. **Vulnerability Scanning**
   - Ensure [Trivy](https://github.com/aquasecurity/trivy) scans are passing and no vulnerabilities are detected in the latest CI run.
   - Review the [latest Trivy scan results](https://github.com/open-policy-agent/gatekeeper/actions/workflows/scan-vulns.yaml?query=branch%3Amaster) before proceeding.

## Building and releasing

1. Once the release pull request is merged to `master` or `release` branch (`<BRANCH NAME>` below), tag that commit with release version and push tags to remote repository.

```shell
git checkout <BRANCH NAME>
git pull origin <BRANCH NAME>
git tag -a <NEW VERSION> -m '<NEW VERSION>'
git push origin <NEW VERSION>
```

1. Pushing the release tag will trigger GitHub Actions to trigger `tagged-release` job.
This will build the `openpolicyagent/gatekeeper` image automatically, then publish the new release image tag and the `latest` image tag to the `openpolicyagent/gatekeeper` repository. Finally, verify step will run e2e tests to verify the newly released tag.

## Publishing

1. GitHub Action will create a new release, review and edit it at https://github.com/open-policy-agent/gatekeeper/releases

## Additional Post-Release Checklist

After a major or minor release, review and release the following dependencies if they contain changes since their last release:

- **frameworks/constraint**: If there are unreleased changes, cut a new release and tag the same commit ID that is referenced in Gatekeeper's `go.mod` with the next appropriate release tag.
- **cert-controller**: If there are unreleased changes, cut a new release and tag the same commit ID that is referenced in Gatekeeper's `go.mod` with the next appropriate release tag.

---

### Release Management (`docs/Release_Management.md`)

# Release Management

## Overview

This document describes Gatekeeper project release management, which includes release versioning, supported releases, and supported upgrades.

## Legend

- **X.Y.Z** refers to the version (git tag) of Gatekeeper that is released. This is the version of the Gatekeeper image and the Chart version.
- **Breaking changes** refer to schema changes, flag changes, and behavior changes of Gatekeeper that may require a clean installation during upgrade, and it may introduce changes that could break backward compatibility.
- **Milestone** should be designed to include feature sets to accommodate 3 months release cycles including test gates. GitHub's milestones are used by maintainers to manage each release. PRs and Issues for each release should be created as part of a corresponding milestone.
- **Patch releases** refer to applicable fixes, including security fixes, may be backported to support releases, depending on severity and feasibility.
- **Test gates** should include soak tests and upgrade tests from the last minor version.

## Release Versioning

All releases will be of the form _vX.Y.Z_ where X is the major version, Y is the minor version and Z is the patch version. This project strictly follows semantic versioning.

The rest of the doc will cover the release process for the following kinds of releases:

**Major Releases**

No plan to move to 4.0.0 unless there is a major design change like an incompatible API change in the project

**Minor Releases**

- X.Y.0-alpha.W, W >= 0 (Branch: master)
    - Released as needed before we cut a beta X.Y release
    - Alpha release, cut from master branch
- X.Y.0-beta.W, W >= 0 (Branch: master)
    - Released as needed before we cut a stable X.Y release
    - More stable than the alpha release to signal users to test things out
    - Beta release, cut from master branch
- X.Y.0-rc.W, W >= 0 (Branch: release-X.Y)
    - Released as needed before we cut a stable X.Y release
    - Soak for a total of ~2 weeks before cutting a stable release
    - Release candidate release, cut from release-X.Y branch
- X.Y.0 (Branch: release-X.Y)
    - Released every ~3 months
    - Stable release, cut from release-X.Y branch when X.Y milestone is complete

**Patch Releases**

- Patch Releases X.Y.Z, Z > 0 (Branch: release-X.Y, only cut when a patch is needed)
    - No breaking changes
    - Applicable fixes, including security fixes, may be cherry-picked from master into the latest supported minor release-X.Y branches.
    - Patch release, cut from a release-X.Y branch

## Supported Releases

Applicable fixes, including security fixes, may be cherry-picked into the release branch, depending on severity and feasibility. Patch releases are cut from that branch as needed.

We expect users to stay reasonably up-to-date with the versions of Gatekeeper they use in production, but understand that it may take time to upgrade. We expect users to be running approximately the latest patch release of a given minor release and encourage users to upgrade as soon as possible.

We expect to "support" n (current) and n-1 major.minor releases. "Support" means we expect users to be running that version in production. For example, when v3.3.0 comes out, v3.1.x will no longer be supported for patches, and we encourage users to upgrade to a supported version as soon as possible.

## Supported Kubernetes Versions

Gatekeeper is assumed to be compatible with the [current Kubernetes Supported Versions](https://kubernetes.io/releases/patch-releases/#detailed-release-history-for-active-branches) per [Kubernetes Supported Versions policy](https://kubernetes.io/releases/version-skew-policy/).

For example, if Gatekeeper _supported_ versions are v3.7 and v3.8, and Kubernetes _supported_ versions are v1.22, v1.23, v1.24, then all supported Gatekeeper versions (v3.7, v3.8) are assumed to be compatible with all supported Kubernetes versions (v1.22, v1.23, v1.24). If Kubernetes v1.25 is released later, then Gatekeeper v3.7 and v3.8 will be assumed to be compatible with v1.25 if those Gatekeeper versions are still supported at that time.

If you choose to use Gatekeeper with a version of Kubernetes that it does not support, you are using it at your own risk.

## Upgrades

Users should be able to run both X.Y and X.Y + 1 simultaneously in order to support gradual rollouts.

## Acknowledgement

This document builds on the ideas and implementations of release processes from projects like Kubernetes and Helm.

---

### Deprecated Docs Ingress Host Conflict (`deprecated/docs/ingress-host-conflict.md`)

# gatekeeper

Kubernetes compliance is enforced at the “runtime” via tools such as network policy and pod security policy. [gatekeeper](https://github.com/open-policy-agent/gatekeeper) extends the compliance enforcement at “create” event not at “run“ event, some of the examples are "Minimum replica count enforcement", "White listed/ black listed registries", "not allowing conflicting hosts for ingresses". Kubernetes allows decoupling complex logic such as policy decision from the inner working of API Server by means of "admission controllers”. Admission control is a custom logic executed by a webhook. `Kubernetes policy controller` is a mutating and a validating webhook which gets called for matching Kubernetes API server requests by the admission controller to enforce semantic validation of objects during create, update, and delete operations. It uses Open Policy Agent ([OPA](https://github.com/open-policy-agent/opa)) is a policy engine for Cloud Native environments hosted by CNCF as a sandbox level project.

The administrator of the cluster defines the policy which is enforced by `gatekeeper`. There are two type of policies namely `validation` e.g. white listed registries and `mutation` e.g. annotating objects created in a namespace.

Lets lets look at the example below which implements a validation policy to ensure Ingress hostnames must be unique across Namespaces.

## deploy `gatekeeper' on a Kubernetes cluster

Prerequisites are that you have a Kubernetes cluster
To implement admission control rules that validate Kubernetes resources during create, update, and delete operations, you must enable the [ValidatingAdmissionWebhook](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#validatingadmissionwebhook) when the Kubernetes API server is started. the admission controller is included in the [recommended set of admission controllers to enable](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#is-there-a-recommended-set-of-admission-controllers-to-use)

### 1.  create opa namespace

```bash
kubectl create ns opa
```

### 2.  create tls secret for `gatekeeper`

```bash
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -days 100000 -out ca.crt -subj "/CN=admission_ca"
cat >server.conf <<EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
EOF
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=opa.opa.svc" -config server.conf
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 100000 -extensions v3_req -extfile server.conf

kubectl -n opa create secret tls opa-server --cert=./server.crt --key=./server.key

kubectl apply -n opa -f ./opa.yaml
```

### 3. deploy default kubernetes policies

```bash
cat > ./matches.rego <<EOF
package k8s
import data.kubernetes

matches[[kind, namespace, name, resource]] {
    resource := kubernetes[kind][namespace][name]
}
EOF
kubectl -n opa create configmap kubernetes-matches --from-file=./matches.rego
```

### 4. enable webhook configuration

```bash
cat > ./validating-webhook-configuration.yaml <<EOF
kind: ValidatingWebhookConfiguration
apiVersion: admissionregistration.k8s.io/v1beta1
metadata:
  name: validating.gatekeeper
webhooks:
  - name: validating.webhook.gatekeeper
    rules:
      - operations: ["CREATE", "UPDATE"]
        apiGroups: ["*"]
        apiVersions: ["*"]
        resources: ["*"]
    clientConfig:
      caBundle: $(cat ./ca.crt | base64 | tr -d '\n')
      service:
        namespace: opa
        name: opa
        path: "/v1/validate"
EOF

kubectl -n opa apply -f ./validating-webhook-configuration.yaml
```

## apply the ingress conflict policy definition

The policy is defined in Rego a policy language used by the Open Policy Agent. Each validation policy is a deny rule. In this case, there is a violation if any two ingresses in different namespaces have the same host.

Store the policy in Kubernetes as a ConfigMap. This is automatically uploaded to the policy engine.

```bash
cat > ./ingress-conflict.rego <<EOF
deny[{
    "id": "ingress-conflict",
    "resource": {"kind": "ingresses", "namespace": namespace, "name": name},
    "message": "ingress host conflicts with an existing ingress",
}] {
    # gets the ingress matching the ingress that needs to be validated
    matches[["ingresses", namespace, name, matched_ingress]]
    # gets any other ingress which is already a part of the cluster
    matches[["ingresses", other_ns, other_name, other_ingress]]
    # filters to ingresses in other namespaces
    namespace != other_ns
    other_ingress.spec.rules[_].host == matched_ingress.spec.rules[_].host
}
EOF
kubectl create configmap ingress-conflict --from-file=ingress-conflict.rego

```

## create ingress in default namespace

This operation will succeed as there is no conflicting ingress host in any other namespace

```bash
cat > ./ingress-host.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-host
spec:
  rules:
  - host: acmecorp.com
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80
EOF
kubectl apply -f ./ingress-host.yaml
```

## Create ingress with same host in another namespace (This should fail)

Create a test namespace

```bash
kubectl create ns test
```

Try create a

```bash
kubectl -n test apply -f ./ingress-host.yaml
```

This is the error message returned by `gatekeeper`

```bash
Error from server: error when creating "ingress-host.yaml": admission webhook "validating.webhook.gatekeeper" denied the request: [
  {
    "id": "ingress-conflict",
    "message": "ingress host conflicts with an existing ingress"
  }

```

## Summary

If you have reached this stage you have successfully created a policy for your cluster using `gatekeeper`.

---

### Deprecated Docs Post (`deprecated/docs/post.md`)

# Kubernetes clusters governance made simple

## Overview

Every organization has some rules. Some of these are essential to meet governance, and legal requirements and other are based on learning from past experience and not repeating the same mistakes. These decisions cannot tolerate human response time as they need near a real-time action. Services that are policy enabled to make the organization agile and are essential for long-term success as they are more adaptable as violations and conflicts can be discovered consistently as they are not prone to human error. 

Kubernetes compliance is enforced at the “runtime” via tools such as network policy and pod security policy. [gatekeeper](https://github.com/Azure/gatekeeper) extends the compliance enforcement at “create” event not at “run“ event. For example, a kubernetes service could answer questions like :

* Can we whitelist / blacklist registries.
* Not allow conflicting hosts for ingresses.
* Label objects based on a user from a department.
* What are the policies that my cluster is violating.

We are happy to announce `gatekeeper` which allows enforcing custom semantic rules on objects during create, update and delete operations without recompiling or reconfiguring the Kubernetes API server. The controller is backed by the Open Policy Agent([OPA](https://github.com/open-policy-agent/opa)) which is a lightweight, general purpose policy engine for Cloud-Native environments.

## How policy works with `gatekeeper`

Policy-enablement empowers users to read, write, and manage these rules without needing specialized development. Policy rules can be selected from a library of pre-created rules or can be added to the library using Rego using OPA’s native query language Rego following a standard template to define validation and mutation policies. Below is one example of a validation policy:

```python
deny[{
    "id": "ingress-conflict",
    "resource": {"kind": "ingresses", "namespace": namespace, "name": name},
    "resolution": {"message": "ingress host conflicts with an existing ingress"},
}] {
    # gets the ingress matching the ingress that needs to be validated
    matches[["ingresses", namespace, name, matched_ingress]]
    # gets any other ingress which is already a part of the cluster
    matches[["ingresses", other_ns, other_name, other_ingress]]
    # filters to ingresses in other namespaces
    namespace != other_ns
    other_ingress.spec.rules[_].host == matched_ingress.spec.rules[_].host
}
```

## Architecture of `gatekeeper`

Kubernetes allows decoupling complex logic such as policy decision from the inner working of API Server by means of "admission controllers”. Admission control is a custom logic executed by a webhook. `Kubernetes policy controller` is a mutating and a validating webhook which gets called for matching Kubernetes API server requests by the admission controller to enforce semantic validation of objects during create, update, and delete operations. It uses Open Policy Agent ([OPA](https://github.com/open-policy-agent/opa)) is a policy engine for Cloud-Native environments hosted by CNCF as a sandbox level project.

They are following components that for `gatekeeper`

* Admission controller Webhook: This is the service that receives CRUD requests from the API server

* OPA service and Kubernetes management pod: The OPA service is a generic policy engine which evaluates configured policy rules on new objects and eventual consistent state of current objects synced using the Kubernetes management pod. 

## What's next

We are on a journey to make policy enforcement on Kubernetes cluster simple and reliable. Try out the [gatekeeper](https://github.com/open-policy-agent/gatekeeper), contribute to writing policies and share your scenarios and ideas! To be sure, there is a lot more to do here, and we look forward to working together to get it done!

We’ll see you on GitHub!

---

### Design Admission Violation Export (`docs/design/admission-violation-export.md`)

# Admission Violation Export Design

**Status**: Proposed
**Tracking Issue**: [#2798](https://github.com/open-policy-agent/gatekeeper/issues/2798)
**Created**: 2026-07-29
**Last Updated**: 2026-07-30

## Summary

Gatekeeper can export violations found during admission so that denied, warned,
and dry-run requests can be consumed outside the Kubernetes admission response.
Admission export reuses the existing `Connection` resource, export system, disk
driver configuration, channel, path, and volume used by audit export.

The admission webhook is latency-sensitive. Export is therefore best-effort and
asynchronous: the webhook encodes each violation and attempts a non-blocking send
to a bounded in-memory queue. A controller-runtime runnable drains the queue and
publishes records through the existing export system. Backend latency or failure
cannot change the admission decision, and the webhook never waits for backend I/O
or queue capacity. JSON encoding and the non-blocking enqueue attempt still run
on the admission path.

The supported alpha deployment uses the disk driver. Admission records are
written as durable JSON Lines segments with a separate filename prefix and
lifecycle from audit files. Audit and webhook publishers report health
independently in `ConnectionPodStatus`.

## Related Designs

This design builds on the following existing designs:

- [Connection config CRD and controller for Export](https://docs.google.com/document/d/12P3LCaOAQO9Uts4cVljHXkRgukEyWqyLketDP0rFq8A/edit)
- [Export Audit Violations without PubSub](https://docs.google.com/document/d/19sguUYd_VVhf2Gmy2SLMx1fwaxvrdqLxes3hTVH0DhU/edit)
- [Export violations using pub-sub](https://docs.google.com/document/d/1xu6c99m_qBOpztAc8uUnoY6ST8UiXyyJzrXOmMmJQ9I/edit)
- [Gatekeeper Resource Status Design](https://docs.google.com/document/d/1kPb3B1I6FBsthpR6hp0Q3SEB11iXoSSuWbj9t1q-_58/edit)

## Motivation

Audit export observes resources that already exist in the cluster. It cannot
fully represent admission-time policy outcomes:

- A denied object is never persisted and cannot later be found by audit.
- Admission warnings and dry-run violations occur in the request path.
- Consumers may need request identity, operation, requested resource, and
  subresource information that is not available from a stored object.

Calling an export backend synchronously from the validating webhook would couple
cluster write availability and latency to the backend. A slow disk, unavailable
connection, or blocked consumer could delay every matching Kubernetes request.
Admission export needs a bounded failure domain that preserves admission
availability while making loss observable.

## Goals

- Export one record for each valid constraint violation produced by the
  validating webhook.
- Include admission-request metadata needed to understand violations for objects
  that may never be persisted.
- Keep backend I/O off the admission response path.
- Bound webhook memory and shutdown work.
- Reuse the existing `Connection`, export system, audit route, disk path, and
  volume rather than expose a second transport configuration.
- Allow audit and admission files to coexist without either reader or retention
  policy consuming the other source's files.
- Report audit and webhook publishing health independently per pod.
- Surface overload and loss through metrics and rate-limited logs.
- Recover complete records from abandoned disk segments after a crash.

## Non-Goals

- Exactly-once or at-least-once delivery.
- Retrying an individual failed admission publish.
- Persisting the in-memory webhook queue across pod restarts.
- Blocking or changing an admission response because export failed.
- Supporting admission export through Dapr in the alpha Helm configuration.
- Multiple admission Connections or channels.
- Admission-specific public spool tuning in the alpha API.
- Coordinating one shared writable disk directory across Gatekeeper pods.
- Providing a production log shipper. The included reader sidecar is a
  demonstration and end-to-end test utility.

## Terminology

- **Admission violation**: a valid constraint result evaluated by the validating
  webhook, regardless of whether its enforcement action denies, warns, or
  records a dry-run result.
- **Producer**: the webhook request goroutine that constructs and attempts to
  enqueue a violation record.
- **Publisher**: the single background runnable that removes queued records and
  calls the export system.
- **Ready segment**: a finalized admission `.log` file available to a reader.
- **Open segment**: a locked admission `.open` file receiving JSON Lines records.
- **Source**: the component reporting publish status, currently `audit` or
  `webhook`.

## Configuration

Admission export is disabled by default and enabled independently from audit
export:

```text
--enable-admission-violation-export=true
```

Admission export deliberately reuses the audit route:

```text
--audit-connection=audit-connection
--audit-channel=audit-channel
```

Only one Connection and one channel are supported for this alpha design. The
Helm configuration is:

```yaml
enableAdmissionViolationExport: true
exportBackend: disk
audit:
  connection: audit-connection
  channel: audit-channel
  exportConnection:
    path: /tmp/violations/topics
    maxAuditResults: 3
  exportVolumeMount:
    path: /tmp/violations
  exportVolume:
    name: tmp-violations
    emptyDir: {}
admission:
  disableExportSidecar: true
```

The chart uses one top-level `exportBackend` for both audit and admission
export; there is no admission-specific backend setting. The chart creates the
shared disk `Connection`, mounts the audit export volume in each
controller-manager pod, and can optionally add the demonstration admission
reader sidecar when `exportBackend` is `disk`. Helm rendering fails when
admission export is enabled with any other backend. Operators deploying without
the chart remain responsible for the `Connection` and storage wiring.

Helm source changes belong under `cmd/build/helmify`; `make manifests` generates
`manifest_staging`. Root `charts` and `deploy` directories are release outputs
and are not source files for this feature.

## Architecture

```mermaid
flowchart LR
    A[Kubernetes admission request] --> B[Constraint evaluation]
    B --> C[Admission response processing]
    B --> D{Reserve message slot}
    D -->|accepted| E[Build shared request fields lazily]
    E --> F[Build and encode one ExportMsg]
    F --> G{Reserve bytes and enqueue}
    D -->|full| H[Drop metric and rate-limited log]
    G -->|accepted| I[Per-pod in-memory queue]
    G -->|rejected| H
    I --> J[Collect up to 64 ready records]
    J --> K[PublishBatch or sequential Publish fallback]
    K --> L[Disk Connection]
    L --> M[Locked admission .open segment]
    M --> N[Atomic rename to admission-*.log]
    C --> O[Allow, warn, or deny response]
```

The export path branches after evaluation but before the admission response is
returned. `TryExport` reserves count capacity before invoking its message
builder, has no error return, and does not perform backend I/O. The admission
response is derived from the same validated enforcement actions, but its outcome
is independent of export success.

### Manager Wiring

When admission export is enabled, webhook setup:

1. Requires an export system and a function that returns the current pod.
2. Constructs a `connectionStatusReporter` using the API reader, client, scheme,
   and pod getter.
3. Constructs a `queuedAdmissionViolationExporter` using the shared Connection
   and channel.
4. Adds the exporter to the controller-runtime manager as a runnable.
5. Injects the same exporter into the validation handler.

The export Connection controller is installed when either audit or admission
export is enabled. It reconciles the `Connection` into the process-local export
system for each Gatekeeper pod that performs export.

## Admission Message Construction

The handler validates a result, then passes a lazy builder to `TryExport`. If the
exporter reserves count capacity, the builder decodes request metadata and
constructs the request-level base message on first use. Later accepted results
reuse that base and copy it before adding constraint-specific fields. A full or
stopped queue therefore rejects the result without decoding request metadata or
building the record. Invalid enforcement actions and results without a
Constraint are not exported.

The JSON record uses `ExportMsg`. Common violation fields include:

```json
{
  "id": "admission-request-uid",
  "eventType": "violation_admission",
  "group": "constraints.gatekeeper.sh",
  "version": "v1beta1",
  "kind": "K8sRequiredLabels",
  "name": "require-team-label",
  "message": "you must provide labels: team",
  "enforcementAction": "deny",
  "constraintAnnotations": {"owner": "platform"},
  "details": {"missingLabels": ["team"]},
  "resourceAPIVersion": "v1",
  "resourceKind": "Pod",
  "resourceNamespace": "default",
  "resourceName": "example",
  "resourceLabels": {"app": "example"},
  "timestamp": "2026-07-29T12:00:00.000000000Z",
  "operation": "CREATE",
  "requestResource": "pods",
  "requestUsername": "alice@example.com",
  "requestUserUID": "uid",
  "requestUserGroups": ["developers"],
  "dryRun": false
}
```

The AdmissionReview UID is used as the record ID. A timestamp is used if the UID
is empty. The original requested resource and subresource are preferred when
Kubernetes equivalent-resource matching converted the request. Resource name and
namespace fall back to decoded object metadata when request fields are empty.
The `kubectl.kubernetes.io/last-applied-configuration` constraint annotation is
omitted because it may contain a large serialized object.
`enforcementActions` is emitted for scoped enforcement; ordinary `deny`, `warn`,
and `dryrun` records use only `enforcementAction`. Empty optional fields are
omitted from the encoded record.

A request can produce multiple records with the same request ID, one for each
valid constraint violation.

## Queue Design

Each controller-manager pod owns one queue and one publisher. Queue limits are
private alpha constants:

| Limit | Value |
|---|---:|
| Maximum in-progress or queued messages | 1,024 |
| Maximum encoded queued bytes | 16 MiB |
| Maximum encoded JSON record | 64 KiB |
| Maximum publish batch | 64 messages |
| Status reporting interval | 10 seconds |
| Unchanged healthy status heartbeat | 1 minute |
| Status write timeout | 2 seconds |
| Shutdown drain timeout | 5 seconds |
| Repeated log interval | 1 minute |

The 64 KiB limit applies to the complete JSON object produced by
`json.Marshal(ExportMsg)`, not only to `message`. Field names and JSON escaping,
policy-provided details, constraint annotations, resource labels, and request
identity all consume the same byte budget. KiB measures encoded bytes rather
than characters. This leaves room for normal policy and request metadata while
ensuring one user-influenced result cannot consume a disproportionate share of
the 16 MiB queue or disk spool. Records over the limit are dropped before
enqueue with reason `message_too_large`.

### Producer Path

For each message, `TryExport`:

1. Takes a read lock that prevents shutdown from starting during the enqueue.
2. Atomically reserves one of 1,024 count slots before constructing the message.
3. Rejects new messages after shutdown starts or when all count slots are held.
4. Builds the message and computes a bounded lower estimate of its encoded size.
5. Drops messages that cannot fit within 64 KiB, then marshals the remainder.
6. Applies the exact 64 KiB encoded limit.
7. Atomically reserves the encoded size against the 16 MiB byte limit.
8. Attempts a non-blocking send to the buffered channel.
9. On any failure, releases all count and byte reservations.

The non-blocking send is required: waiting for queue capacity would put backend
backpressure on the admission path. Count and byte limits are independent. The
count limit includes both builders in progress and queued records, bounding
concurrent construction and channel overhead. The byte limit protects retained
encoded data when records are large. The lower-bound preflight does not replace
the final marshal and exact length check; unknown custom values fall through so
encoding errors keep their normal classification.

Queue depth and byte gauges are approximate snapshots. Concurrent producers may
change one value between observations. Byte accounting can briefly include a
producer that reserved bytes but has not yet completed its channel send.

### Publisher Path

`Start` is the single queue consumer. It drains up to 64 records that are already
available without waiting to fill a batch. A driver can implement the optional
source-neutral batch interface; other drivers retain the single-message
`Publish` fallback. Batch values use the same arbitrary message representations
as `Publish`, allowing admission to pass pre-encoded `json.RawMessage` values and
future audit batching to pass typed `ExportMsg` values. Calls remain serialized,
which preserves file ordering and per-Connection driver state. On dequeue, queue
bytes and gauges are reduced before backend I/O; gauges therefore represent
messages waiting in the queue, not a batch currently in flight.

Publishing is attempted once. A backend error is logged, counted, and aggregated
for status, but the individual message is not retried.

### Shutdown

Manager cancellation is given priority over a continuously ready queue. If
cancellation occurs while a normal publish batch is already in flight, that
batch has already been removed from queue accounting. The publisher stops
waiting when its context is canceled and records publish errors for the batch;
it does not requeue those records. A backend call that ignores cancellation may
finish later in its isolated goroutine, but the late result is not applied.

Shutdown then handles records that remain queued:

1. Acquires the queue lock and rejects future enqueues.
2. Creates a fresh background context with a five-second deadline because the
   manager context is already canceled.
3. Publishes any message selected concurrently with cancellation.
4. Drains queued messages until empty or the deadline expires.
5. Counts remaining messages as dropped with reason `shutdown`.
6. Flushes final publishing status with a two-second timeout.

The runnable returns `nil`; backend and status failures are operational state,
not manager-fatal errors. The chart's 60-second pod termination grace period is
longer than the bounded drain and final status flush, but `SIGKILL`, OOM
termination, and node failure bypass this graceful path. Those events lose all
queued and in-flight records. Disk records already appended and synced can be
recovered only if the volume survives.

## Export Routing

`System` maps a Connection name to a driver. A single ready record uses:

```text
Publish(context, connectionName, channel, encodedMessage)
```

A ready group of two to 64 records uses the optional batch extension:

```text
PublishBatch(context, connectionName, channel, []any{json.RawMessage, ...})
```

`System.PublishBatch` calls `BatchDriver.PublishBatch` when the selected driver
implements it. Otherwise, it invokes `Publish` sequentially with each original
value. The returned error slice corresponds one-to-one with input records in
input order. The batch contract is source-neutral so future audit batching can
pass typed `ExportMsg` values, but the current webhook producer supplies only
pre-encoded admission `json.RawMessage` values and the disk batch path accepts
only `violation_admission` records.

The generic export system does not know whether the message came from audit or
the webhook. The disk driver decodes only an `eventType` header from raw
admission messages. `violation_admission` selects the admission JSON Lines path;
audit control and violation messages retain the existing audit file path.

This keeps source policy out of the transport abstraction. The supported alpha
configuration restricts admission export to disk through Helm validation even
though the generic export system remains driver-agnostic.

## Disk Format and Lifecycle

Audit and admission files share a Connection directory and channel directory but
use distinct protocols:

| Source | Open form | Ready form |
|---|---|---|
| Audit | `<audit-run-id>.txt` | `<audit-run-id>.log` |
| Admission | `admission-<UTC timestamp>-<random>.open` | `admission-<UTC timestamp>-<random>.log` |

The admission timestamp has nanosecond precision and the random suffix contains
eight random bytes encoded as hexadecimal. Files are created with `O_EXCL` and
`O_NOFOLLOW`, then locked with a non-blocking exclusive `flock`. Topic and audit
path segments are validated to prevent traversal. Directories and files use
group-readable/writeable permissions (`0770` and `0660`).

### Write Path

Before appending a batch, the driver:

1. Validates the topic.
2. Checks each record against the same 64 KiB complete-record limit as the queue
  and the 1 MiB segment limit.
3. Checks cached ready-file accounting while reserving room for the complete
  batch, scanning completed segments only when accounting is uninitialized or
  a retention limit requires cleanup.
4. Checks filesystem blocks available to the current user and preserves a 16 MiB
  free-space reserve in addition to the complete batch.
5. Rotates the current segment before a write when adding the record would
   exceed a rotation limit.
6. Appends each encoded JSON record plus one newline.
7. Calls `fsync` once for each segment touched by the batch.

A short or partial write is rolled back to the previous complete boundary. If
rollback fails, the segment is marked poisoned and later recovery publishes only
complete newline-delimited records.

### Rotation

A segment rotates when any condition is met:

| Limit | Value |
|---|---:|
| Segment bytes | 1 MiB |
| Segment records | 1,000 |
| Segment age | 1 minute |

A timer rotates idle segments without waiting for another admission request. An
empty segment is closed and removed. A non-empty segment is synced, unlocked,
closed, and atomically renamed from `.open` to `.log`. Failed rotation is retried
after 30 seconds without requiring new traffic. Timer callbacks include the
expected topic and open path so stale callbacks cannot rotate a newer stream.

### Retention

Admission retention is independent from audit retention. `maxAuditResults`
applies only to audit run files. Private admission limits are:

| Limit | Value |
|---|---:|
| Ready segments | 20 |
| Total admission bytes, including open stream and pending record | 20 MiB |
| Ready segment maximum age | 24 hours |
| Minimum filesystem free-space reserve | 16 MiB |

Cleanup takes one snapshot of all completed admission segments across topic
directories, sorts candidates globally by modification time and then path, and
removes the oldest files until age, count, and byte constraints all hold. One
retention-cleanup invocation removes at most 256 ready segments. Recovery may
also remove abandoned empty `.open` files and `.deleting` remnants before
retention runs. Directory reads use batches of 128 entries while still
exhausting every directory.

The Connection caches ready-segment count, bytes, and oldest modification time
from recovery or cleanup. Appends to an unchanged open segment use that cache;
rotation and recovery invalidate it before the next cleanup snapshot. This
avoids a directory scan for each record while preserving count, byte, and TTL
enforcement.

These limits bound the unconsumed backlog; they do not guarantee 24-hour
retention. Count or byte pressure can remove a ready segment before it reaches
the maximum age. If one-minute age rotation is the limiting condition, 20 ready
segments represent roughly 20 minutes of backlog; segment byte or record limits
can rotate files more quickly. A healthy reader removes completed segments after
consumption, so cumulative throughput can exceed the spool size as long as the
reader keeps up. The demonstration reader logs every complete record and deletes
the segment after a successful read; it is not a durable archive.

A reader holds an exclusive lock while consuming a ready file. Cleanup takes the
same lock non-blockingly; if the oldest required file is being read, publishing
receives backpressure instead of deleting a file under the reader. Before
unlinking, cleanup renames the file to `.deleting` so another scan cannot select
it.

The byte reservation used during pre-write cleanup is accounting for the pending
JSON Lines record; it is not filesystem preallocation. The separate free-space
check enforces actual filesystem headroom.

### Recovery

On Connection creation, recovery scans channel directories once. Recurring
cleanup starts only when recovery finds admission artifacts or the first
admission record opens a stream, and stops when no artifacts remain:

- Locked `.open` files are treated as live and left untouched.
- Abandoned `.open` files are locked, limited to the maximum segment size,
  truncated to their last complete newline, synced, and renamed to a recovered
  `.log` file.
- Files with no complete record are removed.
- `.deleting` remnants are removed.
- Retention is applied after recovery.

## Connection Lifecycle and Cleanup

The disk driver serializes operations per Connection while a global mutex guards
Connection maps, path reservations, and failed cleanup state. Paths being removed
or migrated are reserved so a concurrent create/update cannot recreate or delete
the same directory.

Connection close attempts to release audit and admission resources even if one
fails. A failed close moves state to a bounded retry map. Cleanup retries use
exponential backoff, enforce retry and TTL limits, and run slow filesystem work
outside the global mutex. State that still owns an open descriptor is retained
regardless of retry count or TTL because dropping it would lose the only cleanup
owner. New disk Connections are rejected while 32 failed Connection states are
retained. Failures from Connections that were already open can temporarily take
the retry map above that threshold because descriptor-owning state cannot be
safely discarded.

## Status API

`ConnectionPodStatus` is written per Gatekeeper pod and copied into
`Connection.status.byPod`. The alpha status separates Connection reconciliation
errors from source-owned publishing state:

```yaml
status:
  byPod:
  - id: gatekeeper-controller-manager-abc
    connectionUID: 00000000-0000-0000-0000-000000000000
    operations:
    - webhook
    observedGeneration: 3
    connectionErrors: []
    publishStatuses:
    - source: webhook
      active: true
      lastAttemptTime: "2026-07-29T12:00:00Z"
      lastSuccessTime: "2026-07-29T12:00:00Z"
      errors: []
```

`connectionErrors` reports Connection create/update failures. `publishStatuses`
is a list-map keyed by `source`, with a maximum of two entries: `audit` and
`webhook`. Each source replaces only its own entry, preventing a successful audit
run from clearing a webhook failure or vice versa.

`active` means the source completed at least one publish in the latest reported
window. `lastAttemptTime` and `lastSuccessTime` distinguish current traffic from
stale status. A source with no new publish attempt leaves its prior entry
unchanged.

Status updates retry Kubernetes conflicts. Each retry reads the latest
Connection and `ConnectionPodStatus`, then merges only the reporting source. A
Connection generation change clears old source status before accepting the first
report for the new generation.

Connection and publish error arrays are limited to 500 entries. Publish failures
are coalesced by the text before the first colon. The first 499 distinct classes
are retained; the final entry reports `additional publish error classes omitted`.
The stored message is the coalesced class key and is not otherwise
length-truncated.

Webhook publishing results are accumulated independently from the publisher. A
dedicated reporter checks every ten seconds, reports errors and health
transitions, and coalesces unchanged healthy traffic to a one-minute heartbeat.
The API call never blocks queue publishing. Failed status writes merge their
snapshot back with newer results for a later retry. Publish-only status updates
do not trigger export Connection reconciliation. Audit reports its source entry
at the end of an audit run.

## Observability

### Metrics

Admission export adds the following OpenTelemetry instruments. Exporters expose
them with the normal Gatekeeper metric prefix.

| Instrument | Type | Meaning |
|---|---|---|
| `admission_export_queued_count` | monotonic counter | Records accepted by the in-memory queue |
| `admission_export_queue_full_count` | monotonic counter | Enqueue rejection due to count or byte capacity |
| `admission_export_published_count` | monotonic counter | Successful backend publishes |
| `admission_export_publish_error_count` | monotonic counter | Backend publish errors |
| `admission_export_dropped_count{reason}` | monotonic counter | Records discarded before successful publishing |
| `admission_export_queue_depth` | observable gauge | Current messages waiting in the channel |
| `admission_export_queue_bytes` | observable gauge | Current encoded bytes reserved by queued producers |

Drop reasons are `marshal_error`, `message_too_large`, `queue_bytes_full`,
`queue_full`, and `shutdown`. Backend publish errors increment the publish-error
counter, not the dropped counter.

Gauges are updated after successful enqueue, failed channel enqueue rollback,
dequeue, and shutdown draining. The observable callbacks read atomics when the
metrics SDK collects. Queue depth excludes the message currently being
published. Gauges are advisory snapshots and may reflect slightly different
instants under concurrent producers.

### Logging

Drops and publish/status failures are logged at most once per minute for each log
class. Metrics are the source for sustained-loss alerting; rate limiting prevents
an unavailable backend from flooding webhook logs.

## Security and Privacy

Admission records may contain usernames, user UIDs, groups, resource labels,
constraint annotations, policy-provided details, and messages influenced by user
input. The export destination is security-sensitive and must be protected like
admission and audit logs.

The disk implementation:

- Rejects empty, absolute, nested, and traversal path segments.
- Uses `O_NOFOLLOW` and rejects symlink topic directories and ready files.
- Uses exclusive file creation and file locks.
- Bounds record, segment, spool, queue, and each retention-cleanup invocation,
  and rejects new Connections while the failed-state threshold is reached.
- Preserves filesystem free space before accepting writes.
- Avoids logging full exported records in the manager.

The default `emptyDir` volume isolates each pod but is ephemeral. Durable storage
must provide a separate directory or volume per pod. Multiple pods must not write
to one shared directory because Connection removal owns and deletes its configured
path.

## Failure Semantics

| Failure | Behavior | User signal |
|---|---|---|
| JSON marshal failure | Drop before enqueue | Drop counter and rate-limited log |
| Encoded JSON record over 64 KiB | Drop before enqueue | Drop counter and rate-limited log |
| Queue count or byte limit | Drop without blocking admission | Queue/drop counters, gauges, log |
| Connection unavailable | Single publish fails; no message retry | Publish-error counter, log, webhook source status |
| Disk full/reserve reached | Single publish fails | Publish-error counter, log, webhook source status |
| Reader locks required oldest file | Publish backpressures through an error, not admission latency | Publish error and status |
| Partial disk write | Roll back; poison and recover if rollback fails | Publish error; complete records preserved |
| Rotation failure | Retain stream and schedule retry | Log and publish error where applicable |
| Graceful shutdown with queued records | Attempt queued records for up to five seconds, then drop the remainder | `shutdown` drop counter and rate-limited log |
| Cancellation with a batch already in flight | Stop waiting, report publish errors, and do not requeue; an uncancelable backend call may finish after its result is no longer observed | Publish-error counter, log, webhook source status |
| `SIGKILL`, OOM termination, or node failure | Lose queued and in-flight records because no drain runs | Counters reset with process; no per-record signal survives |
| Container crash with surviving volume | Lose the in-memory queue; recover complete open-file records already written to disk | Recovered ready file |
| Status conflict | Re-read and retry merge | No cross-source overwrite |
| Status write failure | Retain accumulated reporting window | Rate-limited log; retry next interval/shutdown |

Admission allow/deny/warn behavior is unchanged in every export failure case.

## Compatibility and Rollout

The feature and Connection API are alpha. Admission export is opt-in and defaults
to disabled. Audit export remains independently controlled by
`--enable-violation-export`.

With the default `emptyDir`, replacing the pod removes its spool. Recovery covers
process or container restart only when the configured volume and files remain
available.

This design changes the alpha Connection status shape by replacing aggregate
`active` and `errors` fields with `connectionErrors` and source-specific
`publishStatuses`. Status is controller-owned and reconstructed; clients of the
alpha status must update their queries. During a rolling upgrade, status may be
temporarily absent or incomplete until each source publishes for the current
Connection generation.

The message schema is additive relative to audit `ExportMsg`; admission-only
fields are omitted from audit records. Audit file names, content, and retention
remain separate and unchanged. Admission-specific limits remain private while
operational experience is collected.

## Alternatives Considered

### Synchronous Backend Publishing

Rejected because backend latency and availability would become part of admission
latency and cluster write availability.

### Blocking Queue Enqueue

Rejected because a full queue would backpressure Kubernetes admission requests.
Bounded non-blocking enqueue makes overload explicit and observable.

### Unbounded Queue

Rejected because a backend outage or slow disk could exhaust webhook memory.
Both message count and encoded bytes are bounded.

### Persistent Local Queue

Not selected for alpha. It would improve restart durability but add a second disk
protocol, replay, corruption, and lifecycle concerns before the existing driver
is invoked. The current contract is explicitly best-effort.

### Admission-Specific Connection and Channel

Deferred. Reusing audit Connection/channel/path/volume minimizes public alpha
configuration. Audit and webhook pods still own separate spools and demonstration
reader sidecars; source-specific filenames and status preserve separation where
both protocols share a channel directory. The design can add independent routing
later if operational use cases require it.

### Dapr Admission Export

Not supported in the alpha chart. Helm rendering fails when admission export is
enabled with Dapr or any backend other than disk. Keeping the generic export
system source-agnostic avoids hard-coding driver capability into the controller,
while the supported deployment surface remains disk-only until delivery,
cancellation, and overload semantics are defined for other drivers.

### One File per Violation

Rejected because high admission volume would create excessive filesystem metadata
operations. Bounded JSON Lines segments amortize file creation and rotation.

### Reusing Audit Run Files

Rejected because admission is continuous and includes denied objects with no
audit run ID. Separate prefixes, lifecycle, readers, and retention prevent one
source from consuming or deleting the other.

### One Aggregate Connection Health Field

Rejected because audit and webhook report on different schedules. One producer's
success could clear the other producer's failure. Source-keyed status preserves
ownership and freshness.

### Public Admission Spool Knobs

Deferred while the feature is alpha. Fixed conservative limits avoid committing
to an operator-facing API before usage data identifies which controls are needed.

## Test Plan

The implementation is covered at several boundaries:

- Payload tests verify request metadata, enforcement actions, annotations,
  details, nil results, DELETE/CONNECT behavior, and one record per violation.
- Queue tests verify lazy construction, marshal failure, count and byte
  rejection, message-size preflight, non-blocking drops, bounded batch draining,
  asynchronous status, bounded shutdown drain, logging rate limits, and bounded
  error classes.
- Export system tests verify audit and admission share one disk Connection and
  channel while producing distinct files.
- Disk tests verify JSON Lines content, batch sync behavior, `.open` to `.log`
  rotation, timer retry, audit/admission separation, partial-write rollback,
  crash recovery, cached retention accounting, lazy janitor lifecycle, reader
  backpressure, free-space reserve, path safety, cleanup work limits, and
  concurrent lifecycle behavior under the race detector.
- Status tests verify source isolation, generation reset, conflict retry, error
  bounds, and propagation into `Connection.status.byPod`.
- Metrics tests verify counter and observable-gauge values.
- Targeted Helm render checks should verify disabled defaults, disk-only
  validation, shared route, Connection creation, volume/sidecar rendering, and
  rejection of unsupported configuration.
- End-to-end tests deny a pod, observe the reader record, and verify the current
  webhook source status.

Required validation includes unit tests, disk and webhook race tests, pinned
lint, generated-manifest parity, Helm lint and targeted render checks, and disk
export E2E.

## Graduation Considerations

Before beta, the project should collect operational evidence for queue occupancy,
drop rates, segment sizes, cleanup duration, disk reserve behavior, and status
freshness. Beta should require:

- Documented SLO-oriented alerts for drop and publish errors.
- Upgrade and rollback testing across supported Gatekeeper versions.
- Evidence that fixed queue and spool limits are suitable or a reviewed public
  configuration API for the limits that need tuning.
- A supported production consumption pattern for disk segments.
- A decision on whether additional drivers and independent admission routing are
  in scope.
- Stable message and status schemas with compatibility guarantees.

## Open Questions

- Should admission export support a Connection/channel independent from audit?

---

### Design Gator Policy (`docs/design/gator-policy.md`)

# Gator Policy Design and Implementation

**Status**: MVP Complete, Post-MVP Proposed
**Author**: Sertac Ozercan
**Created**: 2026-01-08
**Last Updated**: 2026-01-08

## Table of Contents

- [Overview](#overview)
- [Mental Model](#mental-model)
- [Part 1: Design](#part-1-design)
  - [MVP Design](#mvp-design)
  - [Known Limitations & Deferred Items](#known-limitations--deferred-items)
  - [Post-MVP Design](#post-mvp-design)
- [Part 2: Implementation](#part-2-implementation)
  - [MVP Implementation](#mvp-implementation)
  - [Post-MVP Implementation](#post-mvp-implementation)

---

# Overview

The `gator policy` command provides a brew-inspired interface for managing Gatekeeper policies from the official [gatekeeper-library](https://github.com/open-policy-agent/gatekeeper-library). It enables users to discover, install, upgrade, and manage ConstraintTemplates and Constraints in their Kubernetes clusters.

---

# Mental Model

This section defines core terminology used throughout this document:

- **Policy**: A single ConstraintTemplate definition. When you install a "policy" (without `--bundle`), you get only the template—no Constraint instances are created. The user must create their own Constraint CRs to activate enforcement.
- **Bundle**: A curated collection of policies **plus** pre-configured Constraint instances. Bundles are opinionated, ready-to-use policy sets (e.g., `pod-security-baseline`). Installing a bundle creates both ConstraintTemplates and their associated Constraints.
- **Catalog**: A YAML index file that describes available policies and bundles. It contains metadata (names, versions, descriptions) and **paths** pointing to the actual template/constraint YAML files in the library repository. The catalog itself contains no policy logic—only references.

> **Key distinction**: Policies give you building blocks; bundles give you turnkey enforcement.

---

# Part 1: Design

## MVP Design

### Command Structure

```
gator policy
├── search <query>              # Search available policies (required query)
├── list                        # List installed policies
├── install <policy...>         # Install one or more policies
│   --bundle <name>             # Install a policy bundle
│   --enforcement-action <act>  # Override enforcement action
│   --dry-run                   # Preview only
├── uninstall <policy...>       # Remove policies
│   --dry-run                   # Preview only
├── update                      # Refresh policy catalog
├── upgrade [policy...]         # Upgrade installed policies
│   --all                       # Upgrade all policies
│   --dry-run                   # Preview only
└── generate-catalog            # Generate catalog from gatekeeper-library
    --library-path <path>       # Path to library repository (default: ".")
    --output, -o <file>         # Output file path (default: "catalog.yaml")
    --name <name>               # Catalog name (default: "gatekeeper-library")
    --version <ver>             # Catalog version (default: "v1.0.0")
  --base-url <url>            # Convert local template/constraint paths to URLs
    --bundles <file>            # Bundles definition file (optional)
    --validate                  # Validate generated catalog (default: true)
```

### MVP Commands

| Command | Description | Requires Cluster |
|---------|-------------|------------------|
| `search` | Search available policies | No (uses cached catalog) |
| `list` | List installed policies | Yes |
| `install` | Install policies/bundles | Yes |
| `uninstall` | Remove policies | Yes |
| `update` | Refresh catalog | No |
| `upgrade` | Upgrade policies | Yes |
| `generate-catalog` | Generate catalog from library | No |

### Installation Model

#### ConstraintTemplates vs Constraints

- **Individual policy install**: Installs **ConstraintTemplate only**
- **Bundle install**: Installs ConstraintTemplates **AND** pre-configured Constraints

```bash
# Template only
gator policy install k8srequiredlabels

# Bundle includes templates + constraints
gator policy install --bundle pod-security-baseline
```

#### Bundles

Bundles are curated sets of policies with pre-configured constraints. They are opinionated and ready-to-use.

| Bundle | Description |
|--------|-------------|
| `pod-security-baseline` | Pod Security Standards - Baseline level |
| `pod-security-restricted` | Pod Security Standards - Restricted level |

### Policy Catalog Schema

The policy catalog is a YAML file that provides metadata about available policies.

#### Catalog Location

- **Production**: `https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/catalog.yaml`
- **Local/Testing**: File path via `GATOR_CATALOG_URL=file:///path/to/catalog.yaml`

#### Schema Definition

```
/* Detailed source-code truncated for AI context efficiency. */
```

#### Field Descriptions

##### Metadata

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Catalog identifier |
| `version` | string | Yes | Catalog schema version (semver) |
| `updatedAt` | string | Yes | ISO 8601 timestamp |
| `repository` | string | Yes | Source repository URL |

##### Bundle

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Bundle identifier |
| `description` | string | Yes | Human-readable description |
| `inherits` | string | No | Parent bundle to inherit policies from |
| `policies` | []string | Yes | List of policy names in this bundle |

##### Policy

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Policy identifier |
| `version` | string | Yes | Policy version (semver) |
| `description` | string | Yes | Human-readable description |
| `category` | string | Yes | Category: `general`, `pod-security`, etc. |
| `templatePath` | string | Yes | Relative path to ConstraintTemplate YAML |
| `bundleConstraints` | map[string]string | No | Maps bundle names to their constraint YAML paths. Different bundles may need different constraint configurations for the same template (e.g., baseline vs restricted PSS profiles). |
| `sampleConstraintPath` | string | No | Relative path to sample Constraint |
| `documentationUrl` | string | No | Link to documentation |
| `bundles` | []string | No | Bundle(s) this policy belongs to |

#### Path Resolution Rules

The `templatePath`, `bundleConstraints`, and `sampleConstraintPath` fields are **always relative to the library repository root**, regardless of catalog location:

| Catalog Source | Path Resolution |
|----------------|----------------|
| `https://...` URL | Paths are appended to the repository's raw content URL. E.g., `templatePath: library/general/requiredlabels/template.yaml` resolves to `https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/requiredlabels/template.yaml` |
| `file:///path/to/catalog.yaml` | Paths are resolved relative to the **parent directory** of the catalog file (assumed to be the library root). E.g., if catalog is at `/repos/gatekeeper-library/catalog.yaml`, then `library/general/...` resolves to `/repos/gatekeeper-library/library/general/...` |

> **Important**: Paths must not start with `/` or `./`. They are always library-root-relative.

### Versioning

#### Version Terminology

| Term | Field | Description | Format |
|------|-------|-------------|--------|
| **Catalog Schema Version** | `metadata.version` | Format/contract version of the catalog structure itself. Increment when adding/removing fields. | semver (e.g., `v1.0.0`) |
| **Catalog Content Version** | `metadata.updatedAt` | Timestamp indicating when this catalog snapshot was generated from the library. | ISO 8601 timestamp |
| **Policy Version** | `policies[].version` | Version of the individual ConstraintTemplate/Constraint. Tracks policy logic changes. | semver (e.g., `v1.2.0`) |

#### Version Behavior

Policies are always installed at the version currently available in the catalog. There is no support for installing older versions of policies.

> **Limitation**: The gatekeeper-library does not maintain historical versions of policy templates. Each policy has exactly one version at any given time. When the library updates a policy, the previous version is replaced. As a result, `gator policy install` always installs the current version from the catalog.

If you need a specific older version of a policy, you must:
1. Check out the gatekeeper-library at the desired git tag/commit
2. Use `gator policy generate-catalog` to create a catalog from that version
3. Configure `GATOR_CATALOG_URL` to point to your custom catalog

### Configuration

#### Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `GATOR_HOME` | Cache directory | `~/.config/gator/` |
| `GATOR_CATALOG_URL` | Catalog source URL | `https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/catalog.yaml` |
| `KUBECONFIG` | Kubernetes config | `~/.kube/config` |

#### Cache Structure

```
$GATOR_HOME/              # Default: ~/.config/gator/
├── catalog.yaml          # Cached catalog
└── config.yaml           # User preferences (future)
```

#### Cache Behavior Rules

| Scenario | Behavior |
|----------|----------|
| **First run, no cache** | `search`, `install`, `upgrade` will **error** with a message to run `update` first. Only `update` and `generate-catalog` work without a cache. |
| **Staleness / TTL** | No automatic refresh. The cache is used until explicitly replaced by `update`. Users control when to refresh. |
| **`update` behavior** | Always fetches from `GATOR_CATALOG_URL` and **overwrites** the cached catalog on success. |
| **`update` failure** | If fetch fails, the **existing cache is preserved** (last-known-good). An error is returned but the cache remains usable. |
| **Cache corruption** | If the cached file is invalid YAML, commands will error. Run `update` to replace it. |

### Resource Management

#### Labels and Annotations

All managed resources receive these metadata:

```yaml
metadata:
  labels:
    gatekeeper.sh/managed-by: gator
    gatekeeper.sh/bundle: pod-security-baseline  # If installed via bundle
  annotations:
    gatekeeper.sh/policy-version: v1.0.0
    gatekeeper.sh/policy-source: gatekeeper-library
    gatekeeper.sh/installed-at: "2026-01-08T10:30:00Z"
```

#### Conflict Resolution

| Scenario | Behavior |
|----------|----------|
| Resource doesn't exist | Install it |
| Resource exists, managed by gator | Update if version differs |
| Resource exists, NOT managed by gator | **Error** - refuse to modify |
| Resource exists, same version | Skip (already installed) |

### Error Handling

#### Exit Codes

| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | General error (network, invalid args) |
| 2 | Cluster error (not found, permission denied) |
| 3 | Conflict (resource exists, not managed by gator) |
| 4 | Partial success (some resources failed) |

### Command Examples

#### Search

```bash
$ gator policy search labels

NAME                  VERSION   CATEGORY   DESCRIPTION
k8srequiredlabels     v1.2.0    general    Requires specified labels on resources
```

#### Install

```bash
# Single policy
$ gator policy install k8srequiredlabels
✓ k8srequiredlabels (v1.2.0) installed

# Bundle with enforcement override
$ gator policy install --bundle pod-security-baseline --enforcement-action=warn
Installing pod-security-baseline bundle (8 policies)...
✓ k8spspprivilegedcontainer (v1.0.0)
...
✓ Installed 8 templates, 8 constraints
```

#### Update & Upgrade

```bash
$ gator policy update
Fetching catalog from gatekeeper-library...
Updated catalog to version v1.5.0

$ gator policy upgrade --all
✓ k8srequiredlabels upgraded (v1.1.0 → v1.2.0)
```

#### Generate Catalog

```bash
$ gator policy generate-catalog --library-path=/path/to/gatekeeper-library
Scanning library directory...
Found 45 policies across 5 categories.
Catalog written to catalog.yaml
```

### User Experience Principles

1. **No confirmation prompts** - Use `--dry-run` for safety preview
2. **Fail fast** - Stop on first error, allow re-run (idempotent)
3. **Line-by-line progress** - Immediate feedback, CI-friendly
4. **Explicit over implicit** - `--bundle` flag, `--all` for upgrade
5. **Scriptable** - JSON output, meaningful exit codes

### Output Format Options

All commands support `--output` / `-o` flag:

| Format | Flag | Description |
|--------|------|-------------|
| Table | `-o table` (default) | Human-readable table output |
| JSON | `-o json` | Machine-readable JSON output |

**JSON Schema Stability**:
- The JSON output schema is **versioned** and follows the catalog `apiVersion` (e.g., `gator.gatekeeper.sh/v1alpha1`).
- Fields in `v1alpha1` may change without notice. Stability guarantees begin at `v1beta1`.
- JSON output always includes a `apiVersion` field for schema identification.

**Table Column Stability**:
- Columns `NAME`, `VERSION`, `STATUS` are stable across versions.
- Additional columns (e.g., `CATEGORY`, `BUNDLE`) are best-effort and may change.

### Flag Precedence and Mutual Exclusivity

| Scenario | Behavior |
|----------|----------|
| `upgrade --all` vs explicit policies | **Error**: mutually exclusive. Either upgrade all or specify names. |
| `install --bundle X` with positional policies | **Allowed**: installs the bundle AND the additional policies. Bundle policies get both templates and constraints; additional positional policies get **template-only** (no constraints). Duplicates are deduplicated. |
| `install --bundle X --bundle Y` | **Allowed**: both bundles are installed. Duplicate policies are deduplicated. |

### Bundle Inheritance Semantics

When a bundle specifies `inherits: <parent-bundle>`, the following rules apply:

1. **Recursive expansion**: Inheritance chains are resolved recursively (e.g., A inherits B, B inherits C → A gets C + B + A policies).
2. **Order**: Parent policies are processed **before** child policies (depth-first, parent-first).
3. **Deduplication**: If the same policy appears in multiple bundles, it is installed once. The **first occurrence** (from the deepest ancestor) wins for any policy-level settings.
4. **Cycle detection**: Circular inheritance is detected at catalog load time and results in a validation error.
5. **Maximum depth**: Inheritance is limited to 10 levels to prevent runaway expansion.

### Conflict Resolution (Detailed)

**How "managed by gator" is determined**:
- A resource is considered managed if it has **both**:
  - Label: `gatekeeper.sh/managed-by: gator`
  - Annotation: `gatekeeper.sh/policy-source` (any value)

**Conflict scenarios**:

| Resource State | Behavior |
|----------------|----------|
| Does not exist | Create it |
| Exists with gator labels | Update if version differs; skip if same |
| Exists without gator labels | **Conflict error** (exit code 3) |
| Exists with partial gator labels (only one of label/annotation) | **Conflict error** - treat as unmanaged |

**Adopt flow**: MVP does **not** support adopting unmanaged resources. Post-MVP may add `--adopt` flag to take ownership of existing resources by adding gator labels.

### Enforcement Action Override Behavior

| Scenario | `--enforcement-action` Behavior |
|----------|----------------------------------|
| **Template-only install** (no `--bundle`) | Flag is **ignored with a warning**. Templates don't have enforcement actions; only Constraints do. |
| **Bundle install** (new constraints) | Flag value is applied to all newly created Constraints. |
| **Bundle install** (existing managed constraints) | Existing constraints are **updated** to the new enforcement action. |
| **Upgrade** (managed constraints) | Enforcement action is **preserved** from the installed constraint. To change it, use `--enforcement-action` explicitly. |
| **Upgrade with `--enforcement-action`** | Overrides the enforcement action on all upgraded constraints. |

### Error Handling (Detailed)

**"Fail fast" vs "Partial success" clarification**:

- **Default behavior (MVP)**: Fail fast. On the first error, stop processing and return the appropriate exit code.
- **Exit code 4 (partial success)** occurs only with `--continue-on-error` flag (if implemented) or in specific batch operations where some resources succeed before a failure.
- For MVP, most operations use fail-fast. Exit code 4 is reserved for future batch modes.

| Exit Code | Condition |
|-----------|-----------|
| 0 | All operations succeeded |
| 1 | General error (invalid args, network failure, invalid catalog) |
| 2 | Cluster error (unreachable, permission denied, Gatekeeper not installed) |
| 3 | Conflict (resource exists but not managed by gator) |
| 4 | Partial success (some operations succeeded, some failed) - future use |

### Security and Integrity (MVP)

**Catalog Trust Model**:
- **HTTPS required**: By default, only `https://` catalog URLs are accepted.
- **`file://` allowed**: For local development/testing only. Not recommended for production.
- **Plain HTTP rejected**: `http://` URLs are rejected with an error. Use `--insecure` flag to override (with warning).

**Path Traversal Protection**:
- All content paths (e.g., `templatePath`, `constraintPath` in the catalog) are validated.
- Paths containing `..` sequences are rejected to prevent directory traversal attacks.
- Both URL paths (for HTTP fetches) and file paths (for `file://` fetches) are validated.

**Resource Validation**:
- Before applying any resource, gator validates:
  - `apiVersion` matches expected Gatekeeper API groups (`templates.gatekeeper.sh`, `constraints.gatekeeper.sh`)
  - `kind` is `ConstraintTemplate` or a valid Constraint kind
  - YAML is well-formed and passes basic structural validation
- Invalid resources are rejected before any cluster modification.

**Sensitive Data**:
- `--dry-run` output **redacts** any fields matching common secret patterns (e.g., `password`, `token`, `secret`).
- Logs never include full resource specs at INFO level; use DEBUG for full output.

### Performance Considerations

**API Call Expectations**:

| Operation | Approximate API Calls |
|-----------|----------------------|
| `list` | 1 (list ConstraintTemplates with label selector) |
| `install` (1 policy) | 2-3 (get, create/update template, optionally constraint) |
| `install --bundle` (N policies) | 2N + overhead (batched where possible) |
| `upgrade --all` (N policies) | N+1 (list + update each) |

**Batching Strategy**:
- Multiple resources are applied sequentially (not in parallel) to ensure deterministic ordering and clear error attribution.
- Server-side apply is used where supported to minimize round-trips.
- Future optimization: batch multiple ConstraintTemplates in a single apply for large bundles.

**Latency Targets**:
- `search` / `list`: < 500ms (local cache / single API call)
- `install` (single policy): < 2s
- `install --bundle` (10 policies): < 10s

### Known Limitations & Deferred Items

The following capabilities were identified during the MVP review process and are **intentionally deferred** to post-MVP. They are documented here so they are not lost and can be prioritized in future iterations.

#### 1. `scoped` Enforcement Action (Install & Upgrade)

The `scoped` enforcement action (which delegates enforcement decisions to individual constraints) is **not supported** in the MVP. Both `install --enforcement-action` and `upgrade --enforcement-action` reject `scoped` with an error.

**Rationale**: `scoped` requires additional per-constraint configuration that does not fit the current simplified install model. Supporting it properly requires a way to specify per-constraint enforcement scopes, likely through the declarative `PolicyFile` approach (see Post-MVP).

**Workaround**: Users who need `scoped` enforcement can manually edit the Constraint CR after installation.

#### 2. `--exclude-policies` for `generate-catalog`

The `generate-catalog` command currently includes **all** discovered policies from the library. There is no mechanism to exclude specific policies or categories during catalog generation.

**Rationale**: The initial catalog generation is expected to be comprehensive. Selective inclusion/exclusion adds complexity without clear MVP use cases.

**Future**: Add `--exclude-policies` and/or `--include-categories` flags to `generate-catalog`.

#### 3. `--all` Flag for `uninstall`

The `uninstall` command requires explicit policy names or `--bundle`. There is no `--all` flag to uninstall every gator-managed resource in one command.

**Rationale**: Mass uninstall is a destructive operation. Requiring explicit names or bundles reduces the risk of accidental removal of all policies from a cluster.

**Future**: Add `--all` flag with a confirmation prompt or require `--yes` for non-interactive use.

#### 4. Multiple Catalog Sources

The MVP supports a single catalog source configured via `GATOR_CATALOG_URL`. There is no support for merging policies from multiple catalogs or custom registries.

**Rationale**: The MVP focuses on the official `gatekeeper-library` as the sole source. Multi-source support requires a merge strategy, conflict resolution rules, and priority ordering.

**Future**: Support multiple catalog URLs (e.g., via a config file) with precedence rules. This also relates to the Post-MVP OCI catalog support.

#### 5. Mutex / File Locking for Concurrent Processes

The local catalog cache (`$GATOR_HOME/catalog.yaml`) has no file locking. Concurrent `gator policy update` or `gator policy install` processes running against the same cache directory may race on reads/writes.

**Rationale**: CLI tools are typically invoked sequentially. Concurrent invocation is uncommon in practice and adds implementation complexity.

**Future**: Add advisory file locking (e.g., `flock`) around cache read/write operations, or use atomic rename for writes.

#### 6. Mutation Policy Support in Catalog Generator

The `generate-catalog` command discovers only **validation** policies (ConstraintTemplates). Mutation policies (`Assign`, `AssignMetadata`, `ModifySet`) in the `mutation/` directory of the gatekeeper-library are not included.

**Rationale**: The MVP policy management model is built around ConstraintTemplates and Constraints. Mutation resources have a different lifecycle and configuration model.

**Future**: Extend the catalog schema and generator to support mutation policies as a separate resource type.

#### 7. Cross-Cluster and Multi-Cluster Support

The MVP client operates against a single cluster determined by the current `KUBECONFIG` context. There is no built-in support for managing policies across multiple clusters.

**Rationale**: Multi-cluster management significantly increases scope and requires decisions around consistency models, rollout strategies, and failure handling.

**Future**: The PolicySync controller (see Post-MVP) provides a foundation for multi-cluster management. Additionally, a `--context` flag could allow targeting specific kubeconfig contexts.

---

## Post-MVP Design

### Post-MVP CLI Commands

| Command | Description |
|---------|-------------|
| `info <policy>` | Show detailed policy information |
| `diff <policy>` | Show differences between installed and latest |
| `apply -f <file>` | Declarative policy management |
| `doctor` | Diagnose issues |

#### Declarative Configuration

```yaml
# gator.yaml
apiVersion: gator.gatekeeper.sh/v1alpha1
kind: PolicyFile
metadata:
  name: my-cluster-policies
spec:
  bundles:
    - name: pod-security-baseline
      enforcementAction: warn
  policies:
    - name: k8srequiredlabels
      version: ">=1.0.0"
```

```bash
gator policy apply -f gator.yaml
gator policy apply -f gator.yaml --prune  # Remove unlisted
```

#### Info Command

```bash
$ gator policy info k8srequiredlabels

Name:        k8srequiredlabels
Version:     v1.2.0
Category:    general
Description: Requires specified labels on resources

Parameters:
  - labels (array, required): List of required label keys
  - message (string, optional): Custom violation message
```

#### Doctor Command

```bash
$ gator policy doctor

✓ Catalog reachable (v1.5.0)
✓ Cluster accessible (gatekeeper v3.15.0)
✓ 12 policies installed

All checks passed.
```

### PolicySync Controller (GitOps Integration)

The PolicySync controller enables GitOps-style policy management with automatic drift detection and remediation.

#### Motivation

- **Manual synchronization**: Currently, users must manually run `gator policy install/upgrade` commands
- **Drift detection**: No mechanism to detect or remediate unauthorized policy changes
- **Multi-cluster management**: Difficult to ensure policy consistency across many clusters
- **Version tracking**: No centralized view of which policy versions are deployed

#### Architecture

```
/* Detailed source-code truncated for AI context efficiency. */
```

#### PolicySync CRD

```yaml
apiVersion: gator.gatekeeper.sh/v1alpha1
kind: PolicySync
metadata:
  name: production-policies
spec:
  catalog:
    url: "https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/catalog.yaml"

  syncInterval: 5m

  policies:
    include:
      - k8srequiredlabels
      - k8scontainerlimits
    exclude:
      - k8sdisallowedtags
    bundles:
      - security-essentials

  constraintDefaults:
    enforcementAction: warn
    match:
      excludedNamespaces:
        - kube-system
        - gatekeeper-system

  policyOverrides:
    - name: k8srequiredlabels
      enforcementAction: deny
      parameters:
        labels:
          - key: owner
            allowedRegex: "^team-.+$"

  drift:
    enabled: true
    action: restore  # restore | warn | ignore
    checkInterval: 1m

  suspended: false

status:
  phase: Synced
  catalog:
    version: "v2026.01.08"
    lastFetched: "2026-01-08T04:00:00Z"
  summary:
    desired: 15
    synced: 14
    failed: 1
  conditions:
    - type: Ready
      status: "True"
      reason: SyncComplete
```

#### Sync Controller CLI Commands

```bash
# Start the sync controller
gator policy sync-controller [flags]
  --kubeconfig string       Path to kubeconfig
  --metrics-addr string     Address for metrics endpoint (default ":8080")
  --sync-concurrency int    Number of concurrent sync operations (default 5)

# One-shot sync (for CI/CD)
gator policy sync [flags]
  --catalog-url string      Catalog URL
  --policies strings        Policies to sync
  --bundles strings         Bundles to sync
  --dry-run                 Preview changes

# View sync status
gator policy status [policysync-name]

# Trigger immediate sync
gator policy trigger-sync [policysync-name]
```

#### Observability

##### Metrics

```prometheus
gator_policy_sync_operations_total{policysync="...", status="success|failure"}
gator_policy_sync_policies_total{policysync="...", phase="synced|failed|pending"}
gator_policy_sync_drift_detected_total{policysync="...", policy="...", action="restore|warn"}
```

##### Events

```
Normal  SyncStarted      Syncing 15 policies from catalog v2026.01.08
Normal  PolicySynced     Successfully synced policy k8srequiredlabels (v1.0.2)
Warning DriftDetected    Drift detected in ConstraintTemplate k8srequiredlabels
Normal  DriftRestored    Restored ConstraintTemplate k8srequiredlabels to desired state
```

---

# Part 2: Implementation

## MVP Implementation

### Package Structure

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Dependencies

| Package | Purpose |
|---------|---------|
| `github.com/spf13/cobra` | CLI framework (already used by gator) |
| `k8s.io/client-go` | Kubernetes client (already used) |
| `sigs.k8s.io/yaml` | YAML parsing (already used) |

No new dependencies required.

### Core Types

#### Catalog Types

```
/* Detailed source-code truncated for AI context efficiency. */
```

#### Fetcher Interface

```go
// pkg/gator/policy/catalog/fetch.go

const (
    DefaultCatalogURL = "https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/catalog.yaml"
    DefaultTimeout    = 30 * time.Second
)

type Fetcher interface {
    Fetch(ctx context.Context, catalogURL string) ([]byte, error)
    FetchContent(ctx context.Context, contentURL string) ([]byte, error)
}

type HTTPFetcher struct {
    client  *http.Client
    baseURL string
    mu      sync.RWMutex // protects baseURL for thread-safety
}

func NewHTTPFetcher(timeout time.Duration) *HTTPFetcher {
    return &HTTPFetcher{
        client: &http.Client{Timeout: timeout},
    }
}
```

#### Cache Management

```go
// pkg/gator/policy/catalog/cache.go

type Cache struct {
    dir string
}

func NewCache() (*Cache, error) {
    dir := os.Getenv("GATOR_HOME")
    if dir == "" {
        home, _ := os.UserHomeDir()
        dir = filepath.Join(home, ".config", "gator")
    }
    os.MkdirAll(dir, 0755)
    return &Cache{dir: dir}, nil
}

func (c *Cache) CatalogPath() string {
    return filepath.Join(c.dir, "catalog.yaml")
}

func (c *Cache) SaveCatalog(data []byte) error {
    return os.WriteFile(c.CatalogPath(), data, 0644)
}

func (c *Cache) LoadCatalog() ([]byte, error) {
    return os.ReadFile(c.CatalogPath())
}
```

#### Kubernetes Client

```go
// pkg/gator/policy/client/client.go

type Client interface {
    GatekeeperInstalled(ctx context.Context) (bool, error)
    ListManagedTemplates(ctx context.Context) ([]InstalledPolicy, error)
    GetTemplate(ctx context.Context, name string) (*unstructured.Unstructured, error)
    InstallTemplate(ctx context.Context, template *unstructured.Unstructured) error
    InstallConstraint(ctx context.Context, constraint *unstructured.Unstructured) error
    DeleteTemplate(ctx context.Context, name string) error
}

type InstalledPolicy struct {
    Name        string
    Version     string
    Bundle      string
    InstalledAt string
    ManagedBy   string
}
```

#### Labels Helper

```go
// pkg/gator/policy/labels/labels.go

const (
    LabelManagedBy        = "gatekeeper.sh/managed-by"
    LabelBundle           = "gatekeeper.sh/bundle"
    AnnotationVersion     = "gatekeeper.sh/policy-version"
    AnnotationSource      = "gatekeeper.sh/policy-source"
    AnnotationInstalledAt = "gatekeeper.sh/installed-at"
    ManagedByValue        = "gator"
    SourceValue           = "gatekeeper-library"
)

func AddManagedLabels(obj *unstructured.Unstructured, version, bundle string)
func IsManagedByGator(obj *unstructured.Unstructured) bool
func GetPolicyVersion(obj *unstructured.Unstructured) string
func GetBundle(obj *unstructured.Unstructured) string
func GetInstalledAt(obj *unstructured.Unstructured) string
```

#### Exit Codes

```go
// pkg/gator/policy/exitcodes.go

const (
    ExitSuccess        = 0
    ExitGeneralError   = 1
    ExitClusterError   = 2
    ExitConflictError  = 3
    ExitPartialSuccess = 4
)

type ExitError struct {
    Code    int
    Message string
}

func (e *ExitError) Error() string { return e.Message }

func NewExitError(code int, message string) *ExitError
func NewGeneralError(message string) *ExitError
func NewClusterError(message string) *ExitError
func NewConflictError(message string) *ExitError
func NewPartialSuccessError(message string) *ExitError
```

### CLI Structure

```go
// cmd/gator/policy/policy.go

var Cmd = &cobra.Command{
    Use:     "policy",
    Short:   "Manage Gatekeeper policies from the policy library",
    Long:    "Install, upgrade, and manage Gatekeeper policies from the official gatekeeper-library.",
    Example: examples,
}

func init() {
    Cmd.AddCommand(
        newSearchCommand(),
        newListCommand(),
        newInstallCommand(),
        newUninstallCommand(),
        newUpdateCommand(),
        newUpgradeCommand(),
        newGenerateCatalogCommand(),
    )
}
```

### Testing Strategy

#### Local Testing

```bash
# Set catalog to local file
export GATOR_CATALOG_URL=file://$(pwd)/test/gator/policy/testdata/catalog.yaml

# Test commands
gator policy update
gator policy search test
gator policy install test-policy-1 --dry-run
```

#### CI Testing

```yaml
- name: Test gator policy
  run: |
    make gator
    export GATOR_CATALOG_URL=file://${{ github.workspace }}/test/gator/policy/testdata/catalog.yaml
    ./bin/gator policy update
    ./bin/gator policy search test
```

#### E2E Testing

```bash
# With kind cluster
kind create cluster
kubectl apply -f deploy/gatekeeper.yaml
export GATOR_CATALOG_URL=file://testdata/catalog.yaml
gator policy install test-policy-1
gator policy list
gator policy uninstall test-policy-1
```

---

## Post-MVP Implementation

### PolicySync Controller Implementation

#### API Types

```
/* Detailed source-code truncated for AI context efficiency. */
```

#### Controller Reconciler

```go
type PolicySyncReconciler struct {
    client.Client
    Scheme         *runtime.Scheme
    CatalogFetcher *catalog.Fetcher
    PolicyClient   *policyclient.Client
    Recorder       record.EventRecorder
}

func (r *PolicySyncReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    // 1. Fetch PolicySync resource
    // 2. Check if suspended
    // 3. Fetch catalog (with caching)
    // 4. Resolve desired policies (include/exclude/bundles)
    // 5. Get current state (installed policies with owner ref)
    // 6. Calculate diff (add/update/remove)
    // 7. Apply changes with owner references
    // 8. Update status
    // 9. Requeue after syncInterval
}
```

#### RBAC Requirements

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: gator-sync-controller
rules:
  - apiGroups: ["gator.gatekeeper.sh"]
    resources: ["policysyncs"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["gator.gatekeeper.sh"]
    resources: ["policysyncs/status"]
    verbs: ["update", "patch"]
  - apiGroups: ["templates.gatekeeper.sh"]
    resources: ["constrainttemplates"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  - apiGroups: ["constraints.gatekeeper.sh"]
    resources: ["*"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  - apiGroups: [""]
    resources: ["configmaps", "secrets"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "patch"]
```

#### Helm Chart Integration

```yaml
# values.yaml additions
policySync:
  enabled: false
  image:
    repository: openpolicyagent/gator
    tag: ""
  replicas: 1
  resources:
    limits:
      cpu: 200m
      memory: 256Mi
  defaultPolicySync:
    enabled: false
    catalog:
      url: "https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/catalog.yaml"
    syncInterval: 5m
    constraintDefaults:
      enforcementAction: warn
```

### Future Considerations

1. **OCI Catalog Support**: Fetch catalogs from OCI registries
2. **Signature Verification**: Cosign/Notation support for catalog authenticity
3. **Multi-Cluster**: Federation support for syncing to multiple clusters
4. **Approval Workflow**: Require approval before applying policy changes
5. **Rollback**: Automatic rollback on policy failures
6. **UI Dashboard**: Visual policy sync status

---

### Design Remote Cluster Routing (`docs/design/remote-cluster-routing.md`)

# Remote Cluster Status Resource Routing Design

**Status**: Proposal implemented
**Author**: Abhishek Sheth
**Created**: 2026-05-18
**Last Updated**: 2026-06-17

## Overview
In remote cluster mode, Gatekeeper runs on a **local cluster** but enforces policies on a separate **remote cluster** (connected via `--kubeconfig`). PodStatus resources need to live on the local cluster because:

1. **Garbage collection needs both objects on the same cluster:** Each PodStatus has an OwnerReference pointing to the Gatekeeper pod. If the PodStatus is on a different cluster than the pod, Kubernetes can't find the owner and GC breaks.
2. **Automatic cleanup on pod restart:** When a Gatekeeper pod restarts, Kubernetes GC deletes the old PodStatus objects automatically.


All other resources (ConstraintTemplates, Constraints, Config, etc.) stay on the remote cluster.


## Design

A routing layer wraps the manager's cache and client. On every read or write, it looks at the resource's API group and sends it to the right cluster:

- `status.gatekeeper.sh/*` → **local cluster**
- Everything else → **remote cluster**

The routing check is simple:

```go
func isLocalClusterResource(gvk schema.GroupVersionKind) bool {
    return gvk.Group == "status.gatekeeper.sh"
}
```

This covers all 7 PodStatus types across `v1alpha1` and `v1beta1`.

### Components

**`routingCache`** (`pkg/routing/cache.go`): wraps `cache.Cache`, constructed via `NewRoutingCache(remoteCluster, localCluster, scheme)`. Every cache operation (`Get`, `List`, `GetInformer`, `GetInformerForKind`, `RemoveInformer`, `IndexField`) checks the resource type and picks the right underlying cache. It starts and syncs both caches. In non-remote mode, both point to the same cache.

**`routingClient`** (`pkg/routing/client.go`): wraps `client.Client`, constructed via `NewRoutingClient(remoteCluster, localCluster, scheme)`. It routes all reads (`Get`, `List`) and writes (`Create`, `Update`, `Delete`, `Patch`, `DeleteAllOf`, `Apply`) by resource type. `Status()` and `SubResource()` are also routed (via a `routingSubResourceClient`) by the parent object's GVK, so subresource writes on PodStatus objects reach the local cluster too. The local cluster client is cache-backed (it reuses the manager-provided cache reader), so routed PodStatus reads are served from the local cache rather than hitting the API server on every call.

**`resolveGVK`** (`pkg/routing/routing.go`): figures out the GVK of an object. It first checks if the object already has a GVK set, then falls back to looking it up in the scheme (typed objects). If it can't determine the GVK, it returns an error. The shared `routeIsLocal` helper wraps `resolveGVK` and `isLocalClusterResource`, and the error propagates up through `clientFor`/`cacheFor` so the operation fails loudly rather than silently routing to the wrong cluster.

### main.go

```go
// localClusterConfig = where the pod runs (the local/management cluster).
// Only built when remote cluster mode is enabled; nil otherwise.
var localClusterConfig *rest.Config
if controller.RemoteClusterEnabled() {
    localClusterConfig, _ = rest.InClusterConfig()
}

// The manager's primary config is the remote (target) cluster.
mgr, _ := ctrl.NewManager(config, ctrl.Options{
    NewCache:  newCacheFunc(scheme, localClusterConfig),   // nil in non-remote mode
    NewClient: newClientFunc(scheme, localClusterConfig),  // nil in non-remote mode
})
```

When `localClusterConfig` is nil (non-remote mode), these return nil and controller-runtime uses its defaults. Nothing changes.

The local cluster cache only watches the `gatekeeper-system` namespace to keep RBAC permissions minimal.

## Design Decisions

1. **Routing happens at the manager level**: Controllers, audit, and webhooks don't know about routing. No controller code changes were needed.

2. **Route by API group, not resource name**: The API group is stable across versions. No need to maintain a list of resource names.

3. **OwnerReferences are always set**: Previously, remote mode skipped setting OwnerReferences (since they wouldn't work cross-cluster). Now that PodStatus lives on the same cluster as the pod, OwnerReferences always work.

4. **Both caches must sync before ready**: `WaitForCacheSync` waits for both caches, so the manager won't serve traffic until both are ready.

5. **Error on unknown GVK**: If `resolveGVK` can't determine the resource type (e.g. unregistered type, empty GVK), the routing layer returns an error and the operation fails. An unresolved GVK means the routing decision can't be made, so failing loudly is safer.

## RBAC Requirements (Local Cluster)

The local cluster needs minimal permissions in the `gatekeeper-system` namespace:

| Resource | Verbs |
|----------|-------|
| `pods` | `get` (for OwnerReference lookup) |
| `status.gatekeeper.sh/*` (all PodStatus types) | `get`, `list`, `watch`, `create`, `update`, `patch`, `delete` |

These are scoped to the `gatekeeper-system` namespace via a `Role` + `RoleBinding` (not a `ClusterRole`). No cluster-wide permissions are needed on the local cluster.

## Files Changed

| File | What it does |
|------|-------------|
| `pkg/routing/routing.go` | Routing decision logic (`isLocalClusterResource`, `resolveGVK`) |
| `pkg/routing/cache.go` | `routingCache` / `NewRoutingCache`, routes cache reads and informers |
| `pkg/routing/client.go` | `routingClient` / `NewRoutingClient`, routes client reads, writes, and subresources; `routeIsLocal` helper |
| `main.go` | Builds the local cluster config, passes routing factories to the manager |
| `pkg/controller/controller.go` | `RemoteClusterEnabled()` helper |
| `apis/status/v1*/...` | OwnerReferences always set (removed conditional skip) |

## Non-Remote Mode

When `--enable-remote-cluster` is not set:
- `localClusterConfig` is nil
- Routing factories return nil
- Manager uses its default cache and client
- Everything goes to the single cluster
- Behavior is identical to before this change

---

### Api (`website/docs/api.md`)

---
id: api
title: API Reference
---

This page lists Gatekeeper's Custom Resource Definitions (CRDs) and provides a quick reference for commonly configured fields. It is not an exhaustive schema reference: use the [schemas and examples](#viewing-schemas-and-examples) for complete field definitions and the linked feature guides for usage examples. Required fields and defaults below include Gatekeeper's validation rules, not only OpenAPI schema requirements.

To inspect the live schema in a cluster:

```bash
kubectl get crds | grep gatekeeper
kubectl explain configs.config.gatekeeper.sh.spec
kubectl explain constrainttemplates.templates.gatekeeper.sh.spec
```

Constraint kinds (for example `K8sRequiredLabels`) are **not** shipped as static CRDs. Gatekeeper creates those CRDs at runtime when you apply a `ConstraintTemplate`. Their shared constraint fields are documented below.

## CRD catalog

| Kind | API group | Scope | Purpose |
| ---- | --------- | ----- | ------- |
| `ConstraintTemplate` | `templates.gatekeeper.sh` | Cluster | Defines Rego/CEL policy and the schema for a constraint kind |
| *Constraint* (dynamic) | `constraints.gatekeeper.sh` | Cluster | Instantiates a template with match criteria, enforcement mode, and parameters |
| `Config` | `config.gatekeeper.sh` | Namespaced | Gatekeeper configuration (sync, exemption matchers, validation traces) |
| `SyncSet` | `syncset.gatekeeper.sh` | Cluster | Declares additional GVKs for Gatekeeper to cache |
| `Assign` | `mutations.gatekeeper.sh` | Cluster | Mutate object fields outside metadata |
| `AssignMetadata` | `mutations.gatekeeper.sh` | Cluster | Add missing metadata labels/annotations |
| `AssignImage` | `mutations.gatekeeper.sh` | Cluster | Mutate container image strings |
| `ModifySet` | `mutations.gatekeeper.sh` | Cluster | Merge or prune list values |
| `ExpansionTemplate` | `expansion.gatekeeper.sh` | Cluster | Expand generator resources (for example Deployments) into child objects for policy |
| `Connection` | `connection.gatekeeper.sh` | Namespaced | Configures export drivers/connections |
| `Provider` | `externaldata.gatekeeper.sh` | Cluster | Registers an external data provider |
| [`*PodStatus` kinds](#status-crds-statusgatekeepersh) | `status.gatekeeper.sh` | Namespaced | Per-pod status reported by Gatekeeper controllers (read-only operational data) |

---

## ConstraintTemplate (`templates.gatekeeper.sh`)

Preferred version: `v1` (also served: `v1beta1`, `v1alpha1`).

| Field | Type | Description |
| ----- | ---- | ----------- |
| `spec.crd.spec.names.kind` | string | Required kind name for constraints created from this template (for example `K8sRequiredLabels`) |
| `spec.crd.spec.names.shortNames` | []string | Optional short names for `kubectl` |
| `spec.crd.spec.validation.openAPIV3Schema` | object | Optional schema for the constraint `spec.parameters` field; `v1` templates use a [structural schema](constrainttemplates.md#v1-constraint-template) |
| `spec.crd.spec.validation.legacySchema` | bool | Enable legacy schema mode; defaults to `false` in `v1`, but `true` in `v1alpha1` and `v1beta1` |
| `spec.targets[]` | []object | Required policy target definitions |
| `spec.targets[].target` | string | Required target identifier: `admission.k8s.gatekeeper.sh` |
| `spec.targets[].rego` | string | Legacy Rego policy source; alternatively use `code` |
| `spec.targets[].libs` | []string | Optional supporting libraries for the legacy Rego source |
| `spec.targets[].code[]` | []object | Engine-specific policy definitions, each with `engine` and `source` |
| `spec.targets[].code[].engine` | string | Required for each code entry: `Rego` or `K8sNativeValidation` (CEL) |
| `spec.targets[].code[].source` | object | Required engine-specific source; see [Rego v1](constrainttemplates.md#enable-opa-rego-v1-syntax-in-constrainttemplates) and [CEL sources](validating-admission-policy.md#policy-updates-to-add-vap-cel) |
| `status` | object | Read-only template installation status observed by Gatekeeper |

See [Constraint Templates](constrainttemplates.md) for examples and [engine selection and field precedence](constrainttemplates.md#field-precedence-in-constrainttemplate). Defining multiple engines does not mean that all of them are evaluated.

---

## Constraint resources (`constraints.gatekeeper.sh/v1beta1`)

Each installed `ConstraintTemplate` registers a cluster-scoped constraint CRD whose kind matches `spec.crd.spec.names.kind`. All constraints share the following fields regardless of parameters schema.

### `spec` fields

| Field | Type | Description |
| ----- | ---- | ----------- |
| `spec.match` | object | Optional object selection. Matchers are AND-ed. Empty/undefined match selects everything. |
| `spec.match.kinds` | []object | List of `{apiGroups, kinds}` groups. A resource needs one matching entry. |
| `spec.match.scope` | string | `*`, `Cluster`, or `Namespaced` (default `*`) |
| `spec.match.namespaces` | []string | Include only these namespaces (prefix globs like `kube-*` allowed) |
| `spec.match.excludedNamespaces` | []string | Exclude these namespaces (prefix globs allowed) |
| `spec.match.labelSelector` | object | Standard label selector (`matchLabels` / `matchExpressions`) on the object |
| `spec.match.namespaceSelector` | object | Label selector on the object's namespace (or the object itself if it is a Namespace) |
| `spec.match.name` | string | Object name or prefix glob |
| `spec.match.source` | string | Target resource origin: `All`, `Generated`, or `Original` (default `All`); see [expansion matching](expansion.md#match-source) |
| `spec.parameters` | object | Template-specific inputs; required fields and types depend on the template's OpenAPI schema |
| `spec.enforcementAction` | string | Optional violation handling mode; defaults to `deny` (see below) |
| `spec.scopedEnforcementActions` | []object | Required when `enforcementAction` is `scoped`; ignored otherwise |

All match fields are optional. Namespace filters do not exclude non-Namespace cluster-scoped resources; set `spec.match.scope: Namespaced` to exclude those resources. See [matching semantics](howto.md#the-match-field).

### `spec.enforcementAction`

| Value | Behavior |
| ----- | -------- |
| `deny` | **Default.** Admission requests that violate the constraint are rejected. |
| `dryrun` | Violations are recorded (for example on the constraint status during audit) but admission is not blocked. |
| `warn` | Admission is allowed; clients receive a warning (Kubernetes 1.19+). |
| `scoped` | Use `spec.scopedEnforcementActions` to choose different actions per [enforcement point](enforcement-points.md). |

See [Handling Constraint Violations](violations.md) and [Enforcement Points](enforcement-points.md).

### `spec.scopedEnforcementActions[]`

| Field | Type | Description |
| ----- | ---- | ----------- |
| `action` | string | Required: `deny`, `warn`, or `dryrun` for the listed enforcement points |
| `enforcementPoints[]` | []object | Required non-empty list of enforcement points |
| `enforcementPoints[].name` | string | Required: `validation.gatekeeper.sh`, `audit.gatekeeper.sh`, `gator.gatekeeper.sh`, `vap.k8s.io`, or `*` for all points |

With `enforcementAction: scoped`, an enforcement point not named in any entry is excluded unless an entry names `*`. In particular, audit is not implicitly included. Native Kubernetes enforcement (`vap.k8s.io`) requires a CEL template and VAP/VAPBinding generation; see [Enforcement Points](enforcement-points.md#understanding-enforcement-points).

### `status` fields (observed)

| Field | Description |
| ----- | ----------- |
| `status.byPod[].enforced` | Enforcement status reported by each Gatekeeper controller pod |
| `status.auditTimestamp` | Timestamp of the latest audit run recorded in this constraint's status, including runs with zero violations |
| `status.violations[]` | Bounded list of violations from the latest recorded audit run (`enforcementAction`, `kind`, `name`, `namespace`, `message`, ...) |
| `status.totalViolations` | Total violation count from that audit run, including violations omitted from `status.violations` |

The violation list is limited by `--constraint-violations-limit` (default `20`); see [Reading Audit Results](audit.md#constraint-status).

---

## Config (`config.gatekeeper.sh/v1alpha1`)

Singleton configuration object. It must be named `config` in Gatekeeper's namespace (`gatekeeper-system` by default). Gatekeeper ignores Config resources with other names or namespaces.

All configuration sections below are optional.

| Field | Type | Description |
| ----- | ---- | ----------- |
| `spec.sync.syncOnly[]` | []object | `{group, version, kind}` entries to replicate for referential policies; combined with all SyncSets, not an override of them |
| `spec.match[]` | []object | Process-specific configuration such as namespace exemptions |
| `spec.match[].processes` | []string | `audit`, `webhook`, `sync`, `mutation-webhook`, or `*` for all processes; see [namespace exemptions](exempt-namespaces.md#exempting-namespaces-from-gatekeeper-using-config-resource) |
| `spec.match[].excludedNamespaces` | []string | Namespaces excluded for those processes (wildcards supported) |
| `spec.validation.traces[]` | []object | Admission trace requests; each needs `user` and `kind` (`group`, `version`, `kind`). Optional `dump: All` includes OPA state; see [Tracing](debug.md#tracing) |
| `spec.readiness.statsEnabled` | bool | Enable readiness tracker stats (default `false`) |

See [replication with Config](sync.md#replicating-data-with-config).

---

## SyncSet (`syncset.gatekeeper.sh/v1alpha1`)

Cluster-scoped list of GVKs to cache. The effective sync set is the union of all `SyncSet` objects plus `Config.spec.sync.syncOnly`.

| Field | Type | Description |
| ----- | ---- | ----------- |
| `spec.gvks[]` | []object | Entries with `group`, `version`, and `kind` |

A resource remains cached while any SyncSet or Config still requests its GVK. Removing it from only one source does not stop replication. See [replication with SyncSets](sync.md#replicating-data-with-syncsets-recommended).

---

## Mutation CRDs (`mutations.gatekeeper.sh`)

`Assign`, `AssignMetadata`, and `ModifySet` use `v1` (also served: `v1alpha1`, `v1beta1`). `AssignImage` uses `v1alpha1`.

Common mutation fields:

| Field | Type | Description |
| ----- | ---- | ----------- |
| `spec.applyTo[]` | []object | Required for `Assign`, `AssignImage`, and `ModifySet`; not supported by `AssignMetadata`. Each entry needs `groups`, `versions`, and `kinds`; globs are not allowed |
| `spec.applyTo[].operations` | []string | Optional: `CREATE`, `UPDATE`, or `*`. Omitted/empty means all supported mutation operations (currently `CREATE` and `UPDATE`); `*` must appear alone. See [operation filtering](mutation.md#operations-field) |
| `spec.match` | object | Optional [match criteria](mutation.md#extent-of-changes); empty/undefined criteria match everything |
| `spec.location` | string | Required object path, for example `spec.containers[name: main].image`; see [path syntax](mutation.md#intent) |
| `spec.parameters` | object | Mutator-specific options |
| `spec.parameters.pathTests[]` | []object | Optional `subPath` + `condition` (`MustExist` / `MustNotExist`) checks; each subpath must be a prefix of `location`. Supported by `Assign`, `AssignImage`, and `ModifySet`, not `AssignMetadata`; see [conditionals](mutation.md#conditionals) |

Omitted operations and `*` also include any mutation operations supported by future releases. List explicit operations to keep the same scope across upgrades. Operation-filtered mutators only run without admission-operation context (for example during expansion) if they include every supported operation.

### Assign (`v1`)

`spec.parameters.assign` must select exactly one of these value sources:

| Field | Type | Description |
| ----- | ---- | ----------- |
| `spec.parameters.assign.value` | any | Constant value to assign; may be a scalar, list, or object |
| `spec.parameters.assign.fromMetadata.field` | string | `name` or `namespace` from the object being mutated; see [metadata assignment](mutation.md#assigning-values-from-metadata) |
| `spec.parameters.assign.externalData` | object | External provider configuration; see the [external-data mutation API](externaldata.md#api) for provider selection, data sources, and failure policies |

### AssignMetadata (`v1`)

Adds only missing `metadata.labels` / `metadata.annotations` entries. Existing labels and annotations are not overwritten. `applyTo` and `pathTests` are not supported.

| Field | Description |
| ----- | ----------- |
| `spec.parameters.assign` | Exactly one of the [Assign value sources](#assign-v1); `value` must be a string. External data only supports `dataSource: Username` |

See [AssignMetadata](mutation.md#assignmetadata) for examples.

### AssignImage (`v1alpha1`)

| Field | Description |
| ----- | ----------- |
| `spec.parameters.assignDomain` | Image registry domain (no trailing slash) |
| `spec.parameters.assignPath` | Image path/repository component |
| `spec.parameters.assignTag` | Tag or digest; must start with `:` or `@` |

At least one image component is required. If `assignPath` could be interpreted as a domain, `assignDomain` must also be specified. See [AssignImage](mutation.md#assignimage).

### ModifySet (`v1`)

| Field | Description |
| ----- | ----------- |
| `spec.parameters.operation` | `merge` (default) or `prune` |
| `spec.parameters.values.fromList` | List values to merge into or prune from the location |

See [ModifySet](mutation.md#modifyset).

---

## ExpansionTemplate (`expansion.gatekeeper.sh/v1beta1`)

Also served: `v1alpha1`.

| Field | Type | Description |
| ----- | ---- | ----------- |
| `spec.applyTo[]` | []object | Generator resource GVKs to expand (for example Deployment, Job) |
| `spec.templateSource` | string | Field on the generator used as the pod/template source (often `spec.template`) |
| `spec.generatedGVK` | object | `{group, version, kind}` of the generated resource (for example Pod) |
| `spec.enforcementAction` | string | Optional override for enforcement on expanded resources; empty defers to the constraint |

See [ExpansionTemplate behavior](expansion.md#expansiontemplate-explained).

---

## Connection (`connection.gatekeeper.sh/v1alpha1`)

| Field | Type | Description |
| ----- | ---- | ----------- |
| `spec.driver` | string | Required export driver name: `dapr` or `disk` |
| `spec.config` | object | Required driver-specific configuration (preserved unknown fields); see [export configuration](export.md#setting-up-audit-to-export-violations) |

Create the Connection in Gatekeeper's namespace and select its name with `--audit-connection`. See [Export](export.md) for driver configuration and enablement.

---

## Provider (`externaldata.gatekeeper.sh`)

Preferred version: `v1beta1` (also served: `v1alpha1`, deprecated).

Registers an external data provider HTTPS service.

| Field | Type | Description |
| ----- | ---- | ----------- |
| `spec.url` | string | Required provider endpoint URL (must use the `https://` prefix) |
| `spec.timeout` | integer | Request timeout in seconds when querying the provider |
| `spec.caBundle` | string | Required base64-encoded TLS CA bundle in PEM format; see [provider TLS configuration](externaldata.md#how-gatekeeper-trusts-the-external-data-provider-tls) |

See the [Provider API](externaldata.md#provider) for examples.

---

## Status CRDs (`status.gatekeeper.sh`)

Gatekeeper writes these namespaced resources so each controller pod can report health and errors. They are controller-owned operational data, not resources that users normally create or edit.

| Kind | API version |
| ---- | ----------- |
| `ConfigPodStatus` | `status.gatekeeper.sh/v1beta1` |
| `ConnectionPodStatus` | `status.gatekeeper.sh/v1alpha1` |
| `ConstraintPodStatus` | `status.gatekeeper.sh/v1beta1` |
| `ConstraintTemplatePodStatus` | `status.gatekeeper.sh/v1beta1` |
| `ExpansionTemplatePodStatus` | `status.gatekeeper.sh/v1beta1` |
| `MutatorPodStatus` | `status.gatekeeper.sh/v1beta1` |
| `ProviderPodStatus` | `status.gatekeeper.sh/v1beta1` |

---

## Viewing schemas and examples

* CRD YAML with full OpenAPI schemas: [`config/crd/bases`](https://github.com/open-policy-agent/gatekeeper/tree/master/config/crd/bases)
* Helm-packaged CRDs, including Provider: [`charts/gatekeeper/crds`](https://github.com/open-policy-agent/gatekeeper/tree/master/charts/gatekeeper/crds)
* End-to-end samples: [Examples](examples.md) and the [demo manifests](https://github.com/open-policy-agent/gatekeeper/tree/master/demo)

---

### Audit (`website/docs/audit.md`)

---
id: audit
title: Audit
---

Audit performs periodic evaluations of existing resources against constraints, detecting pre-existing misconfigurations.

## Reading Audit Results

There are three ways to gather audit results, depending on the level of detail needed.

### Prometheus Metrics

Prometheus metrics provide an aggregated look at the number of audit violations:

* `gatekeeper_audit_last_run_time` provides the start time timestamp of the most recent audit run
* `gatekeeper_audit_last_run_end_time` provides the end time timestamp of the last completed audit run
* `gatekeeper_violations` provides the total number of audited violations for the last audit run, broken down by violation severity

### Constraint Status

Violations of constraints are listed in the `status` field of the corresponding constraint.
Note that only violations from the most recent audit run are reported. Also note that there
is a maximum number of individual violations that will be reported on the constraint
itself. If the number of current violations is greater than this cap, the excess violations
will not be reported (though they will still be included in the `totalViolations` count).
This is because Kubernetes has a cap on how large individual API objects can grow, which makes
unbounded growth a bad idea. This limit can be configured via the `--constraint-violations-limit` flag.

Here is an example of a constraint with violations:

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-gk
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["gatekeeper"]
status:
  auditTimestamp: "2019-05-11T01:46:13Z"
  enforced: true
  violations:
  - enforcementAction: deny
    group: ""
    version: v1
    kind: Namespace
    message: 'you must provide labels: {"gatekeeper"}'
    name: default
  - enforcementAction: deny
    group: ""
    version: v1
    kind: Namespace
    message: 'you must provide labels: {"gatekeeper"}'
    name: gatekeeper-system
  - enforcementAction: deny
    group: ""
    version: v1
    kind: Namespace
    message: 'you must provide labels: {"gatekeeper"}'
    name: kube-public
  - enforcementAction: deny
    group: ""
    version: v1
    kind: Namespace
    message: 'you must provide labels: {"gatekeeper"}'
    name: kube-system
```

Limitations of getting violations from constraint status:

- To reduce in-memory consumption of Gatekeeper audit pod and to avoid hitting [default etcd limit](https://etcd.io/docs/v3.5/dev-guide/limit/#request-size-limit) of 1.5MB per resource, gatekeeper recommends configuring a [limit up-to 500 violations](https://open-policy-agent.github.io/gatekeeper/website/docs/audit/#configuring-audit)(by default 20) on constraint. Because of these limitations, users might not get all the violations from a Constraint resource.

### Audit Logs

#### Violations

The audit pod emits JSON-formatted audit logs to stdout. The following is an example audit event:

```json
{
  "level": "info",
  "ts": 1632889070.3075402,
  "logger": "controller",
  "msg": "container <kube-scheduler> has no resource limits",
  "process": "audit",
  "audit_id": "2021-09-29T04:17:47Z",
  "event_type": "violation_audited",
  "constraint_group": "constraints.gatekeeper.sh",
  "constraint_api_version": "v1beta1",
  "constraint_kind": "K8sContainerLimits",
  "constraint_name": "container-must-have-limits",
  "constraint_namespace": "",
  "constraint_action": "deny",
  "constraint_enforcement_actions": [],
  "constraint_annotations": {
    "test-annotation-1": "annotation_1"
  },
  "resource_group": "",
  "resource_api_version": "v1",
  "resource_kind": "Pod",
  "resource_namespace": "kube-system",
  "resource_name": "kube-scheduler-kind-control-plane"
  "resource_labels": {
    "env": "prod",
    "my-app-system": "true"
  }
}
```

In addition to information on the violated constraint, violating resource, and violation message, the
audit log entries also contain:

* An `audit_id` field that uniquely identifies a given audit run. This allows indexing of historical audits
* An `event_type` field with a value of `violation_audited` to make it easy to programmatically identify audit violations

Limitations of getting violations from audit logs:

- It could be difficult to parse audit pod logs to look for violation messages, as violation logs would be mixed together with other log statements.

#### Other Event Types

In addition to violations, these other audit events may be useful (all uniquely identified via the `event_type` field):

* `audit_started` marks the beginning of a new audit run
* `constraint_audited` marks when a constraint is done being audited for a given run, along with the number of violations found
* `audit_finished` marks the end of the current audit run

All of these events (including `violation_audited`) are marked 
with the same `audit_id` for a given audit run.

### Export violations

This feature allows different systems to be provided for Gatekeeper to export audit violations. Thereby, ensuring violations are not subject to reporting limits. Please refer to [the export guide](export.md) to configure audit to push violations via this feature.

Limitations/drawbacks of exporting violations:

- There is a risk of messages getting dropped. You might not receive all the exported violations. This depends on the type of backend you are using for delivery. For example, using a network as backend to export violation has the risk of messages getting dropped.
- Additional dependency on the backend system provided. For example, using pubsub tools to export violations.

## Running Audit

### Why Audit Runs as a Singleton

Gatekeeper audit is designed to run as a singleton because it writes audit results to Constraint status. Multiple audit instances can contend on the same Constraint status fields. In Gatekeeper v3.18 and later, the audit deployment may also run the `generate` operation, which creates or updates Constraint CRDs and, when VAP/VAPB generation is enabled, ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding resources. The `generate` operation should also run as a singleton.

If your setup only consumes audit results from logs or exports, setting `--constraint-violations-limit=0` avoids storing individual violations in Constraint `.status.violations`. This does not disable all Constraint status writes: audit still updates fields such as `.status.auditTimestamp` and `.status.totalViolations`, so running multiple audit replicas can still cause status update contention. If you scale the audit deployment beyond one replica, ensure that only one instance runs the `generate` operation, or disable it for the audit deployment, for example with Helm's `audit.disableGenerateOperation=true`. If VAP/VAPB generation is enabled, ensure it is handled by a singleton generator or disable it with `defaultCreateVAPForTemplates=false` and `defaultCreateVAPBindingForConstraints=false` (or the equivalent runtime flags).

For more details on how to deploy audit and 
number of instances to run, please refer to [operations audit](operations.md#audit). 

## Configuring Audit

- Audit violations per constraint: set `--constraint-violations-limit=123` (defaults to `20`). NOTE: This flag only impacts when gathering audit results using the constraint status model. If you want to export audit results via other means, please refer to [the export guide](export.md). Both approaches for getting audit violations can be configured independently and work simultaneously without any interference.
- Audit chunk size: set `--audit-chunk-size=400` (defaults to `500`, `0` = infinite) Lower chunk size can reduce memory consumption of the auditing `Pod` but can increase the number requests to the Kubernetes API server.
- Audit interval: set `--audit-interval=123` (defaults to every `60` seconds). Disable audit interval by setting `--audit-interval=0`
- Audit api server cache write to disk (Gatekeeper v3.7.0+): Starting from v3.7.0, by default, audit writes api server cache to the disk attached to the node. This reduces the memory consumption of the audit `pod`. If there are concerns with high IOPS, then switch audit to write cache to a tmpfs ramdisk instead. NOTE: write to ramdisk will increase memory footprint of the audit `pod`.  
  - helm install `--set audit.writeToRAMDisk=true` 
  - if not using helm, modify the deployment manifest to mount a ramdisk
    ```yaml
    - emptyDir:
        medium: Memory
    ```

By default, audit will request each resource from the Kubernetes API during each audit cycle. To rely on the audit informer cache instead, use the flag `--audit-from-cache=true`. Note that this requires replication of Kubernetes resources into the audit cache before they can be evaluated against the enforced policies. Refer to the [Replicating data](sync.md) section for more information.

### Disabling Audit

If you want to completely disable the audit process (for example, to reduce CPU or Memory usage), you must be careful not to break other singleton operations like CRD generation and status aggregation, which are also handled by the audit pod.

Instead of completely removing the audit deployment (e.g., by setting `disableAudit: true` in Helm), you should disable just the audit operation:
- In Helm, set `audit.disableAuditOperation: true`.
- If not using Helm, remove the `--operation=audit` flag from the audit deployment manifest.

### Audit using kinds specified in the constraints only

By default, Gatekeeper will audit all resources in the cluster. This operation can take some time depending on the number of resources.

If all of your constraints match against specific kinds (e.g. "match only pods"), then you can speed up audit runs by setting `--audit-match-kind-only=true` flag. This will only check resources of the kinds specified in all [constraints](howto.md#constraints) defined in the cluster.

For example, defining this constraint will only audit `Pod` kind:

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: prod-repo-is-openpolicyagent
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
...
```

If any of the [constraints](howto.md#constraints) do not specify `kinds`, it will be equivalent to not setting `--audit-match-kind-only` flag (`false` by default), and will fall back to auditing all resources in the cluster.

### Opt-out of Audit in constraints

By default, all constraints are opted-in audit. To opt-out of the audit process at constraint, you can use `enforcementAction: scoped` and define `scopedEnforcementActions` without including audit enforcement point.

For example, defining this constraint will opt-out of audit

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: prod-repo-is-openpolicyagent
spec:
...
  enforcementAction: scoped
  scopedEnforcementActions:
  - action: warn
    enforcementPoints:
    - name: "validation.gatekeeper.sh"
  - action: deny
    enforcementPoints:
    - name: "gator.gatekeeper.sh"
...
```

Find out more about different [enforcement points](enforcement-points.md) in Gatekeeper.

## Audit UserInfo

When using `input.review.userInfo`, *NOTE* the request's user's information, such as `username`, `uid`, `groups`, `extra`, cannot be populated by Kubernetes for audit reviews and therefore constraint templates that rely on `userInfo` are not auditable. It is up to the rego author to handle the case where `userInfo` is unset and empty in order to avoid every matching resource being reported as violating resources.

---

### Cloud Specific (`website/docs/cloud-specific.md`)

---
id: vendor-specific
title: Cloud and Vendor Specific Fixes
---

## Running on private GKE Cluster nodes

By default, firewall rules restrict the cluster master communication to nodes only on ports 443 (HTTPS) and 10250 (kubelet). Although Gatekeeper exposes its service on port 443, GKE by default enables `--enable-aggregator-routing` option, which makes the master to bypass the service and communicate straight to the POD on port 8443.

Two ways of working around this:

- create a new firewall rule from master to private nodes to open port `8443` (or any other custom port)
  - https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#add_firewall_rules
- make the pod to run on privileged port 443 (need to run pod as root, or have `NET_BIND_SERVICE` capability)
  - update Gatekeeper deployment manifest spec:
    - add `NET_BIND_SERVICE` to `securityContext.capabilities.add` to allow binding on privileged ports as non-root
    - update port from `8443` to `443`
    ```yaml
    containers:
    - args:
      - --port=443
      ports:
      - containerPort: 443
        name: webhook-server
        protocol: TCP
      securityContext:
        capabilities:
          drop: ["all"]
          add: ["NET_BIND_SERVICE"]
    ```

## Running on OpenShift 4.x

When running on OpenShift, the `anyuid` scc must be used to keep a restricted profile but being able to set the UserID.

In order to use it, the following section must be added to the gatekeeper-manager-role Role:

```yaml
- apiGroups:
  - security.openshift.io
  resourceNames:
    - anyuid
  resources:
    - securitycontextconstraints
  verbs:
    - use
```

With this restricted profile, it won't be possible to set the `container.seccomp.security.alpha.kubernetes.io/manager: runtime/default` annotation. On the other hand, given the limited amount of privileges provided by the anyuid scc, the annotation can be removed.

---

### Constrainttemplates (`website/docs/constrainttemplates.md`)

---
id: constrainttemplates
title: Constraint Templates
---

ConstraintTemplates define a way to validate some set of Kubernetes objects in Gatekeeper's Kubernetes [admission controller](https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/).

They are part of Gatekeeper's validation policy model. Mutation policies use separate [mutator resources](mutation.md).

ConstraintTemplates are made of two main elements:

1. Rego or CEL policy code in either `spec.targets[].rego` or `spec.targets[].code[]` that defines policy violation logic; see [field precedence](#field-precedence-in-constrainttemplate)
2. The schema of the accompanying `Constraint` object, which represents an instantiation of a `ConstraintTemplate`


## `v1` Constraint Template

In release version 3.6.0, Gatekeeper included the `v1` version of `ConstraintTemplate`.  Unlike past versions of `ConstraintTemplate`, `v1` requires the Constraint schema section to be [structural](https://kubernetes.io/blog/2019/06/20/crd-structural-schema/).

Structural schemas have a variety of [requirements](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema).  One such requirement is that the `type` field be defined for each level of the schema.

For example, users of Gatekeeper may recognize the `k8srequiredlabels` ConstraintTemplate, defined here in version `v1beta1`:

```yaml
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels

        violation[{"msg": msg, "details": {"missing_labels": missing}}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("you must provide labels: %v", [missing])
        }
```

The `parameters` field schema (`spec.crd.spec.validation.openAPIV3Schema`) is _not_ structural.  Notably, it is missing the `type:` declaration:

```yaml
openAPIV3Schema:
  # missing type
  properties:
    labels:
      type: array
      items:
        type: string
```

This schema is _invalid_ by default in a `v1` ConstraintTemplate.  Adding the `type` information makes the schema valid:

```yaml
openAPIV3Schema:
  type: object
  properties:
    labels:
      type: array
      items:
        type: string
```

For more information on valid types in JSONSchemas, see the [JSONSchema documentation](https://json-schema.org/understanding-json-schema/reference/type.html).

## Why implement this change?

Structural schemas are required in version `v1` of `CustomResourceDefinition` resources, which underlie ConstraintTemplates.  Requiring the same in ConstraintTemplates puts Gatekeeper in line with the overall direction of Kubernetes.

Beyond this alignment, structural schemas yield significant usability improvements. The schema of a ConstraintTemplate's associated Constraint is both more visible and type validated.

As the data types of Constraint fields are defined in the ConstraintTemplate, the API server will reject a Constraint with an incorrect `parameters` field. Previously, the API server would ingest it and simply not pass those `parameters` to Gatekeeper.  This experience was confusing for users, and is noticeably improved by structural schemas.

For example, see this incorrectly defined `k8srequiredlabels` Constraint:

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-gk
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    # Note that "labels" is now contained in an array item, rather than an object key under "parameters"
    - labels: ["gatekeeper"]
```

In a `v1beta1` ConstraintTemplate, this Constraint would be ingested successfully.  However, it would not work.  The creation of a new namespace, `foobar`, would succeed, even in the absence of the `gatekeeper` label:

```shell
$ kubectl create ns foobar
namespace/foobar created
```

This is incorrect.  We'd expect this to fail:

```shell
$ kubectl create ns foobar
Error from server ([ns-must-have-gk] you must provide labels: {"gatekeeper"}): admission webhook "validation.gatekeeper.sh" denied the request: [ns-must-have-gk] you must provide labels: {"gatekeeper"}
```

The structural schema requirement _prevents this mistake_.  The aforementioned `type: object` declaration would prevent the API server from accepting the incorrect `k8srequiredlabels` Constraint.

```shell
# Apply the Constraint with incorrect parameters schema
$ cat << EOF | kubectl apply -f -
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-gk
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    # Note that "labels" is now an array item, rather than an object
    - labels: ["gatekeeper"]
EOF
The K8sRequiredLabels "ns-must-have-gk" is invalid: spec.parameters: Invalid value: "array": spec.parameters in body must be of type object: "array"
```

Fixing the incorrect `parameters` section would then yield a successful ingestion and a working Constraint.

```shell
$ cat << EOF | kubectl apply -f -
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-gk
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["gatekeeper"]
EOF
k8srequiredlabels.constraints.gatekeeper.sh/ns-must-have-gk created
```

```shell
$ kubectl create ns foobar
Error from server ([ns-must-have-gk] you must provide labels: {"gatekeeper"}): admission webhook "validation.gatekeeper.sh" denied the request: [ns-must-have-gk] you must provide labels: {"gatekeeper"}
```

## Enable OPA Rego v1 syntax in ConstraintTemplates

Gatekeeper 3.19 ships with ability to use OPA Rego v1 as policy language in ConstraintTemplates. Using Rego v1 syntax is opt-in, by default only Rego v0 is allowed. You can use below spec to enable Rego v1 syntax:

```yaml
...
  targets:
    - target: admission.k8s.gatekeeper.sh
      code:
        - engine: Rego
          source:
            version: "v1"
            rego: |
              <v1-rego-code>
...
```

:::note
Rego v1 syntax can only be used under `targets[_].code[_].[engine: Rego].source` with `version: "v1"`. No need to add `import rego.v1` to use rego v1 syntax.
:::

Here is a sample ConstraintTemplate using Rego v1 syntax:

```yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          type: object
          properties:
            message:
              type: string
            labels:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                  allowedRegex:
                    type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      code:
        - engine: Rego
          source:
            version: "v1"
            rego: |
              package k8srequiredlabels

              violation contains 
                {"msg": msg, "details": {"missing_labels": missing}} 
                if {
                  provided := {label | input.review.object.metadata.labels[label]}
                  required := {label | label := input.parameters.labels[_]}
                  missing := required - provided
                  count(missing) > 0
                  msg := sprintf("you must provide labels: %v", [missing])
                }
```

## Built-in variables across all engines

### Common variables

### Rego variables

| Variable | Description |
| --- | --- |
| `input.review` | Contains input request object under review |
| `input.review.namespaceObject` | Contains the full Namespace object (with metadata, labels, annotations) for namespaced resources. This is `null` for cluster-scoped resources. |
| `input.parameters` | Contains constraint parameters e.g. `input.parameters.repos` see [example](https://open-policy-agent.github.io/gatekeeper-library/website/validation/allowedrepos) |
| `data.lib`     |  It serves as an import path for helper functions defined under `libs` in ConstraintTemplate, e.g. data.lib.exempt_container.is_exempt see [example](https://open-policy-agent.github.io/gatekeeper-library/website/validation/host-network-ports) |
| `data.inventory` | Refers to a structure that stores synced cluster resources. It is used in Rego policies to validate or enforce referential rules based on the current state of the cluster. e.g. unique ingress host [example](https://open-policy-agent.github.io/gatekeeper-library/website/validation/uniqueingresshost/) |

### CEL variables

| Variable | Description |
| --- | --- |
| `variables.params` | Contains constraint parameters e.g. `variables.params.labels` see [example](https://open-policy-agent.github.io/gatekeeper-library/website/validation/requiredlabels) |
| `variables.anyObject` | Contains either an object or (on DELETE requests) oldObject, see [example](https://open-policy-agent.github.io/gatekeeper-library/website/validation/requiredlabels) |
| `namespaceObject` | Contains the full Namespace object (with metadata, labels, annotations) for namespaced resources. This is `null` for cluster-scoped resources. This aligns with the Kubernetes Validating Admission Policy `namespaceObject` variable. |

## Field Precedence in ConstraintTemplate

ConstraintTemplates support multiple ways to define policy code with the following precedence rules: (1) The legacy `spec.targets[].rego` field takes precedence over any Rego engine defined in `spec.targets[].code[]`. (2) When multiple engines are defined in the `code` array, only one engine is evaluated—the `K8sNativeValidation` (CEL) engine has higher priority than the `Rego` engine with no fallback mechanism. **Best practice:** Use the `code` array exclusively and define policy logic in only one engine (either Rego for complex policies with referential constraints and external data, or CEL for simpler validations) to avoid confusion about which policy will be evaluated.

For more information on CEL integration and engine precedence, see the [Integration with Kubernetes Validating Admission Policy](validating-admission-policy.md) documentation.

## Managing Rego at Scale with Helm

When managing many policies or writing complex policies, it is often desirable to keep the Rego logic in separate `.rego` files. This allows you to leverage tools like `opa fmt` and `opa test` for unit testing, and maintain better code readability.

Instead of manually copying and pasting your Rego code into the `ConstraintTemplate` YAML, you can use Helm to compile the template. 

By utilizing the `Files.Get` function in Helm, you can inject the contents of an external Rego file directly into your `ConstraintTemplate` at deployment time.

For example, your Helm template (`templates/constrainttemplate.yaml`) might look like this:

```yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        {{ .Files.Get "policies/requiredlabels.rego" | indent 8 }}
```

With this approach, you can maintain `policies/requiredlabels.rego` alongside your unit tests in the same repository, and Helm will seamlessly inline it when you install or upgrade the chart.

---

### Customize Admission (`website/docs/customize-admission.md`)

---
id: customize-admission
title: Customizing Admission Behavior
---

Gatekeeper is a [Kubernetes admission webhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#webhook-configuration)
whose default configuration can be found in the `gatekeeper.yaml` manifest file. By default, it is
a `ValidatingWebhookConfiguration` resource named `gatekeeper-validating-webhook-configuration`.

Currently the configuration specifies two webhooks: one for checking a request against
the installed constraints and a second webhook for checking labels on namespace requests
that would result in bypassing constraints for the namespace. The namespace-label webhook
is necessary to prevent a privilege escalation where the permission to add a label to a
namespace is equivalent to the ability to bypass all constraints for that namespace.
You can read more about the ability to exempt namespaces by label [here](exempt-namespaces.md#exempting-namespaces-from-the-gatekeeper-admission-webhook-using---exempt-namespace-flag).

Because Kubernetes adds features with each version, if you want to know how the webhook can be configured it
is best to look at the official documentation linked at the top of this section. However, two particularly important
configuration options deserve special mention: [timeouts](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#timeouts) and
[failure policy](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#failure-policy).

Timeouts allow you to configure how long the API server will wait for a response from the admission webhook before it
considers the request to have failed. Note that setting the timeout longer than the overall request timeout
means that the main request will time out before the webhook's failure policy is invoked, causing the
request to fail.

Failure policy controls what happens when a webhook fails for whatever reason. Common
failure scenarios include timeouts, a 5xx error from the server or the webhook being unavailable.
You have the option to ignore errors, allowing the request through, or failing, rejecting the request.
This results in a direct tradeoff between availability and enforcement.

Currently Gatekeeper is defaulting to using `Ignore` for the constraint requests, which means
constraints will not be enforced at admission time if the webhook is down or otherwise inaccessible.
This is because we cannot know the operational details of the cluster Gatekeeper is running on and
how that might affect webhook uptime. For a more detailed treatment of this topic, see our docs
on [failing closed](failing-closed.md).

The namespace label webhook defaults to `Fail`, this is to help ensure that policies preventing
labels that bypass the webhook from being applied are enforced. Because this webhook only gets
called for namespace modification requests, the impact of downtime is mitigated, making the
theoretical maximum availability less of an issue.

Because the manifest is available for customization, the webhook configuration can
be tuned to meet your specific needs if they differ from the defaults.

## Enable Validation of Delete Operations

### Caveats

#### Deletes are not Auditable

Once a resource is deleted, it is gone. This means that non-compliant deletes cannot be
audited via Gatekeeper's audit mechanism, and increases the importance of webhook-based
enforcement.

#### Policies Against DELETE May Not be Perfectly Enforced

Since the webhook fails open by default (as described earlier on this page), it is possible
for admission requests to have imperfect enforcement, which means some non-compliant deletes
may still go through despite the policy. Normally such failures of webhook enforcement could
be caught by audit, but deletes are not auditable.

It is possible to improve the likelihood of enforcement by configuring the webhook to
[fail closed](failing-closed.md).

### How to Enable Validation of Delete Operations

To enable Delete operations for the `validation.gatekeeper.sh` admission webhook, add "DELETE" to the list of operations in the `gatekeeper-validating-webhook-configuration` ValidatingWebhookConfiguration as seen in this deployment manifest of gatekeeper: [here](https://github.com/open-policy-agent/gatekeeper/blob/v3.1.0-beta.10/deploy/gatekeeper.yaml#L792-L794)

 So you have
 ```YAML
    operations:
    - CREATE
    - UPDATE
    - DELETE
```

You can now check for deletes.

### How to Enable Validation of Connect Operations

This operation allows gatekeeper to review and validate `kubectl exec` commands via the validation webhook.

To enable Connect operations for the `validation.gatekeeper.sh` admission webhook, add "CONNECT" to the list of operations in the `gatekeeper-validating-webhook-configuration`.

```yaml
    operations:
    - CREATE
    - UPDATE
    - CONNECT
```

---

### Customize Startup (`website/docs/customize-startup.md`)

---
id: customize-startup
title: Customizing Startup Behavior
---

## Allow retries when adding objects to OPA

Gatekeeper's webhook servers undergo a bootstrapping period during which they are unavailable until the initial set of resources (constraints, templates, synced objects, etc...) have been ingested. This prevents Gatekeeper's webhook from validating based on an incomplete set of policies. This wait-for-bootstrapping behavior can be configured.

The `--readiness-retries` flag defines the number of retry attempts allowed for an object (a Constraint, for example) to be successfully added to OPA.  The default is `0`.  A value of `-1` allows for infinite retries, blocking the webhook until all objects have been added to OPA.  This guarantees complete enforcement, but has the potential to indefinitely block the webhook from serving requests.

## Enable profiling using `pprof`

The `--enable-pprof` flag enables an HTTP server for profiling using the [pprof](https://pkg.go.dev/net/http/pprof) library. By default, it serves to `localhost:6060` but the port can be customized with the `--pprof-port` flag.

## Disable certificate generation and rotation for Gatekeeper's webhook

By default, Gatekeeper uses [`open-policy-agent/cert-controller`](https://github.com/open-policy-agent/cert-controller) to handle the webhook's certificate rotation and generation. If you want to use a third-party solution, you may disable the cert-controller feature using `--disable-cert-rotation`.

## Disable OPA built-in functions

The `--disable-opa-builtin` flag disables specific [OPA built-ins functions](https://www.openpolicyagent.org/docs/v0.37.2/policy-reference/#built-in-functions). Starting with v3.8.0, Gatekeeper disables the `http.send` built-in function by default. For more information, please see [external data](./externaldata.md#motivation).

## [Alpha] Emit admission and audit events

The `--emit-admission-events` flag enables the emission of all admission violations as Kubernetes events. This flag is in alpha stage and it is set to `false` by default.

The `--emit-audit-events` flag enables the emission of all audit violation as Kubernetes events. This flag is in alpha stage and it is set to `false` by default.

The `--admission-events-involved-namespace` flag controls which namespace admission events will be created in. When set to `true`, admission events will be created in the namespace of the object violating the constraint. If the object has no namespace (ie. cluster scoped resources), they will be created in the namespace Gatekeeper is installed in. Setting to `false` will cause all admission events to be created in the Gatekeeper namespace.

The `--audit-events-involved-namespace` flag controls which namespace audit events will be created in. When set to `true`, audit events will be created in the namespace of the object violating the constraint. If the object has no namespace (ie. cluster scoped resources), they will be created in the namespace Gatekeeper is installed in. Setting to `false` will cause all audit events to be created in the Gatekeeper namespace.

There are four types of events that are emitted by Gatekeeper when the emit event flags are enabled:

| Event              | Description                                                             |
| ------------------ | ----------------------------------------------------------------------- |
| `FailedAdmission`  | The Gatekeeper webhook denied the admission request (default behavior). |
| `WarningAdmission` | When `enforcementAction: warn` is specified in the constraint.          |
| `DryrunViolation`  | When `enforcementAction: dryrun` is specified in the constraint.        |
| `AuditViolation`   | A violation is detected during an audit.                                |

> ❗ Warning: if the same constraint and violating resource tuple was emitted for [more than 10 times in a 10-minute rolling interval](https://github.com/kubernetes/kubernetes/blob/v1.23.3/staging/src/k8s.io/client-go/tools/record/events_cache.go#L429-L438), the Kubernetes event recorder will aggregate the events, e.g.
> ```
> 39s         Warning   FailedAdmission   namespace/test      (combined from similar events):  Admission webhook "validation.gatekeeper.sh" denied request, Resource Namespace: , Constraint: ns-must-have-gk, Message: you must provide labels: {"gatekeeper"}
> ```
> Gatekeeper might burst 25 events about an object, but limit the refill rate to 1 new event every 5 minutes. This will help control the long-tail of events for resources that are always violating the constraint.

## [Alpha] Emit API server audit annotations for admission evaluations

The `--emit-admission-audit-annotations` flag adds audit annotations to validation requests that reach Gatekeeper policy evaluation. It is disabled by default. When enabled, it annotates violations only unless `--admission-audit-annotations-include-success=true` is also set. Requests skipped before policy evaluation, such as excluded namespaces, are not annotated.

The validation webhook returns one `evaluation` entry in `AdmissionResponse.auditAnnotations`. The API server prefixes that key with the webhook name, producing `validation.gatekeeper.sh/evaluation` in the API audit event. Its versioned JSON value contains Gatekeeper's `allowed` decision, bounded summaries of deny, warn, and dryrun violations, the total and included violation counts, and a truncation indicator. The decision is specific to Gatekeeper; another admission plugin or a later API server error can still reject the request. Request identity belongs to the enclosing audit event and is not repeated in this payload. The AdmissionReview UID, event type, evaluated resource kind/version, resource labels, and Constraint annotations are also intentionally omitted. The value is limited to 10 KiB. Long messages, policy-provided `details`, or additional violations may be omitted, and the payload reports truncation.

With `--admission-audit-annotations-include-success=true`, an evaluation with no violations produces this custom annotation value; otherwise it produces no custom annotation:

```json
{"schemaVersion":"v1","allowed":true,"violations":[],"totalViolations":0,"includedViolations":0,"truncated":false}
```

When admission audit annotations are enabled on a process performing the `generate` operation, generated ValidatingAdmissionPolicyBindings add the Kubernetes `Audit` action alongside `Deny` or `Warn`; `dryrun` already maps to `Audit`. Failed native validations therefore produce Kubernetes' standard `validation.policy.admission.k8s.io/validation_failure` annotation. Kubernetes controls that annotation's content and aggregation; it is not an exhaustive list of all matching bindings. By default, generated ValidatingAdmissionPolicies omit the custom `evaluation` marker and rely on this native failure annotation.

To also annotate successful evaluations, set `--admission-audit-annotations-include-success=true`. It defaults to `false` and has no effect unless `--emit-admission-audit-annotations` is enabled. Success here means zero violations, not simply an allowed request: deny, warn, and dryrun violations remain annotated regardless of this setting. When both flags are enabled, generated VAPs add an `evaluation` audit annotation with the value `true` when at least one binding evaluates the request. Kubernetes deduplicates this constant across matching bindings, keeping the value bounded without listing matching Constraint names. This option does not re-evaluate CEL expressions or change admission decisions. For Helm, set `emitAdmissionAuditAnnotations=true` for violations-only auditing, and also set `admissionAuditAnnotationsIncludeSuccess=true` to include successful evaluations. If the webhook and native VAP enforcement points both evaluate a request, both may add audit entries.

For split deployments, configure both flags consistently on the validation webhook process and the process performing the `generate` operation. Restart the affected processes when changing these startup settings; generated VAPs are reconciled to the selected mode. API server audit logging must be enabled at `Metadata` or a higher level. Audit annotations do not create Kubernetes Event resources, do not annotate admitted objects, and do not change admission decisions. The violation-export payload is unaffected by these settings. Policy messages and `details` may contain user-controlled or sensitive data, so protect access to the audit backend.

## [Beta] Enable mutation logging and annotations

The `--log-mutations` flag enables logging of mutation events and errors.

The `--mutation-annotations` flag adds the following two annotations to mutated objects:

| Annotation                  | Value                                                                                                                                                         |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gatekeeper.sh/mutation-id` | The UUID of the mutation.                                                                                                                                     |
| `gatekeeper.sh/mutations`   | A list of comma-separated mutations in the format of `<MutationType>/<MutationNamespace>/<MutationName>:<MutationGeneration>` that are applied to the object. |

> ❗ Note that this will break the idempotence requirement that Kubernetes sets for mutation webhooks. See the [Kubernetes docs here](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#idempotence) for more details

## [Alpha] Remote Cluster Mode for Gatekeeper

The `--enable-remote-cluster` flag enables Gatekeeper to run in a local (management) cluster while enforcing policies on a separate target cluster specified via `--kubeconfig`. This is designed for hosted control plane architectures where the target cluster's API server runs within the management cluster.

> 📖 For a full end-to-end setup walkthrough, installing CRDs across both clusters, deploying Gatekeeper, wiring webhook certificates, and a smoke test see the [Remote Cluster Mode](remote-cluster.md) guide.

### When to Use

Use remote cluster mode when:
- Gatekeeper runs in a local (management) cluster
- You want to enforce policies on a remote target cluster

### Configuration

```bash
--enable-remote-cluster            # Enable remote cluster mode
--kubeconfig=/path/to/target.yaml  # Kubeconfig for target cluster
```

### How It Works

Status resources live on the management cluster alongside the Gatekeeper pod, with OwnerReferences pointing to the pod. This enables automatic garbage collection — when a pod restarts, Kubernetes cleans up its old status resources automatically.

### RBAC Requirements

Gatekeeper needs permissions on the **management/local cluster** to resolve its pod identity and manage status resources:

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: gatekeeper-manager-role
  namespace: gatekeeper-system
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get"]
- apiGroups: ["status.gatekeeper.sh"]
  resources: ["*"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
```

### Migration from Previous Versions

If upgrading from a version where `--enable-remote-cluster` stored status resources on the target cluster, you may have orphaned status resources on the target cluster. Run the following to clean them up:

```bash
kubectl delete constrainttemplatepodstatuses,constraintpodstatuses,mutatorpodstatuses,expansiontemplatepodstatuses,configpodstatuses,providerpodstatuses,connectionpodstatuses \
  -n gatekeeper-system --all --context <target-cluster-context>
```

This is a one-time cleanup. After upgrading, status resources are automatically managed on the management cluster.

```bash
# List all pod names referenced in status resources (repeat for each status type)
kubectl get constrainttemplatepodstatuses -n gatekeeper-system \
  -o jsonpath="{.items[*].metadata.labels['gatekeeper\.sh/pod']}" | tr ' ' '\n' | sort -u

# Compare with running Gatekeeper pods in local cluster
kubectl get pods -n gatekeeper-system -l control-plane=controller-manager -o name
```

To clean up orphaned resources after identifying old pod names:

```bash
# Delete status resources for a specific old pod
OLD_POD="gatekeeper-controller-manager-old-xyz"
kubectl delete constrainttemplatepodstatuses,constraintpodstatuses,mutatorpodstatuses,expansiontemplatepodstatuses,configpodstatuses,providerpodstatuses,connectionpodstatuses \
  -n gatekeeper-system -l gatekeeper.sh/pod=$OLD_POD
```

## Other Configuration Options

For the complete list of configuration flags for your specific version of Gatekeeper, run the Gatekeeper binary with the `--help` flag. For example:

`docker run openpolicyagent/gatekeeper:v3.10.0-beta.0 --help`

To ensure you are seeing all relevant flags, be sure the image tag (`:3.10.0-beta.0` above) corresponds with the version of Gatekeeper you are running.

---

### Debug (`website/docs/debug.md`)

---
id: debug
title: Debugging
---

> NOTE: Verbose logging with DEBUG level can be turned on with `--log-level=DEBUG`.  By default, the `--log-level` flag is set to minimum log level `INFO`. Acceptable values for minimum log level are [`DEBUG`, `INFO`, `WARNING`, `ERROR`]. In production, this flag should not be set to `DEBUG`.

## Viewing the Request Object

A simple way to view the request object is to use a constraint/template that
denies all requests and outputs the request object as its rejection message.

Example template:

```yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sdenyall
spec:
  crd:
    spec:
      names:
        kind: K8sDenyAll
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdenyall

        violation[{"msg": msg}] {
          msg := sprintf("REVIEW OBJECT: %v", [input.review])
        }
```

Example constraint:

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyAll
metadata:
  name: deny-all-namespaces
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
```

## Tracing

In debugging decisions and constraints, a few pieces of information can be helpful:

   * Cached data and existing rules at the time of the request
   * A trace of the evaluation
   * The input document being evaluated

Writing out all the information above for every request would be expensive in terms of memory and load on the Gatekeeper server, which may lead to requests timing out. It would also be hard
to find the relevant logs for a given request.

For tracing, Gatekeeper **requires** operators to specify
resources and requesting users for which traces will be logged. They can do so by
configuring the `Config` resource, which lives in the `gatekeeper-system` namespace.

Below is an example of a config resource:

```yaml
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
  name: config
  namespace: "gatekeeper-system"
spec:
  # Data to be replicated into OPA
  sync:
    syncOnly:
      - group: ""
        version: "v1"
        kind: "Namespace"
  validation:
    # Requests for which we want to run traces
    traces:
        # The requesting user for which traces will be run
        # This field is required.
        # To trace multiple users, feel free to pass in a list.
        # To trace controllers, use the service accounts of those controllers.
      - user: "user_to_trace@company.com"
        kind:
          # The group, version, kind for which we want to run a trace
          group: ""
          version: "v1"
          kind: "Namespace"
        # If dump is defined and set to `All`, also dump the state of OPA
        dump: "All"
```

Traces will be written to the stdout logs of the Gatekeeper controller.


If there is an error in the Rego in the ConstraintTemplate, there are cases where it is still created via `kubectl apply -f [CONSTRAINT_TEMPLATE_FILENAME].yaml`.

When applying the constraint using `kubectl apply -f constraint.yaml` with a ConstraintTemplate that contains incorrect Rego, and error will occur: `error: unable to recognize "[CONSTRAINT_FILENAME].yaml": no matches for kind "[NAME_OF_CONSTRAINT]" in version "constraints.gatekeeper.sh/v1beta1"`.

To find the error, run `kubectl get -f [CONSTRAINT_TEMPLATE_FILENAME].yaml -o yaml`. Build errors are shown in the `status` field.

---

### Developers (`website/docs/developers.md`)

---
id: developers
title: Developers
---

This section describes how Gatekeeper developers can leverage [kind](https://kind.sigs.k8s.io/) and [Tilt](https://tilt.dev/) for rapid iterative development. Kind allows developers to quickly provision a conformant Kubernetes cluster using Docker and Tilt enables smart rebuilds and live updates of your Kubernetes workload during development time.

## Prerequisites

1. [kind](https://kind.sigs.k8s.io/#installation-and-usage) v0.11.0 or newer
2. [Tilt](https://docs.tilt.dev/install.html) v0.25.0 or newer

## Getting started

### Create a kind cluster with a local registry

Kind cluster with a local registry will enable faster image pushing and pulling:

```bash
./third_party/github.com/tilt-dev/kind-local/kind-with-registry.sh
```

> If you would like to customize the local registry port on your machine (the default port is `5000`), you can run `export KIND_REGISTRY_PORT=<port>` to customize it.

### Create `tilt-settings.json`

`tilt-settings.json` contains various settings that developers can customize when deploying gatekeeper to a local kind cluster. Developers can create the JSON file under the project root directory:

```json
{
    "helm_values": {
        "controllerManager.metricsPort": 8080,
        "enableExternalData": true
    },
    "trigger_mode": "manual"
}
```

#### `tilt-settings.json` fields

- `helm_values` (Map, default=`{}`): A map of helm values to be injected when deploying `manifest_staging/charts/gatekeeper` to the kind cluster.

- `trigger_mode` (String, default=`"auto"`): Optional setting to configure if tilt should automatically rebuild on changes. Set to `manual` to disable auto-rebuilding and require users to trigger rebuilds of individual changed components through the UI.

### Run `make tilt`

```bash
make tilt
```

<details>
<summary>Output</summary>

```
/* Detailed source-code truncated for AI context efficiency. */
```

</details>

### Start developing!

If you have trigger mode set to `auto`, any changes in the source code will trigger a rebuild of the gatekeeper manager binary. The build will subsequently trigger a rebuild of the gatekeeper manager image, load it to your kind cluster, and restart the deployment.

If you have trigger mode set to `manual`, you can trigger a manager build manually in the local Tilt UI portal. By default, it is located at `http://localhost:10350/`

### Tear down the kind cluster

To tear down the kind cluster and its local registry:

```bash
./third_party/github.com/tilt-dev/kind-local/teardown-kind-with-registry.sh
```

---

### Emergency (`website/docs/emergency.md`)

---
id: emergency
title: Emergency Recovery
---

If a situation arises where Gatekeeper is preventing the cluster from operating correctly,
the webhook can be disabled. This will remove all Gatekeeper admission checks. Assuming
the default webhook name has been used this can be achieved by running:

`kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io gatekeeper-validating-webhook-configuration`

Redeploying the webhook configuration will re-enable Gatekeeper.

---

### Enforcement Points (`website/docs/enforcement-points.md`)

---
id: enforcement-points
title: Enforcement points in Gatekeeper
---

## Understanding Enforcement Points

An enforcement point defines the location where enforcement happens. Below are the different enforcement points available in Gatekeeper:

- `validation.gatekeeper.sh` indicates that enforcement should be carried out by Gatekeeper's validating webhook for a constraint. Supports templates with CEL and Rego.
- `gator.gatekeeper.sh` indicates that enforcement should be carried out in shift-left via [gator-cli](gator.md) for a constraint. Supports templates with CEL and Rego.
- `audit.gatekeeper.sh` indicates that on-cluster resources should be audited and violations should be reported for the resources that are in violation of constraint. Supports templates with CEL and Rego.
- `vap.k8s.io` indicates that enforcement should be carried out by Validating Admission Policy for a constraint. Supports templates with CEL.

### How to use different enforcement points in constraint

By default, a constraint will be enforced at all enforcement points with common enforcement action defined in `spec.enforcementAction`. However, you can choose to enforce a constraint at specific enforcement points with different actions using `enforcementAction: scoped` and `spec.scopedEnforcementActions`. Below are examples and use cases that utilize different enforcement actions for different enforcement points.

:::note
`spec.enforcementAction: scoped` is needed to customize specific enforcement point/enforcement action behavior. If `spec.enforcementAction: scoped` is not provided, `spec.scopedEnforcementActions` is ignored and the provided `enforcementAction` will be applied across all enforcement points.
:::

###### Deny in shift-left and warn at admission

You are trying out a new constraint template, and you want to deny violating resources in shift-left testing, but do not want to block any resources admitted to clusters to reduce impact for faulty rejections. You may want to use `deny` action for the `gator.gatekeeper.sh` shift-left enforcement point and `warn` for `the validation.gatekeepet.sh` admission webhook enforcement point. The below constraint satisfies this use case.

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: prod-repo-is-openpolicyagent
spec:
...
  enforcementAction: scoped
  scopedEnforcementActions:
  - action: warn
    enforcementPoints:
    - name: "validation.gatekeeper.sh"
  - action: deny
    enforcementPoints:
    - name: "gator.gatekeeper.sh"
...
```

> **Note**: The audit enforcement point is not included unless explicitly added to scopedEnforcementActions.enforcementPoints or if scopedEnforcementActions.enforcementPoints is set to "*".

###### Only audit

You are depending on external-data or referential policies for validating resources. These type of validation may be latency sensitive and may take longer to evaluate. To avoid such situation you may want to only use `audit.gatekeeper.sh` enforcement point to not face any delay at admission time, but still get the information about violating resources from Gatekeeper's audit operation. Here is the constraint for only using `audit.gatekeeper.sh` enforcement point.

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: prod-repo-is-openpolicyagent
spec:
...
  enforcementAction: scoped
  scopedEnforcementActions:
  - action: deny
    enforcementPoints:
    - name: "audit.gatekeeper.sh"
...
```

###### Enforcing through Validating Admission Policy and using Gatekeeper as fall-back validation mechanism

You want to utilize in-tree Validating Admission Policy for faster turn around time. But you want to make sure that in case Validating Admission Policy fails-open, Gatekeeper blocks faulty resources from being created. Here is how you can achieve the same.

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: prod-repo-is-openpolicyagent
spec:
...
  enforcementAction: scoped
  scopedEnforcementActions:
  - action: deny
    enforcementPoints:
    - name: "vap.k8s.io"
    - name: "validation.gatekeeper.sh"
...
```

Please refer to [VAP/VAPB generation behavior](validating-admission-policy.md#policy-updates-to-generate-validating-admission-policy-resources).

###### Enforcing through Validating Admission Policy and using audit from Gatekeeper

You want to utilize in-tree Validating Admission Policy for faster turn around time and only want to use audit operation from Gatekeeper to get information about violation resources on-cluster. Here is the constraint that users `vap.k8s.io` and `audit.gatekeeper.sh` enforcement points.

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: prod-repo-is-openpolicyagent
spec:
...
  enforcementAction: scoped
  scopedEnforcementActions:
  - action: deny
    enforcementPoints:
    - name: "vap.k8s.io"
    - name: "audit.gatekeeper.sh"
...
```

Checkout this [demo](https://github.com/open-policy-agent/gatekeeper/tree/master/demo/scoped-enforcement-actions) to understand how enforcement points and actions work.

---

### Examples (`website/docs/examples.md`)

---
id: examples
title: Examples
---

The [demo/basic](https://github.com/open-policy-agent/gatekeeper/tree/master/demo/basic) directory contains the above examples of simple constraints, templates and configs to play with.

The [demo/agilebank](https://github.com/open-policy-agent/gatekeeper/tree/master/demo/agilebank) directory contains more complex examples based on a slightly more realistic scenario. Both folders have a handy demo script to step you through the demos.

---

### Exempt Namespaces (`website/docs/exempt-namespaces.md`)

---
id: exempt-namespaces
title: Exempting Namespaces
---

`Feature State`: The `Config` resource is currently alpha.

## Exempting Namespaces from Gatekeeper using config resource

> The "Config" resource must be named `config` for it to be reconciled by Gatekeeper. Gatekeeper will ignore the resource if you do not name it `config`.

The config resource can be used as follows to exclude namespaces from certain processes for all constraints in the cluster. An asterisk can be used for wildcard matching (e.g. `kube-*`). To exclude namespaces at a constraint level, use `excludedNamespaces` in the [constraint](howto.md#constraints) instead.

```yaml
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
  name: config
  namespace: "gatekeeper-system"
spec:
  match:
    - excludedNamespaces: ["kube-*", "my-namespace"]
      processes: ["*"]
    - excludedNamespaces: ["audit-excluded-ns"]
      processes: ["audit"]
    - excludedNamespaces: ["audit-webhook-sync-excluded-ns"]
      processes: ["audit", "webhook", "sync"]
    - excludedNamespaces: ["mutation-excluded-ns"]
      processes: ["mutation-webhook"]
...
```

Available processes:

- `audit` process exclusion will exclude resources from specified namespace(s) in audit results.
- `webhook` process exclusion will exclude resources from specified namespace(s) from the admission webhook.
- `sync` process exclusion will exclude resources from specified namespace(s) from being synced into OPA.
- `mutation-webhook` process exclusion will exclude resources from specified namespace(s) from the mutation webhook.
- `*` includes all current processes above and includes any future processes.

## Exempting Namespaces from the Gatekeeper Admission Webhook using `--exempt-namespace` flag

Note that the following only exempts resources from the admission webhook. They will still be audited. Editing individual constraints or [config resource](#exempting-namespaces-from-gatekeeper-using-config-resource) is
necessary to exclude them from audit.

If it becomes necessary to exempt a namespace from Gatekeeper webhook entirely (e.g. you want `kube-system` to bypass admission checks), here's how to do it:

   1. Make sure the validating admission webhook configuration for Gatekeeper has the following namespace selector:

        ```yaml
          namespaceSelector:
            matchExpressions:
            - key: admission.gatekeeper.sh/ignore
              operator: DoesNotExist
        ```

      the default Gatekeeper manifest should already have added this. The default name for the
      webhook configuration is `gatekeeper-validating-webhook-configuration` and the default
      name for the webhook that needs the namespace selector is `validation.gatekeeper.sh`

   2. Tell Gatekeeper it's okay for the namespace to be ignored by adding a flag to the pod:
      `--exempt-namespace=<NAMESPACE NAME>`. This step is necessary because otherwise the
      permission to modify a namespace would be equivalent to the permission to exempt everything
      in that namespace from policy checks. This way a user must explicitly have permissions
      to configure the Gatekeeper pod before they can add exemptions.

      > In order to add the `admission.gatekeeper.sh/ignore` label to a namespace, that namespace must be listed under the gatekeeper `controllerManager.exemptNamespaces` [parameter](https://github.com/open-policy-agent/gatekeeper/blob/master/charts/gatekeeper/README.md#parameters) when installing via Helm.

   3. Add the `admission.gatekeeper.sh/ignore` label to the namespace. The value attached
      to the label is ignored, so it can be used to annotate the reason for the exemption.

Similarly, you can also enable the exemption of entire groups of namespaces using the `--exempt-namespace-prefix` and `--exempt-namespace-suffix` flags. Using these flags allows the `admission.gatekeeper.sh/ignore` label to be added to any namespace that matches the supplied prefix or suffix.

## Difference between exclusion using config resource and `--exempt-namespace` flag

The difference is at what point in the admission process an exemption occurs.

If you use `--exempt-namespace` flag and `admission.gatekeeper.sh/ignore` label, Gatekeeper's webhook will not be called by the API server for any resource in that namespace. That means that Gatekeeper being down should have no effect on requests for that namespace.

If you use the config method, Gatekeeper itself evaluates the exemption. The benefit there is that we have more control over the syntax and can be more fine-grained, but it also means that the API server is still calling the webhook, which means downtime can have an impact.

---

### Expansion (`website/docs/expansion.md`)

---
id: expansion
title: Validating Workload Resources using ExpansionTemplate
---

`Feature State:` Gatekeeper version v3.10+ (alpha), version 3.13+ (beta)

> ❗This feature is in _beta_ stage. It is enabled by default. To disable the feature,
> set the `enable-generator-resource-expansion` flag to false.

## Motivation

A workload resource is a resource that creates other resources, such as a
[Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) or [Job](https://kubernetes.io/docs/concepts/workloads/controllers/job/). Gatekeeper can be configured to reject workload resources
that create a resource that violates a constraint.

## `ExpansionTemplate` explained

An `ExpansionTemplate` is a custom resource that Gatekeeper will use to create temporary, fake resources and validate the constraints against them. We refer to these resources that Gatekeeper creates for validation purposes as `expanded resources`. We refer to the `Deployment` or other workload resource as the `parent resource` and the act of creating those `expanded` resources as `expansion`.

The `ExpansionTemplate` custom resource specifies:

- Which workload resource(s) should be expanded, specified by their GVK
- The GVK of the expanded resources
- The "source" as defined in the field `templateSource` on the `parent resource`, which is used as the blueprint for the expanded resource. For example, in a case where a
  `Deployment` expands into a `Pod`, `spec.template` would typically be the
  source.
- Optionally, an `enforcementAction` override can be used when validating expanded
  resources. If this field is set, any violations against the expanded resource
  will use this enforcement action. If an enforcement action is not specified by
  the `ExpansionTemplate`, the enforcement action set by the Constraint in
  violation will be used.

Here is an example of a `ExpansionTemplate` that specifies that `DaemonSet`,
`Deployment`, `Job`, `ReplicaSet`, `ReplicationController`, and `StatefulSet`
 resources should be expanded into a `Pod`.

```yaml
apiVersion: expansion.gatekeeper.sh/v1alpha1
kind: ExpansionTemplate
metadata:
  name: expand-deployments
spec:
  applyTo:
    - groups: ["apps"]
      kinds: ["DaemonSet", "Deployment", "ReplicaSet", "StatefulSet"]
      versions: ["v1"]
    - groups: [""]
      kinds: ["ReplicationController"]
      versions: ["v1"]
    - groups: ["batch"]
      kinds: ["Job"]
      versions: ["v1"]
  templateSource: "spec.template"
  enforcementAction: "warn" # This will overwrite all constraint enforcement actions for the GVKs below that result from the GVKs above.
  generatedGVK:
    kind: "Pod"
    group: ""
    version: "v1"
```

With this `ExpansionTemplate`, any constraints that are configured to target
`Pods` will also be evaluated on the `expanded` pods that Gatekeeper creates when a `Deployment` or `ReplicaSet` is
being reviewed. Any violations created against these expanded `Pod`s, and only these expanded `Pod`s, will have their
enforcement action set to `warn`, regardless of the enforcement actions
specified by the Constraint in violation.

To see how to use Mutators and Constraints to exclusively review expanded resources, see the [Match Source](#match-source) section below.

### Limitations

#### Sidecars and Mutators

It may not always be possible to build an accurate representation of an
expanded resource by looking at the workload resource alone. For example, suppose a
cluster is using [Istio](https://istio.io/), which will inject a sidecar container on specific
resources. This sidecar configuration is not specified in the config of the
workload resource (i.e. Deployment), but rather injected by Istio's webhook. In
order to accurately represent expanded resources modified by controllers or
webhooks, Gatekeeper leverages its
[Mutations](mutation.md)
feature to allow expanded resources to be manipulated into their desired form. In
the Istio example, `Assign` and `ModifySet` mutators could be configured to
mimic Istio sidecar injection. For further details on mutating expanded resources
see the [Match Source](#match-source) section below, or to see a working example,
see the [Mutating Example](#mutating-example) section.

#### Unknown Data

Any resources configured for expansion will be expanded by both the validating
webhook and
[Audit](audit.md). This
feature will only be enabled if a user creates an `ExpansionTemplate` that
targets any resources that exist on the cluster.

Note that the accuracy of enforcement depends on how well the expanded resource
resembles the real thing. Mutations can help with this, but 100% accuracy is
impossible because not all fields can be predicted. For instance, Deployments
create pods with random names. Inaccurately expanded resources may lead to over- or under-
enforcement. In the case of under-enforcement, the expanded pod should still be
rejected. Finally, non-state-based policies (those that rely on transient
metadata such as requesting user or time of creation) cannot be enforced
accurately. This is because such metadata would necessarily be different when
creating the expanded resource. For example, a Deployment is created using the
requesting user's account, but the pod creation request comes from the service
account of the Deployment controller.

## Configuring Expansion

Expansion behavior is configured through the `ExpansionTemplate` custom
resource. Optionally, users can create `Mutation` custom resources to customize
how resources are expanded. Mutators with the `source: Generated` field will
only be applied when expanding workload resources, and will not mutate real
resources on the cluster. If the `source` field is not set, the `Mutation` will
apply to both expanded resources and real resources on the cluster.

Users can test their expansion configuration using the
[`gator expand` CLI](gator.md#the-gator-expand-subcommand)
.

#### Match Source

The `source` field on the `match` API, present in the Mutation
and `Constraint` kinds, specifies if the config should match Generated (
i.e. fake) resources, Original resources, or both. The `source` field is
an `enum` which accepts the following values:

- `Generated` – the config will only apply to expanded resources, **and will not
  apply to any real resources on the cluster**
- `Original` – the config will only apply to Original resources, and will not
  affect expanded resources
- `All` – the config will apply to both `Generated` and `Original` resources.
  This is the default value.

For example, suppose a cluster's `ReplicaSet` controller adds a default value
for `fooField` when creating Pods that cannot reasonably be added to the
`ReplicaSet`'s `spec.template`. If a constraint relies on these default values,
a user could create a Mutation custom resource that modifies expanded resources,
like so:

```yaml
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: assign-foo-field
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  location: "spec.containers[name: *].fooField"
  parameters:
    assign:
      value: "Bar"
  match:
    source: "Generated"
    scope: Cluster
    kinds:
      - apiGroups: []
        kinds: []
```

Similarly, `Constraints` can be configured to only target fake resources by
setting the `Constraint`'s `spec.match.source` field to `Generated`. This can
also be used to define different enforcement actions for expanded resources and
original resources.

For example, suppose a cluster has a policy that blocks all [standalone pods](https://kubernetes.io/docs/concepts/configuration/overview/#naked-pods-vs-replicasets-deployments-and-jobs), but allows them to be created as part of a workload resource, such as `Deployment`. A user could create a `Constraint` that only targets original resources, like so:

```yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: block-standalone-pods
metadata:
  name: block-standalone-pods
spec:
  match:
    source: Original
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
```

## Mutating Example

Suppose a cluster is using Istio, and has a policy configured to ensure
specified Pods have an Istio sidecar. To validate Deployments that would create
Pods which Istio will inject a sidecar into, we need to use mutators to mimic
the sidecar injection.

What follows is an example of:

- an  `ExpansionTemplate` configured to expand `Deployments` into `Pods`
- an `Assign` mutator to add the Istio sidecar container to `Pods`
- a `ModifySet` mutator to add the `proxy` and `sidecar` args
- an inbound `Deployment`, and the expanded `Pod`

**Note that the Mutators set the `source: Generated` field, which will cause
them to only be applied when expanding resources specified
by `ExpansionTemplates`. These Mutators will not affect any real resources on
the cluster.**

```
/* Detailed source-code truncated for AI context efficiency. */
```

When expanded, the above configs will produce the following `Pod`:

```yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: nginx
spec:
  containers:
  - args:
    - /bin/sh
    image: nginx:1.14.2
    name: nginx
    ports:
    - containerPort: 80
  - args:
    - proxy
    - sidecar
    image: docker.io/istio/proxyv2:1.15.0
    imagePullPolicy: IfNotPresent
    name: istio-proxy
    ports:
    - containerPort: 15090
      name: http-envoy-prom
      protocol: TCP
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
```

---

### Export Driver Walkthrough (`website/docs/export-driver-walkthrough.md`)

---
id: export-driver
title: Export Interface/Driver walkthrough
---

This guide provides an overview of the driver interface, including details of its structure and functionality. Additionally, it offers instructions on adding a new driver and utilizing different backends to export audit violations.

## Driver interface

```go
type Driver interface {
	// Publish publishes single message with specific subject using a connection
	Publish(ctx context.Context, connectionName string, data interface{}, subject string) error

	// CloseConnection closes a connection
	CloseConnection(connectionName string) error

	// UpdateConnection updates an existing connection
	UpdateConnection(ctx context.Context, connectionName string, config interface{}) error

	// CreateConnection creates new connection
	CreateConnection(ctx context.Context, connectionName string, config interface{}) error
}
```

As an example, the Dapr driver implements these methods to publish message and manage connection to do so. Please refer to [dapr.go](https://github.com/open-policy-agent/gatekeeper/blob/master/pkg/export/dapr/dapr.go) to understand the logic that goes in each of these methods.

### How to add new driver to export audit violations to foo backend

A driver must maintain a map of open connections associated with backend `foo`.

```go
type Connection struct {
	// properties needed for individual connection
}

type Foo struct {
	openConnections map[string]Connection
}

const (
	Name = "foo"
)

var Connections = &Foo{
	openConnections: make(map[string]Connection),
}

```

A driver must implement the `Driver` interface.

```go
func (r *Foo) Publish(ctx context.Context, connectionName string, data interface{}, subject string) error {
  ...
}

func (r *Foo) CloseConnection(connectionName string) error {
  ...
}

func (r *Foo) UpdateConnection(ctx context.Context, connectionName string, config interface{}) error {
  ...
}

func (r *Foo) CreateConnection(ctx context.Context, connectionName string, config interface{}) error {
  ...
}
```

This newly added driver's `Connections` exported variable must be added to the map of `supportedDrivers` in [system.go](https://github.com/open-policy-agent/gatekeeper/blob/master/pkg/export/system.go). For example,

```go
var supportedDrivers = map[string]driver.Driver{
	dapr.Name: dapr.Connections,
  foo.Name: foo.Connections,
}
```

And thats it! Exporter system will take the newly added driver into account and a `Connection` custom resource to establish connection to export message is created.

### How to establish connections to different backend

To enable audit to use this driver to publish messages, a `Connection` custom resource with appropriate `config` and `driver` is needed. For example,

```yaml
apiVersion: connection.gatekeeper.sh/v1alpha1
kind: Connection
metadata:
  name: audit-connection
  namespace: gatekeeper-system
spec:
  driver: "foo"
  config:
    key: value
```

> The `spec.driver` field must exist and must match one of the keys of the `supportedDrivers` map that was defined earlier to use the corresponding driver. The `spec.config` field in the configuration can vary depending on the driver being used. For dapr driver, `spec.config` must be `component: "pubsub"`.

---

### Export (`website/docs/export.md`)

---
id: export
title: Exporting violations
---

`Feature State`: Audit export in Gatekeeper version v3.13+; admission export in v3.24+ (alpha)

> ❗ This feature is alpha, subject to change (feedback is welcome!). This feature was previously known as "Consuming violations using Pubsub".

## Description

This feature exports audit violations, and optionally admission violations, to a backend from where users can consume violations.

> To gain insights into different methods of obtaining audit violations and the respective trade-offs for each approach, please refer to [Reading Audit Results](audit.md#reading-audit-results).

## Enabling Gatekeeper to export audit violations

Install prerequisites such as a pubsub tool, a message broker etc.

### Setting up audit to export violations

In the audit deployment, set the `--enable-violation-export` flag to `true` to export audit violations. Additionally, use `--audit-connection` (defaults to `audit-connection`) and `--audit-channel`(defaults to `audit-channel`) flags to allow audit to export violations using desired connection onto desired channel. `--audit-connection` must be set to the name of the connection config, and `--audit-channel` must be set to name of the channel where violations should get published.

A `Connection` custom resource with `spec` that contains `driver` and `config` fields are required to establish connection for sending violations over the channel. Following is an example to establish a connection that uses Dapr to export messages:

```yaml
apiVersion: connection.gatekeeper.sh/v1alpha1
kind: Connection
metadata:
  name: audit-connection
  namespace: gatekeeper-system
spec:
  driver: "disk"
  config:
    path: "tmp/violations/topics"
    maxAuditResults: 3
```
- `driver` field determines which tool/driver should be used to establish a connection. Valid values are: `dapr`, `disk`
- `config` field is an object that configures how the connection is made. E.g. which queue messages should be sent to.

#### Available drivers

- Dapr: Export violations using pubsub model provided with [Dapr](https://dapr.io/)
- Disk: Export violations to file system.

#### Status
Upon controller ingestion, the `Connection` will reflect the state of the export connection on its `status` sub resource.

```yaml
apiVersion: connection.gatekeeper.sh/v1alpha1
kind: Connection
metadata:
  name: audit-connection
  namespace: gatekeeper-system
spec:
  driver: "dapr"
  config:
    component: "pubsub"
status:
  byPod:
  - id: "pod-id"
    connectionUID: "connection-id"
    connectionErrors:
    - type: UpsertConnection
      message: "Error message"
    publishStatuses:
    - source: audit
      active: true
      lastAttemptTime: "2026-07-28T12:00:00Z"
      lastSuccessTime: "2026-07-28T12:00:00Z"
      errors: []
    - source: webhook
      active: false
      lastAttemptTime: "2026-07-28T12:00:05Z"
      errors:
      - type: Publish
        message: "Error message"
```

The following table describes each property in the `status.byPod` section:

| Property | Type | Description |
|----------|------|-------------|
| `id` | string | Unique identifier for the pod handling the connection |
| `connectionUID` | string | Unique identifier for the specific connection instance |
| `connectionErrors` | array | Errors from creating or updating the Connection, limited to 500 entries |
| `connectionErrors[].type` | string | Type of Connection error encountered, such as `UpsertConnection` |
| `connectionErrors[].message` | string | Human-readable description of the Connection error |
| `publishStatuses` | array | Publishing health grouped by source so one producer cannot clear another producer's state |
| `publishStatuses[].source` | string | Publisher that owns the entry: `audit` or `webhook` |
| `publishStatuses[].active` | boolean | Whether the source completed at least one publish in its latest reporting window |
| `publishStatuses[].lastAttemptTime` | timestamp | Most recent publish attempt represented by this entry |
| `publishStatuses[].lastSuccessTime` | timestamp | Most recent successful publish by this source |
| `publishStatuses[].errors` | array | Publish error classes reported by this source, limited to 500 entries |

Each publisher replaces only the entry it owns. Audit updates `source: audit`, while admission violation export from the validation webhook updates `source: webhook`; either update preserves the other entry. If a source observes more than 500 distinct error classes before a successful status update, the final entry reports that additional classes were omitted. Each stored error message is the coalesced class text before the first colon and is not otherwise length-truncated.

## Enabling Gatekeeper to export admission violations

Admission violation export is independent from audit export and is disabled by default. Set `--enable-admission-violation-export=true` on the controller-manager deployment to enable it. Enabling `--enable-violation-export` on the audit deployment does not enable admission export.

Admission export uses these routing flags:

- `--audit-connection`: Connection resource name shared by audit and admission export. Defaults to `audit-connection`.
- `--audit-channel`: Channel shared by audit and admission export. Defaults to `audit-channel`.

The equivalent Helm configuration is:

```yaml
enableAdmissionViolationExport: true
exportBackend: disk
```

Admission violation export currently supports only the disk driver. The Helm chart rejects `enableAdmissionViolationExport: true` unless `exportBackend: disk`; the Dapr driver is not supported for admission export. The supported configuration routes audit and admission export through the same `Connection`, channel, path, and volume. Admission segment retention and other spool limits are fixed internal defaults while the feature is alpha; `maxAuditResults` continues to apply only to audit results. Additional admission-specific configuration can be added later if operational feedback requires it.

The chart mounts `audit.exportVolume` at `audit.exportVolumeMount.path` in every controller-manager pod when admission export is enabled. The reader sidecar is disabled by default; configure a production reader or explicitly enable the demonstration reader with `admission.disableExportSidecar: false`. Each pod writes its own spool, so multiple webhook replicas and separate audit/webhook deployments do not contend for one file.

```yaml
enableAdmissionViolationExport: true
exportBackend: disk
audit:
  connection: audit-connection
  channel: audit-channel
  exportConnection:
    path: tmp/violations/topics
    maxAuditResults: 3
admission:
  disableExportSidecar: true
```

Admission disk files use newline-delimited JSON. Audit and admission files can share the same channel directory because their names are distinct: audit uses `<audit-run-id>.log`, while admission uses `admission-<timestamp>-<random>.log`. A writer creates a uniquely named, locked admission `.open` segment. Reaching the fixed byte, record, or age limit flushes and closes the segment, then atomically renames it to `.log`. The demonstration reader selects only the `admission-` prefix in admission mode, so it cannot delete audit run files.

Cleanup removes only completed, unlocked `admission-` segments and enforces fixed file count, total bytes, and TTL limits. Audit cleanup explicitly ignores that prefix. Startup recovery ignores files locked by another live writer, truncates an abandoned `.open` file to its final complete JSONL record, and publishes it as a recovered `.log`. A periodic janitor starts only when recovery finds admission files or the first admission record is written, and stops after all admission artifacts are gone. The driver also reserves filesystem headroom and rejects new records before exhausting the filesystem.

Each retention-cleanup invocation removes at most 256 ready segments. Recovery may also remove abandoned empty `.open` files and `.deleting` remnants before retention runs. New disk Connections are rejected while 32 failed cleanup states are retained. Failures from Connections that were already open can temporarily take the retry map above that threshold because descriptor-owning state cannot be safely discarded.

The default chart uses per-pod `emptyDir` volumes. Unconsumed files are lost when that pod is deleted. For durable custom storage, use a separate directory or volume per pod; do not point multiple pods at the same shared directory because Connection removal owns and cleans its configured path.

Admission export messages use `eventType: violation_admission`. They include the evaluation timestamp, admission `operation` (`CREATE`, `UPDATE`, `DELETE`, or `CONNECT`), API resource and subresource, dry-run state, and requesting user's name, UID, and groups. They can describe denied requests that were never persisted in Kubernetes and include policy-provided details, resource labels, and constraint annotations. Treat the destination as security-sensitive; identity fields and policy or resource data may contain user-controlled or sensitive data.

### Default queue and disk limits

Admission export limits are fixed while the feature is alpha and apply independently to each controller-manager pod:

| Layer | Limit | Default |
|---|---|---:|
| In-memory queue | Messages being constructed or waiting to publish | 1,024 |
| In-memory queue | Total encoded bytes waiting to publish | 16 MiB |
| Publisher | Maximum records in one ready batch | 64 |
| Record | Complete encoded JSON record | 64 KiB |
| Disk segment | Maximum bytes | 1 MiB |
| Disk segment | Maximum records | 1,000 |
| Disk segment | Maximum age before rotation | 1 minute |
| Disk spool | Completed segments | 20 |
| Disk spool | Total bytes, including the open segment and pending record | 20 MiB |
| Disk spool | Maximum completed-segment age | 24 hours |
| Filesystem | Free-space reserve | 16 MiB |

The 64 KiB record limit applies to the entire JSON object after encoding, not only to the violation message. JSON field names and escaping, policy-provided details, constraint annotations, resource labels, and request identity all count toward the limit. KiB measures bytes, so the number of characters that fit varies with UTF-8 and JSON escaping. The limit leaves room for normal policy and request metadata while preventing one user-influenced result from consuming a disproportionate share of the queue and disk spool. The `kubectl.kubernetes.io/last-applied-configuration` constraint annotation is omitted, but other annotations still count. An oversized record is dropped before enqueue and reported with drop reason `message_too_large`.

Segment rotation occurs when any byte, record-count, or age limit is reached. The spool limits bound unconsumed backlog; they do not guarantee that records remain available for 24 hours. Cleanup removes the oldest completed segments until the count, byte, and age limits all hold, so count or byte pressure can remove a segment long before its maximum age. When one-minute age rotation is the limiting factor, 20 completed segments provide roughly 20 minutes of backlog; higher volume can rotate segments sooner. A reader must therefore drain segments fast enough for the workload.

The demonstration admission reader logs each record and deletes its completed segment after a successful read. It demonstrates consumption and is not a retention archive. Retain exported records in the downstream system when longer history is required.

### Delivery behavior

Admission export is best-effort. Backend publishing does not delay or change the admission response:

- Each controller-manager pod has an asynchronous queue limited to 1,024 messages, including records being constructed, and 16 MiB of encoded data.
- A complete encoded JSON record is limited to 64 KiB.
- The webhook reserves count capacity before constructing a record. The publisher drains up to 64 records that are already queued without waiting to fill a batch.
- Messages are dropped when encoding fails or an enqueue limit is reached. A failed publish is not retried.
- During graceful termination, messages still in the queue are drained for up to five seconds. Messages still queued after that deadline are dropped and reported with the `shutdown` reason.
- A batch already removed from the queue when termination begins is not requeued. Gatekeeper stops waiting when its publish context is canceled; a backend call that ignores cancellation may finish later, but its result is not used and the process may exit first.
- `SIGKILL`, OOM termination, and node failure do not run the drain. Queued and in-flight records are then lost. Complete disk records already written and synced can be recovered only if the volume survives; the default `emptyDir` survives a container restart but not pod deletion or replacement.
- Repeated drop and publish-error logs are limited to one per minute for each class; use the admission export metrics to detect sustained loss.
- Webhook publish status is reported outside the queue publisher. Errors and health transitions are checked every 10 seconds, while unchanged healthy traffic is coalesced to a one-minute heartbeat. Audit updates only the `audit` entry at the end of each run.
- A source with no new publish attempts leaves its previous entry unchanged. A later successful reporting window clears only that source's errors; use `lastAttemptTime` and `lastSuccessTime` to evaluate freshness.

### Quick start with exporting admission violations to disk

This quick start enables the demonstration admission reader. It logs completed admission records and deletes each segment after reading it, so use it only to verify the feature.

1. Install or upgrade Gatekeeper with admission export, the disk backend, and the demonstration reader enabled:

    ```shell
    helm upgrade --install gatekeeper gatekeeper/gatekeeper \
      --namespace gatekeeper-system \
      --create-namespace \
      --set enableAdmissionViolationExport=true \
      --set exportBackend=disk \
      --set admission.disableExportSidecar=false \
      --set audit.connection=audit-connection \
      --set audit.channel=audit-channel

    kubectl rollout status deployment/gatekeeper-controller-manager \
      --namespace gatekeeper-system \
      --timeout=2m
    ```

2. Install a test policy that requires the `test` label on Pods in the `nginx` namespace:

    ```shell
    export GATEKEEPER_EXPORT_EXAMPLES=https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/test/export

    kubectl create namespace nginx --dry-run=client --output yaml | kubectl apply -f -
    kubectl apply -f "${GATEKEEPER_EXPORT_EXAMPLES}/k8srequiredlabels_ct.yaml"
    until kubectl get crd k8srequiredlabels.constraints.gatekeeper.sh >/dev/null 2>&1; do sleep 1; done
    kubectl apply -f "${GATEKEEPER_EXPORT_EXAMPLES}/pod_must_have_test.yaml"
    until kubectl get k8srequiredlabels pod-must-have-test \
      -o jsonpath='{.status.byPod[*].operations[*]}' 2>/dev/null | grep -qw webhook; do sleep 1; done
    ```

3. Submit a Pod that violates the policy. The command is expected to fail with a denial:

    ```shell
    kubectl apply -f - <<'EOF'
    apiVersion: v1
    kind: Pod
    metadata:
      name: denied-export-pod
      namespace: nginx
      labels:
        app: denied-export
    spec:
      containers:
      - name: nginx
        image: nginx:latest
    EOF
    ```

4. Confirm that a controller-manager reader observed the admission record:

    ```shell
    kubectl logs --namespace gatekeeper-system \
      --selector control-plane=controller-manager \
      --container admission-reader \
      --since=5m | grep '"eventType":"violation_admission"' | grep '"resourceName":"denied-export-pod"'
    ```

    The webhook publisher also reports health under `source: webhook`:

    ```shell
    kubectl get connection audit-connection \
      --namespace gatekeeper-system \
      --output yaml
    ```

### Quick start with exporting audit violations using Dapr and Redis

#### Prerequisites for Dapr

1. Install Dapr

   To install Dapr with specific requirements and configuration, please refer to [Dapr docs](https://docs.dapr.io/operations/hosting/kubernetes/kubernetes-deploy/).

  :::important
    - Make sure to set `SIDECAR_DROP_ALL_CAPABILITIES` environment variable on `dapr-sidecar` injector pod to `true` to avoid getting `PodSecurity violation` errors for the injected sidecar container as Gatekeeper by default requires workloads to run with [restricted](https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted) policy. If using helm charts to install Dapr, you can use `--set dapr_sidecar_injector.sidecarDropALLCapabilities=true`.
    - Additionally, [configure appropriate seccompProfile for sidecar containers](https://docs.dapr.io/operations/hosting/kubernetes/kubernetes-production/#configure-seccompprofile-for-sidecar-containers) injected by Dapr to avoid getting `PodSecurity violation` errors. We are setting required Dapr annotation for audit pod while deploying Gatekeeper later in this quick start to avoid getting `PodSecurity violation` error.
  :::

    > Dapr is installed with mtls enabled by default, for more details on the same please refer to [Dapr security](https://docs.dapr.io/operations/security/mtls/#setting-up-mtls-with-the-configuration-resource).

2. Install Redis

    Please refer to [this](https://docs.dapr.io/getting-started/tutorials/configure-state-pubsub/#step-1-create-a-redis-store) guide to install Redis.

    > Redis is used for example purposes only. Dapr supports [many different state store options](https://docs.dapr.io/reference/components-reference/supported-state-stores/). To install Redis with TLS, please refer to [this](https://docs.bitnami.com/kubernetes/infrastructure/redis-cluster/administration/enable-tls/) doc.

#### Configure a sample subscriber to receive violations

1. Create `fake-subscriber` namespace and redis secret

    ```shell
    kubectl create ns fake-subscriber
    # creating redis secret in subscriber namespace to allow Dapr sidecar to connect to redis instance
    kubectl get secret redis --namespace=default -o yaml | sed 's/namespace: .*/namespace: fake-subscriber/' | kubectl apply -f -
    ```

2. Create Dapr pubsub component

    ```shell
    kubectl apply -f - <<EOF
    apiVersion: dapr.io/v1alpha1
    kind: Component
    metadata:
      name: pubsub
      namespace: fake-subscriber
    spec:
      type: pubsub.redis
      version: v1
      metadata:
      - name: redisHost
        value: redis-master.default.svc.cluster.local:6379
      - name: redisPassword
        secretKeyRef: 
          name: redis
          key: redis-password
    EOF
    ```

    > Please use [this guide](https://docs.dapr.io/reference/components-reference/supported-state-stores/setup-redis/) to properly configure Redis pubsub component for Dapr.

3. Deploy subscriber application

    ```yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sub
      namespace: fake-subscriber
      labels:
        app: sub
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sub
      template:
        metadata:
          labels:
            app: sub
          annotations:
            dapr.io/enabled: "true"
            dapr.io/app-id: "subscriber"
            dapr.io/enable-api-logging: "true"
            dapr.io/app-port: "6002"
        spec:
          containers:
          - name: go-sub
            image: ghcr.io/open-policy-agent/fake-subscriber:latest
            imagePullPolicy: Always
    ```

    :::important
    The `fake-subscriber` image is published as part of each Gatekeeper release at `ghcr.io/open-policy-agent/fake-subscriber`. To build a custom version locally, use the Dockerfile at [gatekeeper/test/export/fake-subscriber](https://github.com/open-policy-agent/gatekeeper/tree/master/test/export/fake-subscriber).
    :::

#### Configure Gatekeeper with Export enabled with Dapr

1. Create Gatekeeper namespace, and create Dapr pubsub component and Redis secret in Gatekeeper's namespace (`gatekeeper-system` by default). Please make sure to update `gatekeeper-system` namespace for the next steps if your cluster's Gatekeeper namespace is different.

    ```shell
    kubectl create namespace gatekeeper-system
    kubectl get secret redis --namespace=default -o yaml | sed 's/namespace: .*/namespace: gatekeeper-system/' | kubectl apply -f -
    kubectl apply -f - <<EOF
    apiVersion: dapr.io/v1alpha1
    kind: Component
    metadata:
      name: pubsub
      namespace: gatekeeper-system
    spec:
      type: pubsub.redis
      version: v1
      metadata:
      - name: redisHost
        value: redis-master.default.svc.cluster.local:6379
      - name: redisPassword
        secretKeyRef:
          name: redis
          key: redis-password
    EOF
    ```

2. To upgrade or install Gatekeeper with `--enable-violation-export` set to `true`, `--audit-connection` set to `audit-connection`, `--audit-channel` set to `audit-channel` on audit pod.

    ```shell
    # auditPodAnnotations is used to add annotations required by Dapr to inject sidecar to audit pod
    echo 'auditPodAnnotations: {dapr.io/enabled: "true", dapr.io/app-id: "audit", dapr.io/metrics-port: "9999", dapr.io/sidecar-seccomp-profile-type: "RuntimeDefault"}' > /tmp/annotations.yaml
    helm upgrade --install gatekeeper gatekeeper/gatekeeper --namespace gatekeeper-system \
    --set enableViolationExport=true \
    --set audit.connection=audit-connection \
    --set audit.channel=audit-channel \
    --values /tmp/annotations.yaml
    ```

    **Note:** Verify that after the audit pod is running there is a Dapr sidecar injected and running along side `manager` container.

3. Create connection config to establish a connection.

    ```shell
    kubectl apply -f - <<EOF
    apiVersion: connection.gatekeeper.sh/v1alpha1
    kind: Connection
    metadata:
      name: audit-connection
      namespace: gatekeeper-system
    spec:
      driver: "dapr"
      config:
        component: "pubsub"
    EOF
    ```

    **Note:** Name of the `Connection` custom resource must match the value of `--audit-connection` for it to be used by audit to export violation. At the moment, only one connection can exist for audit.

4. Create the constraint templates and constraints, and make sure audit ran by checking constraints. If constraint status is updated with information such as `auditTimeStamp` or `totalViolations`, then audit has ran at least once. Additionally, populated `TOTAL-VIOLATIONS` field for all constraints while listing constraints also indicates that audit has ran at least once.

    ```log
    kubectl get constraint
    NAME                 ENFORCEMENT-ACTION   TOTAL-VIOLATIONS
    pod-must-have-test                        0
    ```

5. Finally, check the subscriber logs to see the violations received.

    ```log
    kubectl logs -l app=sub -c go-sub -n fake-subscriber 
    2023/07/18 20:16:41 Listening...
    2023/07/18 20:37:20 main.ExportMsg{ID:"2023-07-18T20:37:19Z", Details:map[string]interface {}{"missing_labels":[]interface {}{"test"}}, EventType:"violation_audited", Group:"constraints.gatekeeper.sh", Version:"v1beta1", Kind:"K8sRequiredLabels", Name:"pod-must-have-test", Namespace:"", Message:"you must provide labels: {\"test\"}", EnforcementAction:"deny", ConstraintAnnotations:map[string]string(nil), ResourceGroup:"", ResourceAPIVersion:"v1", ResourceKind:"Pod", ResourceNamespace:"nginx", ResourceName:"nginx-deployment-58899467f5-j85bs", ResourceLabels:map[string]string{"app":"nginx", "owner":"admin", "pod-template-hash":"58899467f5"}}
    ```

### Quick start with exporting violations on node storage using Disk driver via emptyDir

#### Configure Gatekeeper with Export enabled to Disk

1. Deploy Gatekeeper with disk export configurations.

    Below are the default configurations that enable disk export and add a sidecar container to the Gatekeeper audit pod:

    ```yaml
    audit: 
      exportVolume: 
        name: tmp-violations 
        emptyDir: {} 
      exportVolumeMount: 
        path: /tmp/violations 
      exportSidecar: 
        name: reader
        image: ghcr.io/open-policy-agent/fake-reader:latest
        imagePullPolicy: Always 
        securityContext: 
          allowPrivilegeEscalation: false 
          capabilities: 
            drop: 
            - ALL 
          readOnlyRootFilesystem: true 
          runAsGroup: 999 
          runAsNonRoot: true 
          runAsUser: 1000 
          seccompProfile: 
            type: RuntimeDefault 
        volumeMounts: 
        - mountPath: /tmp/violations 
          name: tmp-violations
    ```

    :::warning
    The reader sidecar image `ghcr.io/open-policy-agent/fake-reader` is published as part of each Gatekeeper release and is intended for demonstration and quickstart purposes only. It is not recommended for production environments. For production use, it is advised to create and configure a custom sidecar image tailored to your specific requirements.
    :::

    ```shell
    helm upgrade --install gatekeeper gatekeeper/gatekeeper --namespace gatekeeper-system \
    --set enableViolationExport=true \
    --set audit.connection=audit-connection \
    --set audit.channel=audit-channel \
    --set audit.exportConnection.path=tmp/violations/topics \
    --set audit.exportConnection.maxAuditResults=3 \
    --set exportBackend=disk \
    ```
    
    As part of the command above, the `Connection` resource is installed with the following values and defaults:

    ```yaml
    apiVersion: connection.gatekeeper.sh/v1alpha1
    kind: Connection
    metadata:
      name: "audit-connection"
      namespace: "gatekeeper-system"
    spec:
      driver: "disk"
      config:
        path: "tmp/violations/topics"
        maxAuditResults: 3
    ```

    | Property        | Description                                                                                                                                                            | Default                  |
    |:----------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |:-------------------------|
    | path            | (alpha) Path for audit pod manager container to export violations and sidecar container to read from. Must be a child of volume mount path so the parent is writable.  | "tmp/violations/topics" |
    | maxAuditResults | (alpha) Maximum number of audit results that can be stored in the export path.                                                      | 3                 |
    | closedConnectionTTL | (alpha) Optional duration string controlling how long a failed closed Connection remains eligible for cleanup retries. Accepted values are `"1m"` through `"10m"`. The chart leaves it unset and the driver defaults to `"10m"`. | `"10m"` |

    **Note**: After the audit pod starts, verify that it contains two running containers.

    ```shell
    kubectl get pod -n gatekeeper-system 
    NAME                                             READY   STATUS    RESTARTS        AGE
    gatekeeper-audit-6865f5f56d-vclxw                2/2     Running   0               12s
    ```

    :::tip
    The command above deploys the audit pod with a default sidecar reader and volume. To customize the sidecar reader or volume according to your requirements, you can set the following variables in your values.yaml file:

    ```yaml
    audit: 
      exportVolume: 
        <your-volume>
      exportVolumeMount: 
        path: <volume-mount-path>
      exportSidecar: 
        <your-side-car>
    ```
    :::

2. Create the constraint templates and constraints, and make sure audit ran by checking constraints. If constraint status is updated with information such as `auditTimeStamp` or `totalViolations`, then audit has ran at least once. Additionally, populated `TOTAL-VIOLATIONS` field for all constraints while listing constraints also indicates that audit has ran at least once.

    ```log
    kubectl get constraint
    NAME                 ENFORCEMENT-ACTION   TOTAL-VIOLATIONS
    pod-must-have-test                        0
    ```

3. Finally, check the sidecar reader logs to see the violations written.

    ```log
    kubectl logs -l gatekeeper.sh/operation=audit -c go-sub -n gatekeeper-system 
    2025/03/05 00:37:16 {"id":"2025-03-05T00:37:13Z","details":{"missing_labels":["test"]},"eventType":"violation_audited","group":"constraints.gatekeeper.sh","version":"v1beta1","kind":"K8sRequiredLabels","name":"pod-must-have-test","message":"you must provide labels: {\"test\"}","enforcementAction":"deny","resourceAPIVersion":"v1","resourceKind":"Pod","resourceNamespace":"nginx","resourceName":"nginx-deployment-2-79479fc6db-7qbnm","resourceLabels":{"app":"nginx-ingress","app.kubernetes.io/component":"controller","pod-template-hash":"79479fc6db"}}
    ```

### Violations

The audit pod exports violations in following format:

```json
{
  "id": "2023-07-18T21:21:52Z",
  "details": {
    "missing_labels": [
      "test"
    ]
  },
  "eventType": "violation_audited",
  "group": "constraints.gatekeeper.sh",
  "version": "v1beta1",
  "kind": "K8sRequiredLabels",
  "name": "pod-must-have-test",
  "message": "you must provide labels: {\"test\"}",
  "enforcementAction": "deny",
  "resourceAPIVersion": "v1",
  "resourceKind": "Pod",
  "resourceNamespace": "nginx",
  "resourceName": "nginx-deployment-cd55c47f5-2b84x",
  "resourceLabels": {
    "app": "nginx",
    "pod-template-hash": "cd55c47f5"
  }
}
```

---

### Externaldata (`website/docs/externaldata.md`)

---
id: externaldata
title: External Data
---

`Feature State`: Gatekeeper version v3.11+ (beta)

## Motivation

Gatekeeper provides various means to mutate and validate Kubernetes resources. However, in many of these scenarios this data is either built-in, static or user defined. With external data feature, we are enabling Gatekeeper to interface with various external data sources, such as image registries, using a provider-based model.

A similar way to connect with an external data source can be done today using OPA's built-in `http.send` functionality. However, there are limitations to this approach.
- Gatekeeper does not support Rego policies for mutation, which cannot use the OPA `http.send` built-in function.
- Security concerns due to:
  - if template authors are not trusted, it will potentially give template authors access to the in-cluster network.
  - if template authors are trusted, authors will need to be careful on how rego is written to avoid injection attacks.

Key benefits provided by the external data solution:
- Addresses security concerns by:
  - Restricting which hosts a user can access.
  - Providing an interface for making requests, which allows Gatekeeper to better handle things like escaping strings.
- Addresses common patterns with a single provider, e.g. image tag-to-digest mutation, which can be leveraged by multiple scenarios (e.g. validating image signatures or vulnerabilities).
- Provider model creates a common interface for extending Gatekeeper with external data.
  - It allows for separation of concerns between the implementation that allows access to external data and the actual policy being evaluated.
  - Developers and consumers of data sources can rely on that common protocol to ease authoring of both constraint templates and data sources.
  - Makes change management easier as users of an external data provider should be able to tell whether upgrading it will break existing constraint templates. (once external data API is stable, our goal is to have that answer always be "no")
- Performance benefits as Gatekeeper can now directly control caching and which values are significant for caching, which increases the likelihood of cache hits.
  - For mutation, we can batch requests via lazy evaluation.
  - For validation, we make batching easier via [`external_data`](#external-data-for-Gatekeeper-validating-webhook) Rego function design.



## Providers

Providers are designed to be in-cluster components that can communicate with external data sources (such as image registries, Active Directory/LDAP directories, etc) and return data in a format that can be processed by Gatekeeper.

Example provider _template_ can be found at: https://github.com/open-policy-agent/gatekeeper-external-data-provider

### Providers maintained by the community

If you have built an external data provider and would like to add it to this list, please submit a PR to update this page.

If you have any issues with a specific provider, please open an issue in the applicable provider's repository.

The following external data providers are maintained by the community:

- [ratify](https://github.com/deislabs/ratify)
- [cosign-gatekeeper-provider](https://github.com/sigstore/cosign-gatekeeper-provider)
- [GitHub artifact attestations OPA provider](https://github.com/github/artifact-attestations-opa-provider)
- [JFrog verify evidence OPA provider](https://github.com/jfrog/jfrog-opa-policy)


### Sample providers

The following external data providers are samples and are not supported/maintained by the community:

- [trivy-provider](https://github.com/sozercan/trivy-provider)
- [tag-to-digest-provider](https://github.com/sozercan/tagToDigest-provider)
- [aad-provider](https://github.com/sozercan/aad-provider)
- [kubernetes-api-provider](https://github.com/nilekhc/k8s-gatekeeper-external-data-provider)

### API (v1beta1)

#### `Provider`

Provider resource defines the provider and the configuration for it.

```yaml
apiVersion: externaldata.gatekeeper.sh/v1beta1
kind: Provider
metadata:
  name: my-provider
spec:
  url: https://<service-name>.<namespace>:<port>/<endpoint> # URL to the external data source (e.g., https://my-provider.my-namespace:8090/validate)
  timeout: <timeout> # timeout value in seconds (e.g., 1). this is the timeout on the Provider custom resource, not the provider implementation.
  caBundle: <caBundle> # CA bundle to use for TLS verification.
```

When used by the mutating webhook, the effective external data request timeout is the smaller of:
- the remaining admission webhook request deadline
- the provider `spec.timeout` (or Gatekeeper's default timeout when unset)

For example, if the webhook has 1s remaining and `spec.timeout` is 10s, the provider request is capped at ~1s.

#### `ProviderRequest`

`ProviderRequest` is the API request that is sent to the external data provider.

```go
// ProviderRequest is the API request for the external data provider.
type ProviderRequest struct {
	// APIVersion is the API version of the external data provider.
	APIVersion string `json:"apiVersion,omitempty"`
	// Kind is kind of the external data provider API call. This can be "ProviderRequest" or "ProviderResponse".
	Kind ProviderKind `json:"kind,omitempty"`
	// Request contains the request for the external data provider.
	Request Request `json:"request,omitempty"`
}

// Request is the struct that contains the keys to query.
type Request struct {
	// Keys is the list of keys to send to the external data provider.
	Keys []string `json:"keys,omitempty"`
}
```

#### `ProviderResponse`

`ProviderResponse` is the API response that a provider must return.

```go
// ProviderResponse is the API response from a provider.
type ProviderResponse struct {
	// APIVersion is the API version of the external data provider.
	APIVersion string `json:"apiVersion,omitempty"`
	// Kind is kind of the external data provider API call. This can be "ProviderRequest" or "ProviderResponse".
	Kind ProviderKind `json:"kind,omitempty"`
	// Response contains the response from the provider.
	Response Response `json:"response,omitempty"`
}

// Response is the struct that holds the response from a provider.
type Response struct {
	// Idempotent indicates that the responses from the provider are idempotent.
	// Applies to mutation only and must be true for mutation.
	Idempotent bool `json:"idempotent,omitempty"`
	// Items contains the key, value and error from the provider.
	Items []Item `json:"items,omitempty"`
	// SystemError is the system error of the response.
	SystemError string `json:"systemError,omitempty"`
}

// Items is the struct that contains the key, value or error from a provider response.
type Item struct {
	// Key is the request from the provider.
	Key string `json:"key,omitempty"`
	// Value is the response from the provider.
	Value interface{} `json:"value,omitempty"`
	// Error is the error from the provider.
	Error string `json:"error,omitempty"`
}
```

### Implementation

Provider is an HTTP server that listens on a port and responds to [`ProviderRequest`](#providerrequest) with [`ProviderResponse`](#providerresponse).

As part of [`ProviderResponse`](#providerresponse), the provider can return a list of items. Each item is a JSON object with the following fields:
- `Key`: the key that was sent to the provider
- `Value`: the value that was returned from the provider for that key
- `Error`: an error message if the provider returned an error for that key

If there is a system error, the provider should return the system error message in the `SystemError` field.

> 📎 Recommendation is for provider implementations to keep a timeout such as maximum of 1-2 seconds for the provider to respond.

Example provider implementation: https://github.com/open-policy-agent/gatekeeper/blob/master/test/externaldata/dummy-provider/provider.go

#### Provider Response Caching
Starting with v3.13+, Gatekeeper supports caching of responses from external data providers for audit and the validating webhook. Mutation provider responses are also cached when external data is used by mutation. Gatekeeper caches the response based on the `Key` and `Value` received as part of the [`ProviderResponse`](#providerresponse). By default, the cache is invalidated after 3 minutes, which is the default Time-to-Live (TTL). You can configure the TTL using the `--external-data-provider-response-cache-ttl` flag. Setting the flag to 0 disables this cache.

## External data for Gatekeeper validating webhook

External data adds a [custom OPA built-in function](https://www.openpolicyagent.org/docs/latest/extensions/#custom-built-in-functions-in-go) called `external_data` to Rego. This function is used to query external data providers.

`external_data` is a function that takes a request and returns a response. The request is a JSON object with the following fields:
- `provider`: the name of the provider to query
- `keys`: the list of keys to send to the provider

e.g.,
```rego
  # build a list of keys containing images for batching
  my_list := [img | img = input.review.object.spec.template.spec.containers[_].image]

  # send external data request
  response := external_data({"provider": "my-provider", "keys": my_list})
```

Response example: [[`"my-key"`, `"my-value"`, `""`], [`"another-key"`, `42`, `""`], [`"bad-key"`, `""`, `"error message"`]]

> 📎 To avoid multiple calls to the same provider, recommendation is to batch the keys list to send a single request.

Example template:
https://github.com/open-policy-agent/gatekeeper/blob/master/test/externaldata/dummy-provider/policy/template.yaml

## External data for Gatekeeper mutating webhook

External data can be used in conjunction with [Gatekeeper mutating webhook](mutation.md).

### API

You can specify the details of the external data provider in the `spec.parameters.assign.externalData` field of `AssignMetadata` and `Assign`.

> Note: `spec.parameters.assign.externalData`, `spec.parameters.assign.value` and `spec.parameters.assign.fromMetadata` are mutually exclusive.

| Field                            | Description                                                                                                                                                 |
|----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `provider`<br/>String             | The name of the external data provider.                                                                                                                     |
| `dataSource`<br/>DataSource       | Specifies where to extract the data that will be sent to the external data provider.<br/>- `ValueAtLocation` (default): extracts an array of values from the path that will be modified. See [mutation intent](mutation.md#intent) for more details.<br/>- `Username`: The name of the Kubernetes user who initiated the admission request.  |
| `failurePolicy`<br/>FailurePolicy | The policy to apply when the external data provider returns an error.<br/>- `UseDefault`: use the default value specified in `spec.parameters.assign.externalData.default`<br/>- `Ignore`: ignore the error and do not perform any mutations.<br/>- `Fail` (default): do not perform any mutations and return the error to the user.                                       |
| `default`<br/>String              | The default value to use when the external data provider returns an error and the failure policy is set to `UseDefault`.                                    |

### `AssignMetadata`

```yaml
apiVersion: mutations.gatekeeper.sh/v1beta1
kind: AssignMetadata
metadata:
  name: annotate-owner
spec:
  match:
    scope: Namespaced
    kinds:
    - apiGroups: ["*"]
      kinds: ["Pod"]
  location: "metadata.annotations.owner"
  parameters:
    assign:
      externalData:
        provider: my-provider
        dataSource: Username
```

<details>
<summary>Provider response</summary>

```json
{
  "apiVersion": "externaldata.gatekeeper.sh/v1beta1",
  "kind": "ProviderResponse",
  "response": {
    "idempotent": true,
    "items": [
      {
        "key": "kubernetes-admin",
        "value": "admin@example.com"
      }
    ]
  }
}
```

</details>

<details>
<summary>Mutated object</summary>

```yaml
...
metadata:
  annotations:
    owner: admin@example.com
...
```

</details>

### `Assign`

```yaml
apiVersion: mutations.gatekeeper.sh/v1beta1
kind: Assign
metadata:
  name: mutate-images
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    scope: Namespaced
  location: "spec.containers[name:*].image"
  parameters:
    assign:
      externalData:
        provider: my-provider
        dataSource: ValueAtLocation
        failurePolicy: UseDefault
        default: busybox:latest
```

<details>
<summary>Provider response</summary>

```json
{
  "apiVersion": "externaldata.gatekeeper.sh/v1beta1",
  "kind": "ProviderResponse",
  "response": {
    "idempotent": true,
    "items": [
      {
        "key": "nginx",
        "value": "nginx:v1.2.3"
      }
    ]
  }
}
```

</details>

<details>
<summary>Mutated object</summary>

```yaml
...
spec:
  containers:
    - name: nginx
      image: nginx:v1.2.3
...
```

</details>

### Limitations

There are several limitations when using external data with the mutating webhook:

- Only supports mutation of `string` fields (e.g. `.spec.containers[name:*].image`).
- `AssignMetadata` only supports `dataSource: Username` because `AssignMetadata` only supports creation of `metadata.annotations` and `metadata.labels`. `dataSource: ValueAtLocation` will not return any data.
- `ModifySet` does not support external data.
- Multiple mutations to the same object are applied alphabetically based on the name of the mutation CRDs. If you have an external data mutation and a non-external data mutation with the same `spec.location`, the final result might not be what you expected. Currently, there is no way to enforce custom ordering of mutations but the issue is being tracked [here](https://github.com/open-policy-agent/gatekeeper/issues/1133).

## TLS and mutual TLS support

Since external data providers are in-cluster HTTP servers backed by Kubernetes services, communication is not encrypted by default. This can potentially lead to security issues such as request eavesdropping, tampering, and man-in-the-middle attack.

To further harden the security posture of the external data feature,

- starting from Gatekeeper v3.9.0, TLS and mutual TLS (mTLS) via HTTPS protocol are supported between Gatekeeper and external data providers
- starting with Gatekeeper v3.11.0, TLS or mutual TLS (mTLS) via HTTPS protocol are _required_ between Gatekeeper and external data providers with a minimum TLS version of 1.3

In this section, we will describe the steps required to configure them.

### Prerequisites

- A Gatekeeper deployment with version >= v3.9.0.
- The certificate of your certificate authority (CA) in PEM format.
- The certificate of your external data provider in PEM format, signed by the CA above.
- The private key of the external data provider in PEM format.

### How to generate a self-signed CA and a keypair for the external data provider

In this section, we will describe how to generate a self-signed CA and a keypair using `openssl`.

1. Generate a private key for your CA:

```bash
openssl genrsa -out ca.key 2048
```

2. Generate a self-signed certificate for your CA:

```bash
openssl req -new -x509 -days 365 -key ca.key -subj "/O=My Org/CN=External Data Provider CA" -out ca.crt
```

3. Generate a private key for your external data provider:

```bash
 openssl genrsa -out server.key 2048
```

4. Generate a certificate signing request (CSR) for your external data provider:

> Replace `<service name>` and `<service namespace>` with the correct values.

```bash
openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/CN=<service name>.<service namespace>" -out server.csr
```

5. Generate a certificate for your external data provider:

```bash
openssl x509 -req -extfile <(printf "subjectAltName=DNS:<service name>.<service namespace>") -days 365 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
```

### How Gatekeeper trusts the external data provider (TLS)

To enable one-way TLS, your external data provider should enable any TLS-related configurations for their HTTP server. For example, for Go's built-in [`HTTP server`](https://pkg.go.dev/net/http#Server) implementation, you can use [`ListenAndServeTLS`](https://pkg.go.dev/net/http#ListenAndServeTLS):

```go
server.ListenAndServeTLS("/etc/ssl/certs/server.crt", "/etc/ssl/certs/server.key")
```

In addition, the provider is also responsible for supplying the certificate authority (CA) certificate as part of the Provider spec so that Gatekeeper can verify the authenticity of the external data provider's certificate.

The CA certificate must be encoded as a base64 string when defining the Provider spec. Run the following command to perform base64 encoding:

```bash
cat ca.crt | base64 | tr -d '\n'
```

With the encoded CA certificate, you can define the Provider spec as follows:

```yaml
apiVersion: externaldata.gatekeeper.sh/v1beta1
kind: Provider
metadata:
  name: my-provider
spec:
  url: https://<service-name>.<namespace>:<port>/<endpoint> # URL to the external data source (e.g., https://my-provider.my-namespace:8090/validate)
  timeout: <timeout> # timeout value in seconds (e.g., 1). this is the timeout on the Provider custom resource, not the provider implementation.
  caBundle: <encoded-ca-certificate> # base64 encoded CA certificate.
```

### How the external data provider trusts Gatekeeper (mTLS)

Gatekeeper attaches its certificate as part of the HTTPS request to the external data provider. To verify the authenticity of the Gatekeeper certificate, the external data provider must have access to Gatekeeper's CA certificate. There are several ways to do this:

1. Deploy your external data provider to the same namespace as your Gatekeeper deployment. By default, [`cert-controller`](https://github.com/open-policy-agent/cert-controller) is used to generate and rotate Gatekeeper's webhook certificate. The content of the certificate is stored as a Kubernetes secret called `gatekeeper-webhook-server-cert` in the Gatekeeper namespace e.g. `gatekeeper-system`. In your external provider deployment, you can access Gatekeeper's certificate by adding the following `volume` and `volumeMount` to the provider deployment so that your server can trust Gatekeeper's CA certificate:

```yaml
volumeMounts:
  - name: gatekeeper-ca-cert
    mountPath: /tmp/gatekeeper
    readOnly: true
volumes:
  - name: gatekeeper-ca-cert
    secret:
      secretName: gatekeeper-webhook-server-cert
      items:
        - key: ca.crt
          path: ca.crt
```

After that, you can attach Gatekeeper's CA certificate in your TLS config and enable any client authentication-related settings. For example:

```go
caCert, err := ioutil.ReadFile("/tmp/gatekeeper/ca.crt")
if err != nil {
  panic(err)
}

clientCAs := x509.NewCertPool()
clientCAs.AppendCertsFromPEM(caCert)

server := &http.Server{
	Addr:    ":8090",
	TLSConfig: &tls.Config{
		ClientAuth: tls.RequireAndVerifyClientCert,
		ClientCAs:  clientCAs,
		MinVersion: tls.VersionTLS13,
	},
}
```

2. If `cert-controller` is disabled via the `--disable-cert-rotation` flag, you can use a cluster-wide, well-known CA certificate for Gatekeeper so that your external data provider can trust it without being deployed to the `gatekeeper-system` namespace.

### Authenticate the API server against Webhook (Self managed K8s cluster only)

> ⚠️ Two new flags will be introduced in v3.11 because of these changes. And since they are not backward compatible, you may need a clean install to make use of them.

**Note:** To enable authenticating the API server you have to be able to modify cluster resources. This may not be possible for managed K8s clusters.

To ensure a request to the Gatekeeper webhook is coming from the API server, Gatekeeper needs to validate the client cert in the request. To enable authenticate API server, the following configuration can be made:

1. Deploy Gatekeeper with a client CA cert name. Provide name of the client CA with the flag `--client-ca-name`. The same name will be used to read certificate from the webhook secret. The webhook will only authenticate API server requests if client CA name is provided with flag. You can modify gatekeeper deployment to add these flags and enable authentication of API server's requests. For example:

    ```yaml
    containers:
    - args:
      - --port=8443
      - --logtostderr
      - --exempt-namespace=gatekeeper-system
      - --operation=webhook
      - --operation=mutation-webhook
      - --disable-opa-builtin={http.send}
      - --client-cn-name=my-cn-name
      - --client-ca-name=clientca.crt
    ```

2. You will need to patch the webhook secret manually to attach client ca crt. Update secret `gatekeeper-webhook-server-cert` to include `clientca.crt`. Key name `clientca.crt` should match the name passed with `--client-ca-name` flag. You could generate your own CA for this purpose.

    ```yaml
    kind: Secret
    apiVersion: v1
    data:
      ca.crt: <ca-crt>
      ca.key: <ca-key>
      tls.crt: <tls-crt>
      tls.key: <tls-key>
      clientca.crt: <myCA.crt> # root certificate generated with the help of commands in step 3
    metadata:
      ...
      name: <gatekeeper-webhook-service-name>
      namespace: <gatekeeper-namespace>
    type: Opaque
    ```

3. Generate CA and client certificates signed with CA authority to be attached by the API server while talking to Gatekeeper webhook. Gatekeeper webhook expects the API server to attach the certificate that has CN name as `kube-apiserver`. Use `--client-cn-name` to provide custom cert CN name if using a certificate with other CN name, otherwise webhook will throw the error and not accept the request.

    - Generate private key for CA

      ```bash
        openssl genrsa -des3 -out myCA.key 2048
      ```

    - Generate a root certificate

      ```bash
        openssl req -x509 -new -nodes -key myCA.key -sha256 -days 1825 -out myCA.crt
      ```

    - Generate private key for API server

      ```bash
      openssl genrsa -out apiserver-client.key 2048
      ```

    - Generate a CSR for API server

      ```bash
      openssl req -new -key apiserver-client.key -out apiserver-client.csr
      ```

    - Generate public key for API server

      ```bash
      openssl x509 -req -in apiserver-client.csr -CA myCA.crt -CAkey myCA.key -CAcreateserial -out apiserver-client.crt -days 365
      ```

      > The client certificate generated by the above command will expire in 365 days, and you must renew it before it expires. Adjust the value of `-day` to set the expiry on the client certificate according to your need.

4. You will need to make sure the K8s API Server includes the appropriate certificate while sending requests to the webhook, otherwise webhook will not accept these requests and will log an error of `tls client didn't provide a certificate`. To make sure the API server attaches the correct certificate to requests being sent to webhook, you must specify the location of the admission control configuration file via the `--admission-control-config-file` flag while starting the API server. Here is an example admission control configuration file:

    ```yaml
    apiVersion: apiserver.config.k8s.io/v1
    kind: AdmissionConfiguration
    plugins:
    - name: ValidatingAdmissionWebhook
      configuration:
        apiVersion: apiserver.config.k8s.io/v1
        kind: WebhookAdmissionConfiguration
        kubeConfigFile: "<path-to-kubeconfig-file>"
    - name: MutatingAdmissionWebhook
      configuration:
        apiVersion: apiserver.config.k8s.io/v1
        kind: WebhookAdmissionConfiguration
        kubeConfigFile: "<path-to-kubeconfig-file>"
    ```

    KubeConfig file should look something like:

    ```yaml
    apiVersion: v1
    clusters:
    - cluster:
        certificate-authority-data: <myCA.crt> # same value as provided in gatekeeper webhook secret's clientca.crt
        server: https://<gatekeeper-webhook-service-name>.<gatekeeper-namespace>.svc:443
      name: <cluster-name>
    contexts:
    - context:
        cluster: <cluster-name>
        user: api-server
      name: <context-name>
    current-context: <context-name>
    kind: Config
    users:
    - name: api-server
      user:
        client-certificate-data: <apiserver-client.crt>
        client-key-data: <apiserver-client.key>
    ```

    **Note**: Default `gatekeeper-webhook-service-name` is `gatekeeper-webhook-service` and default `gatekeeper-namespace` is `gatekeeper-system`.

    Visit [#authenticate-apiservers](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers) for more details.

## Disabling external data support

External data support is enabled by default. If you don't need external data support, you can disable it.

### YAML

You can disable external data support by adding `--enable-external-data=false` in gatekeeper audit and controller-manager deployment arguments.

### Helm

You can also disable external data by installing or upgrading Helm chart by setting `enableExternalData=false`:

```sh
helm install gatekeeper/gatekeeper --name-template=gatekeeper --namespace gatekeeper-system --create-namespace \
  --set enableExternalData=false
```

---

--- METRICS ---
- Files Extracted: 39
- Estimated Token Budget: ~127216 tokens
- Canonical Reference: https://codewiki.google/github.com/open-policy-agent/gatekeeper
