> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/continuous-delivery/use-gitops/application/opa-policy-support.md).

# OPA policy support for GitOps applications

Use Open Policy Agent (OPA) policies to enforce governance for GitOps applications on save and sync

Harness supports Open Policy Agent (OPA) policies for GitOps Applications so you can enforce governance rules and compliance requirements during GitOps operations such as syncing applications.

With OPA policy support, you can:

* **Enforce deployment freezes:** Prevent syncing GitOps Applications during maintenance windows or specific time periods
* **Control production deployments:** Restrict manual syncs for production applications based on naming conventions or labels
* **Validate application configurations:** Ensure GitOps Applications meet organizational standards before syncing
* **Implement time-based restrictions:** Block or allow syncs based on specific time windows

***

## What you will learn from this topic

* How [OPA policies work](#how-opa-policies-work-for-gitops-applications) for GitOps applications and when they are evaluated
* How to [create a policy](#create-a-policy-for-gitops-applications) for GitOps applications
* How to use [sample policies](#sample-policies) for common governance scenarios
* How to [test policies](#test-policies) using the Testing Terminal
* How to [view policy evaluation results](#view-policy-evaluation-results)

***

## Before you begin

Complete the following prerequisites before you create OPA policies for GitOps Applications:

* **GitOps Applications configured:** At least one GitOps Application exists in your project. Go to [Manage GitOps applications](/continuous-delivery/use-gitops/application/manage-gitops-applications.md) to create and manage applications.
* **Policy permissions:** Create/Edit (and View) permissions on Policies in Harness. Go to [RBAC in Harness](https://developer.harness.io/docs/platform/role-based-access-control/rbac-in-harness) to configure roles.
* **Rego familiarity:** Basic knowledge of the Rego policy language used by OPA.

Go to [OPA Policy language](https://www.openpolicyagent.org/docs/latest/policy-language/) and the [Rego Cheatsheet](https://dboles-opa-docs.netlify.app/docs/v0.10.7/rego-cheatsheet/) to learn about writing Rego policies.

Go to [Harness Policy as Code overview](https://developer.harness.io/docs/platform/governance/policy-as-code/harness-governance-overview) for a platform-wide overview of Harness Policy as Code and OPA.

***

## How OPA policies work for GitOps applications

When you create a policy for GitOps Applications, the policy is evaluated against the GitOps Application entity during specific events:

* **On Save:** Policies are evaluated when a GitOps Application is saved or updated
* **On Sync:** Policies are evaluated when a sync operation is initiated for a GitOps Application

The policy receives the GitOps Application configuration as input, including:

* Application metadata (name, namespace, labels)
* Application source configuration
* Application destination configuration
* Sync operation details

{% hint style="warning" %}
**Auto-sync and cluster CLI syncs**

* **OPA policies do not apply to auto-syncs.** Policies are evaluated only when a sync is initiated through the Harness UI or API, not during automatic sync operations triggered by Argo CD.
* **OPA policies do not prevent syncs triggered directly on the cluster.** If a user logs into the cluster and triggers a sync from the command line (for example, using `argocd app sync`), Harness OPA policies are not evaluated.
* **You can prevent auto-syncs using OPA.** Because the `syncPolicy` is set at the application level, you can write an **On Save** policy that denies applications configured with auto-sync enabled, which prevents auto-sync from being set on the application.
  {% endhint %}

***

## Create a policy for GitOps applications

### Navigate to policies

Perform the following steps to open Policies:

1. In Harness, go to **Settings**.
2. Under **Security and Governance**, click **Policies**.

![Policies under Security and Governance in Settings](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-b319417ee58b5b67a6de44340f4feb61204d4dc4%2Fpolicies.png?alt=media)

### Create a new policy

Perform the following steps to create a policy:

1. Click **+ New Policy**.
2. Enter a name for your policy (for example, "GitOps Application - Deployment Freeze").
3. Select **Inline** or **Remote** for policy storage.
4. Click **Apply**.

![New Policy dialog for creating a GitOps Application policy](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-7c8842a3f173c2f442767d4a41b67652657c1e77%2Fnew-policy.png?alt=media)

### Define the policy

In the policy editor, write your Rego policy. The policy should use the `gitopsApplication` package and access the application data through the `input.gitopsApplication` object. You can also search `GitOps` in the Sample Policies and pick the template best suited for the use case.

![Deployment freeze sample policy in the policy editor](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-22327ab9d200ac9893b9fa6c096daf7ed1e851b0%2Fdeployment-freeze-policy.png?alt=media)

### Add policy to a policy set

Perform the following steps to attach the policy to a Policy Set:

1. Go to **Policy Sets**.
2. Create a new Policy Set or edit an existing one.
3. Set the **Entity Type** to **GitOps Application**.
4. Select the event (**On Save** or **On Sync**).
5. Add your policy to the Policy Set.
6. Set the policy severity (**Error and Exit** or **Warn and Continue**).
7. Save the Policy Set.

***

## Sample policies

### Example: Restrict sync during off-hours

This policy prevents GitOps Application syncs during off-hours (for example, between 6 PM and 6 AM UTC):

```rego
# Policy to restrict GitOps Application syncs during off-hours (6 PM to 6 AM)
# This prevents deployments during maintenance windows or when teams are not available
# to respond to issues.
#
# The policy uses the timestamp from the metadata to determine the current hour.
# Configure the restricted hours by modifying restricted_start_hour and restricted_end_hour.
#
# This policy should be applied with action "onsync" to block syncs during restricted hours.

package gitopsApplication

# Define the restricted time window (24-hour format, UTC)
# Syncs are blocked from 18:00 (6 PM) to 06:00 (6 AM)
restricted_start_hour := 18  # 6 PM UTC
restricted_end_hour := 6     # 6 AM UTC

# Calculate current hour from Unix timestamp
# Note: timestamp is in seconds since Unix epoch
# Using floor() to ensure integer division for correct hour calculation
current_hour := hour {
    hour := floor(input.metadata.timestamp / 3600) % 24
}

# Helper rule: Check if current time is in restricted window
# In Rego, multiple rules with the same name act as logical OR
is_restricted_time {
    current_hour >= restricted_start_hour  # Evening hours (6 PM to midnight)
}

is_restricted_time {
    current_hour < restricted_end_hour     # Early morning hours (midnight to 6 AM)
}

# Single deny rule using the helper - message defined once
deny[msg] {
    is_restricted_time
    msg := sprintf("Sync operations are not allowed between %d:00 and %d:00 UTC. Application '%s' sync was attempted at hour %d:00 UTC. Schedule your sync during business hours.", [restricted_start_hour, restricted_end_hour, input.gitopsApplication.name, current_hour])
}
```

### Example: Require service and environment labels

This policy ensures that GitOps Applications have required Harness labels before syncing:

```rego
# Policy to enforce that GitOps Applications have required Harness Service and Environment labels
# These labels (harness.io/serviceRef and harness.io/envRef) are used to link GitOps Applications
# to Harness Services and Environments for tracking deployments and governance.
#
# This policy should be applied with action "onsync" to enforce labels before syncing.

package gitopsApplication

# Deny sync if the Service label (harness.io/serviceRef) is missing
deny[msg] {
    not input.gitopsApplication.app.metadata.labels["harness.io/serviceRef"]
    msg := sprintf("Application '%s' is missing required label 'harness.io/serviceRef'. Add the Harness Service reference label to track deployments.", [input.gitopsApplication.name])
}

# Deny sync if the Service label is empty
deny[msg] {
    input.gitopsApplication.app.metadata.labels["harness.io/serviceRef"] == ""
    msg := sprintf("Application '%s' has an empty 'harness.io/serviceRef' label. Provide a valid Harness Service identifier.", [input.gitopsApplication.name])
}

# Deny sync if the Environment label (harness.io/envRef) is missing
deny[msg] {
    not input.gitopsApplication.app.metadata.labels["harness.io/envRef"]
    msg := sprintf("Application '%s' is missing required label 'harness.io/envRef'. Add the Harness Environment reference label to track deployments.", [input.gitopsApplication.name])
}

# Deny sync if the Environment label is empty
deny[msg] {
    input.gitopsApplication.app.metadata.labels["harness.io/envRef"] == ""
    msg := sprintf("Application '%s' has an empty 'harness.io/envRef' label. Provide a valid Harness Environment identifier.", [input.gitopsApplication.name])
}
```

### Example: Block protected namespaces

This policy prevents GitOps Applications from deploying to protected system namespaces:

```rego
# Policy to prevent GitOps Applications from deploying to protected/system namespaces
# This is a critical security policy to prevent accidental or unauthorized modifications
# to cluster infrastructure namespaces.
#
# Common protected namespaces include:
# - kube-system: Core Kubernetes components
# - kube-public: Public cluster info
# - kube-node-lease: Node heartbeats
# - argocd / gitops-agent namespaces: GitOps infrastructure
# - istio-system: Service mesh
# - cert-manager: Certificate management
#
# This policy can be applied with action "onsave" or "onsync".

package gitopsApplication

# List of namespaces that applications should not deploy to
blocked_namespaces := [
    "kube-system",
    "kube-public",
    "kube-node-lease",
    "default",
    "argocd",
    "gitops-system",
    "istio-system",
    "cert-manager",
    "monitoring",
    "logging"
]

# Check if namespace is in blocked list
is_blocked_namespace(ns) {
    blocked_namespaces[_] == ns
}

# Deny if destination namespace is a protected namespace
deny[msg] {
    ns := input.gitopsApplication.app.spec.destination.namespace
    is_blocked_namespace(ns)
    msg := sprintf("Application '%s' cannot deploy to protected namespace '%s'. Protected namespaces are reserved for system components. Use a different destination namespace.", [input.gitopsApplication.name, ns])
}

# Deny if namespace starts with 'kube-' (Kubernetes reserved)
deny[msg] {
    ns := input.gitopsApplication.app.spec.destination.namespace
    startswith(ns, "kube-")
    msg := sprintf("Application '%s' cannot deploy to Kubernetes reserved namespace '%s'. Namespaces starting with 'kube-' are reserved for Kubernetes system components.", [input.gitopsApplication.name, ns])
}

# Deny if namespace starts with 'openshift-' (OpenShift reserved)
deny[msg] {
    ns := input.gitopsApplication.app.spec.destination.namespace
    startswith(ns, "openshift-")
    msg := sprintf("Application '%s' cannot deploy to OpenShift reserved namespace '%s'. Namespaces starting with 'openshift-' are reserved for OpenShift system components.", [input.gitopsApplication.name, ns])
}
```

***

## Test policies

You can test your policies before applying them. Perform the following steps:

1. In the policy editor, use the **Testing Terminal** tab.
2. Select a sample GitOps Application payload or use a previous evaluation.
3. Run the test to confirm the policy evaluates correctly.
4. Review the results and adjust the policy as needed.

Go to [Harness Policy as Code quickstart](https://developer.harness.io/docs/platform/governance/policy-as-code/harness-governance-quickstart) to test policies in more detail.

***

## Policy input schema

The input payload for GitOps Application policies follows this structure:

```json
{
  "gitopsApplication": {
    "app": {
      "metadata": {
        "name": "application-name",
        "namespace": "argocd",
        "labels": {
          "harness.io/serviceRef": "service-id",
          "harness.io/envRef": "environment-id"
        }
      },
      "spec": {
        "source": {
          "repoURL": "https://github.com/example/repo",
          "targetRevision": "main",
          "path": "manifests"
        },
        "destination": {
          "server": "https://kubernetes.default.svc",
          "namespace": "default"
        }
      },
      "operation": {
        "sync": {
          "syncStrategy": {
            "hook": {}
          }
        }
      }
    }
  },
  "metadata": {
    "action": "onsync",
    "user": {
      "email": "user@example.com",
      "uuid": "user-uuid"
    }
  }
}
```

***

## Policy severity

When adding a policy to a Policy Set, you can set the severity:

* **Error and Exit:** If the policy evaluation fails, the sync operation is blocked and an error message is displayed
* **Warn and Continue:** If the policy evaluation fails, a warning is displayed but the sync operation continues

***

## View policy evaluation results

You can view policy evaluation results in two ways.

### View evaluations in policies

To view all policy evaluations across your GitOps Applications:

1. Go to **Settings** -> **Policies** -> **Evaluations**.
2. Filter evaluations by:
   * **Type:** Select "GitOps Application"
   * **Action:** Select "On Save" or "On Sync"
   * **Status:** Filter by SUCCESS, WARNING, or FAILED
   * **Time range:** Select the date range (for example, "Last 7 days")

The evaluations table shows:

* **ENTITY:** The GitOps Application name and path
* **ENTITY TYPE:** "GitOps Application"
* **EXECUTION:** The Policy Set name that was evaluated
* **EVALUATED ON:** When the evaluation occurred
* **ACTION:** The event that triggered the evaluation ("On Sync" or "On Save")
* **STATUS:** The evaluation result (SUCCESS, WARNING, or FAILED)

![Policy evaluations table filtered for GitOps Application](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-b42ac490879294bb97f682ae4e58bff0369b0c39%2Fevals.png?alt=media)

This view lets you audit policy evaluations over time and identify patterns in policy violations across all your GitOps Applications.

### View evaluation results during sync

When you sync a GitOps Application, the **Policy Set Evaluations** modal appears automatically if policies are evaluated. This modal shows:

* **Evaluation timestamp:** When the policies were evaluated
* **Policy Set information:** The name and scope of the Policy Set
* **Overall status:** The combined status of all policies (SUCCESS, WARNING, or FAILED)
* **Individual policy results:** Each policy's status with specific messages

The modal displays a warning banner if any policies generate warnings, and shows detailed results for each policy in the Policy Set. Policies with **SUCCESS** status are marked with a green checkmark, while policies with **WARNING** or **FAILED** status show the specific error message from the policy evaluation.

This lets you see immediately which policies passed or failed during the sync operation, so you can understand why a sync might have been blocked or why warnings were generated.

![Policy Set Evaluations modal during a GitOps Application sync](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-f322989a6cbbbde346617b9faa9b31fc3c053930%2Fpolicy-eval.png?alt=media)

***

## Best practices

Apply these practices to get value from OPA policies for GitOps Applications:

* **Use descriptive policy names:** Name your policies clearly to indicate their purpose (for example, "GitOps Application - Production Deployment Freeze")
* **Test policies thoroughly:** Use the Testing Terminal to verify policies work as expected before applying them
* **Document policy logic:** Add comments in your Rego code to explain complex logic
* **Start with warnings:** Set policies to "Warn and Continue" first to monitor behavior before enforcing with "Error and Exit"
* **Keep time windows current:** If you use time-based policies, keep maintenance windows and time restrictions accurate
* **Review evaluation results:** Review policy evaluation results regularly to confirm policies behave as intended and to find gaps

***

## Troubleshooting

<details>

<summary>Sync succeeds even though a deny policy exists</summary>

OPA policies do not evaluate Argo CD auto-sync or syncs started with the cluster CLI (for example, `argocd app sync`). Initiate the sync from the Harness UI or API, or use an **On Save** policy that denies auto-sync configuration.

</details>

<details>

<summary>Policy evaluation fails for missing labels</summary>

Add the required `harness.io/serviceRef` and `harness.io/envRef` labels on the GitOps Application, or adjust the policy if those labels are not required for the application.

</details>

<details>

<summary>Policy Set does not run on sync</summary>

Confirm the Policy Set **Entity Type** is **GitOps Application**, the event is **On Sync** (or **On Save** as needed), and the policy is attached with the intended severity.

</details>

***

## Next steps

* [Harness Policy as Code overview](https://developer.harness.io/docs/platform/governance/policy-as-code/harness-governance-overview): Review the platform-wide governance framework.
* [Policy samples](https://developer.harness.io/docs/platform/governance/policy-as-code/sample-policy-use-case): Explore additional policy use cases.
* [Manage GitOps applications](/continuous-delivery/use-gitops/application/manage-gitops-applications.md): Manage your GitOps Applications.

{% @harness-feedback/feedback %}
