# Create a Policy and Block a Deployment

Source: https://docs.ops0.com/docs/how-to/policies-and-compliance

Write a security policy in OPA/Rego, attach it to an IaC project, and watch it block a non-compliant Terraform deployment before anything reaches your cloud.

---

## Scenario

Your team is deploying S3 buckets but some are being created without server-side encryption. You want to:
- Write a policy that requires all S3 buckets to have encryption enabled
- Attach it to your IaC projects
- Have it automatically block any deployment that violates the rule

---

## Prerequisites

- At least one IaC project created in ops0

- `can_policies` IAM permission (admin role has this by default)

---

## Step 1: Create a Policy Group

Policy groups organize related policies and get attached to projects as a unit.

1. Click **Policies & Compliance** in the left sidebar

2. Click **New Policy Group**

3. Name it `S3 Security Policies`

4. Set **Group Type** to **IaC**

5. Click **Create Group**

---

## Step 2: Write the Policy

1. Inside the group, click **New Policy**

2. Fill in the policy details

| Field | Value |
|-------|-------|
| **Name** | Require S3 Encryption |
| **Description** | All S3 buckets must have server-side encryption enabled |
| **Category** | Security |
| **Severity** | Critical |

**Policy content** (OPA/Rego):

```rego
package main

deny[msg] {
  input.resource.type == "aws_s3_bucket"
  not has_encryption(input.resource)
  msg := sprintf(
    "S3 bucket '%v' must have server-side encryption enabled. Add an aws_s3_bucket_server_side_encryption_configuration block.",
    [input.resource.name]
  )
}

has_encryption(resource) {
  resource.values.server_side_encryption_configuration[_].rule[_].apply_server_side_encryption_by_default[_]
}
```

Click **Save Policy**.

---

## Step 3: Add the Policy to the Group

1. In the group view, click **Add Policy**

2. Select the policy you just created

3. Click **Add**

---

## Step 4: Attach the Group to an IaC Project

1. In the group, click **Attach to Projects**

2. Select the IaC project(s) to attach

3. Make sure **Enabled** is toggled on

4. Click **Save**

The policy group is now active on that project. Every future deployment will be checked against it.

---

## Step 5: Trigger a Violation

To see the policy in action, try deploying an S3 bucket without encryption:

```hcl
# This will be BLOCKED by the policy
resource "aws_s3_bucket" "insecure" {
  bucket = "my-insecure-bucket"
}
```

Run a **Plan** on this code. When you try to apply, the policy engine evaluates the plan JSON and returns:

```
Policy Check: FAILED

  ✗ CRITICAL  Require S3 Encryption
    Resource:    aws_s3_bucket.insecure
    Message:     S3 bucket 'insecure' must have server-side encryption enabled.
                 Add an aws_s3_bucket_server_side_encryption_configuration block.
    Remediation: Add server_side_encryption_configuration block to resource

Deployment BLOCKED — critical violations must be resolved before applying.
```

The apply does not proceed. Nothing is created in AWS.

---

## Step 6: Fix the Code and Redeploy

Add the encryption configuration:

```hcl
resource "aws_s3_bucket" "secure" {
  bucket = "my-secure-bucket"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "secure" {
  bucket = aws_s3_bucket.secure.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}
```

Run the plan again. This time the policy check passes and you can apply.

---

## View Compliance Status

Go to **Policies & Compliance → Compliance** to see:

- **Compliance score** across your organization
- **Policy groups** and their attachment status
- **Recent violations** — which deployments were blocked and why
- **Trend** — violation rate over the past 30 days

---

## Violation Severity Behavior

| Severity | Behavior |
|----------|----------|
| **Critical** | Deployment blocked — cannot proceed |
| **High** | Warning shown — engineer must acknowledge before applying |
| **Medium** | Info message logged — deployment continues |
| **Low** | Info message logged — deployment continues |

---

## Next Steps

[Enforce on Kubernetes → Deploy Kyverno policies to block non-compliant pod definitions at admission time](https://docs.ops0.com/docs/configurations/kyverno)
[More policy examples → Cost, tagging, networking, and IAM policy templates](https://docs.ops0.com/docs/policies/creating-policies)

---

## Troubleshooting

Policy not triggering on deployments

Verify the policy group is attached to the correct project and the **Enabled** toggle is on. Policy checks only run on new deployments — they don't retroactively affect past ones.

Rego syntax error on save

ops0 validates Rego syntax on save. Common issues: missing package declaration, incorrect string interpolation with `sprintf`, or forgetting to import builtins. The error message points to the problematic line.

Policy fires on compliant resources

The Rego rule may be too broad. Test the policy with a sample plan JSON using OPA playground (`play.openpolicyagent.org`) before attaching it to projects. Check that your `has_encryption` helper correctly traverses the Terraform plan structure.
