# Creating Policies

Source: https://docs.ops0.com/docs/policies/creating-policies

Write OPA/Rego policies for IaC and configuration projects, or Kyverno YAML for Kubernetes clusters. Use the built-in editor, import from templates, or generate with AI.

---

## Creating a Policy

### Choose a tab
Select **IaC Policies**, **Configuration Policies**, or **Kubernetes Policies**.

### Click Create Policy
Opens the policy editor.

### Configure settings
Set name, category, severity, and IaC type scope.

### Write or generate code
Write Rego/YAML manually, use AI generation, or import a template.

### Test
Run the policy against sample input to verify it catches the intended violations.

### Save and assign
Save the policy and map it to projects or policy groups.

---

## Policy Settings

### IaC and Configuration Policies

| Field | Required | Description |
|-------|----------|-------------|
| **Name** | Yes | Policy name |
| **Description** | No | What this policy checks |
| **Category** | Yes | security, cost, compliance, tagging, best-practices, custom |
| **Severity** | Yes | error, warning, or info |
| **IaC Type** | No | terraform, opentofu, oxid, cloudformation, or any (default) |
| **Enabled** | Yes | Toggle enforcement |

**IaC Type** scoping controls which engine the policy applies to. Set it to `cloudformation` for policies that check CloudFormation template syntax. Leave as `any` to evaluate against all engines.

### Kubernetes Policies

| Field | Required | Description |
|-------|----------|-------------|
| **Name** | Yes | Policy name |
| **YAML** | Yes | Kyverno ClusterPolicy or Policy YAML |
| **Enabled** | Yes | Toggle enforcement |
| **Cluster Mappings** | No | Specific clusters to deploy this policy to |

---

## Policy Editor Layout

The policy editor has four panels:

| Panel | Location | Content |
|-------|----------|---------|
| **Settings** | Left sidebar | Name, description, category, severity, IaC type, enabled toggle |
| **Code editor** | Centre | Rego code (for IaC/Config) or YAML (for Kubernetes) with syntax highlighting |
| **Test panel** | Right | Input JSON (for Rego testing) and output (violation messages) |
| **Validation bar** | Bottom | Syntax errors and lint warnings for the current code |

The center code editor uses Monaco (VS Code engine) with full Rego and YAML syntax support, including error underlines and line-level diagnostics.

---

## AI Policy Generation

Generate a policy from natural language — available for all policy types.

### Click "Generate with AI"
Opens the AI generation dialog.

### Enter a prompt
Example: *"Block any EC2 instance that doesn't have the Environment and Owner tags."*

### Choose category and severity
Set the appropriate values before generating.

### Review and edit
AI produces complete Rego (for IaC/configurations) or Kyverno YAML (for Kubernetes). Edit as needed.

### Save
Save directly from the dialog.

**Requires AI configuration**

AI generation requires a Claude API key in **Settings → API Configuration**.

---

## Policy Editor (Rego)

The editor has a multi-panel layout:

| Panel | Purpose |
|-------|---------|
| **Left** | Policy settings and metadata |
| **Center** | Rego code editor with syntax highlighting |
| **Right** | Test input (JSON) and output (violations) |
| **Bottom** | Validation errors |

---

## Rego Basics

### Policy Structure

```rego
package ops0.terraform.example

# Deny rule — generates an error-severity violation
deny[msg] {
    some_condition

    msg := "Description of the violation"
}

# Warn rule — generates a warning-severity violation
warn[msg] {
    some_other_condition

    msg := "Description of the warning"
}
```

### Key Concepts

| Concept | Description |
|---------|-------------|
| `package` | Namespace — must be unique across all policies in the project |
| `deny[msg]` | Rule that returns Error violations |
| `warn[msg]` | Rule that returns Warning violations |
| `input` | The data being evaluated (Terraform plan JSON, config state, etc.) |
| `sprintf` | Format violation messages with variable values |

**Unique package names**

ops0 uses the `package` declaration to query the correct OPA rule. If two policies in the same project share a package name, one will silently override the other. Use descriptive, unique names like `package ops0.terraform.s3.encryption`.

---

## Terraform Policy Examples

Access Terraform plan data via `input.planned_values.root_module.resources`.

### S3 Encryption Required

```rego
package ops0.terraform.s3.encryption

deny[msg] {
    resource := input.planned_values.root_module.resources[_]
    resource.type == "aws_s3_bucket"
    not resource.values.server_side_encryption_configuration

    msg := sprintf(
        "S3 bucket '%s' must have encryption enabled",
        [resource.values.bucket]
    )
}
```

### Instance Size Limits

```rego
package ops0.terraform.ec2.instance_type

allowed_types := {"t3.micro", "t3.small", "t3.medium", "t3.large"}

deny[msg] {
    resource := input.planned_values.root_module.resources[_]
    resource.type == "aws_instance"
    not resource.values.instance_type in allowed_types

    msg := sprintf(
        "Instance '%s' uses '%s'. Allowed: %v",
        [resource.address, resource.values.instance_type, allowed_types]
    )
}
```

### Required Tags

```rego
package ops0.terraform.tags.required

required_tags := {"Environment", "Owner", "CostCenter"}

deny[msg] {
    resource := input.planned_values.root_module.resources[_]
    resource.values.tags

    missing := required_tags - {tag | resource.values.tags[tag]}
    count(missing) > 0

    msg := sprintf(
        "Resource '%s' missing required tags: %v",
        [resource.address, missing]
    )
}
```

### No Public RDS

```rego
package ops0.terraform.rds.public_access

deny[msg] {
    resource := input.planned_values.root_module.resources[_]
    resource.type == "aws_db_instance"
    resource.values.publicly_accessible == true

    msg := sprintf(
        "RDS instance '%s' must not be publicly accessible",
        [resource.address]
    )
}
```

---

## Kubernetes Policy Examples (Kyverno)

Kyverno policies are YAML and enforce rules at Kubernetes admission time.

### No Root Containers

```yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-root-user
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-runAsNonRoot
      match:
        any:
          - resources:
              kinds: [Pod]
      validate:
        message: "Containers must not run as root."
        pattern:
          spec:
            containers:
              - securityContext:
                  runAsNonRoot: true
```

### Resource Limits Required

```yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-limits
      match:
        any:
          - resources:
              kinds: [Pod]
      validate:
        message: "CPU and memory limits are required."
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    memory: "?*"
                    cpu: "?*"
```

---

## Testing Policies

Use the right panel in the policy editor to test against sample Terraform plan JSON:

### Paste sample JSON
Add a Terraform plan fragment in the **Input** panel.

### Click Run Test
Evaluate the policy against the input.

### View results
Violations appear in the **Output** panel.

**Sample input:**

```json
{
  "planned_values": {
    "root_module": {
      "resources": [
        {
          "address": "aws_s3_bucket.data",
          "type": "aws_s3_bucket",
          "values": {
            "bucket": "my-bucket",
            "tags": { "Environment": "prod" }
          }
        }
      ]
    }
  }
}
```

**Test output for the S3 + tags policies above:**

```json
{
  "deny": [
    "S3 bucket 'my-bucket' must have encryption enabled",
    "Resource 'aws_s3_bucket.data' missing required tags: {\"Owner\", \"CostCenter\"}"
  ]
}
```

---

## Policy Templates

Import from 50 built-in templates rather than writing from scratch.

### Browse templates
Go to **Policies → Templates**. Templates are grouped by category and searchable by name.

### Preview
Click any template to expand a preview showing the full Rego code, category, and severity. The preview panel also shows example violations the policy would catch.

### Import
Click **Import**. A modal opens where you can:
- Edit the name (defaults to the template name)
- Override the category and severity before saving
- Review the code one more time

Click **Create Policy** to save the imported copy as an editable policy.

Imported policies are tagged `source: template` internally, distinguishing them from manually written policies. They can be edited freely after import.

| Category | Count | Examples |
|----------|-------|---------|
| **AWS Security** | ~15 | S3 encryption, no public access, security group rules |
| **AWS Cost** | ~10 | Instance size limits, GP3 volumes |
| **GCP / Azure Security** | ~8 | Storage encryption, firewall rules, NSG rules |
| **Tagging** | ~7 | Required tags, naming conventions |
| **Best Practices** | ~10 | Various platform standards |

---

## Policy Groups

Group policies and attach groups to projects for bulk management.

### Go to Policy Groups tab
Select **Policy Groups** on the Policies page.

### Create group
Click **Create Group**. Set a name, description, and type (`iac`, `configurations`, or `kubernetes`).

### Add policies
Select policies to include.

### Map to projects
Attach the group to one or more projects. All policies apply to all mapped projects.

### Deleting a Group

When you delete a policy group:
- The group and all its project mappings are removed
- Built-in (framework-imported) policies that **only** belong to this group are deleted automatically
- Built-in policies shared with other groups are preserved
- User-created policies are never deleted when a group is deleted

---

## Mapping Policies to Projects

| Method | Use when |
|--------|----------|
| **Direct mapping** | A specific policy applies to a few specific projects |
| **Policy group** | A set of policies applies to many projects |

### Severity Override

Each direct policy-to-project mapping supports an optional **severity override**. This lets you apply a policy at a different severity for a specific project without creating a duplicate policy.

For example, apply the same "S3 Encryption Required" policy as `warning` in dev and `error` in production by mapping it twice with different overrides.

### Effective Policies

A project's effective policies are the union of directly mapped policies and policies from mapped policy groups. Direct mappings take precedence for deduplication — if the same policy is both directly mapped and in a group, the direct mapping's settings (including any override) apply.

View at **Policies → By Project → [project]**.

---

## Deploying Kyverno Policies to Clusters

After creating a Kyverno policy, deploy it to one or more connected Kubernetes clusters:

### Open the Kyverno policy
Navigate to **Policies → Kubernetes Policies** and click the policy.

### Click Deploy to Cluster
Click the **Deploy to Cluster** button in the policy detail view.

### Select clusters
A modal opens showing all connected clusters. Select one or more clusters.

### Choose enforcement mode
For each cluster, choose:
- **Enforce** — Kubernetes admission requests that violate the policy are rejected
- **Audit** — violations are logged but not blocked

### Deploy
Click **Deploy**. ops0 pushes the Kyverno `ClusterPolicy` YAML to each selected cluster via the Kubernetes API.

### Deployment Status

After deploying, the policy detail shows a **Cluster Deployments** table:

| Column | Description |
|--------|-------------|
| **Cluster** | Cluster name |
| **Mode** | Enforce or Audit |
| **Status** | Ready (policy active) / Not Ready (Kyverno error) / Deploying |
| **Deployed At** | When this version was last deployed |

If a policy is updated (YAML changed), you need to re-deploy to push the new version to clusters. The deployment status shows **Outdated** for clusters running an older version.

### Undeploying

To remove a policy from a cluster, click **Undeploy** next to the cluster in the Cluster Deployments table. The `ClusterPolicy` resource is deleted from the cluster immediately.

---

## Related

- [Policies Overview](https://docs.ops0.com/docs/policies/overview): Policy types, severity levels, frameworks, and platform capabilities.

- [Compliance Dashboard](https://docs.ops0.com/docs/policies/compliance): Monitor compliance posture and manage violations.

- [Enforce Security Policies](https://docs.ops0.com/docs/how-to/enforce-security-policies): Step-by-step guide to setting up policy enforcement.

- [Compliance Settings](https://docs.ops0.com/docs/settings/compliance): Configure blocking levels and default policy groups.
