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.
Select IaC Policies, Configuration Policies, or Kubernetes Policies.
Opens the policy editor.
Set name, category, severity, and IaC type scope.
Write Rego/YAML manually, use AI generation, or import a template.
Run the policy against sample input to verify it catches the intended violations.
Save the policy and map it to projects or policy groups.
| 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.
| 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 |
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.
Generate a policy from natural language — available for all policy types.
Opens the AI generation dialog.
Example: "Block any EC2 instance that doesn't have the Environment and Owner tags."
Set the appropriate values before generating.
AI produces complete Rego (for IaC/configurations) or Kyverno YAML (for Kubernetes). Edit as needed.
Save directly from the dialog.
AI generation requires a Claude API key in Settings → API Configuration.
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 |
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"
}
| 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 |
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.
Access Terraform plan data via input.planned_values.root_module.resources.
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]
)
}
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]
)
}
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]
)
}
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]
)
}
Kyverno policies are YAML and enforce rules at Kubernetes admission time.
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
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: "?*"
Use the right panel in the policy editor to test against sample Terraform plan JSON:
Add a Terraform plan fragment in the Input panel.
Evaluate the policy against the input.
Violations appear in the Output panel.
Sample input:
{
"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:
{
"deny": [
"S3 bucket 'my-bucket' must have encryption enabled",
"Resource 'aws_s3_bucket.data' missing required tags: {\"Owner\", \"CostCenter\"}"
]
}
Import from 50 built-in templates rather than writing from scratch.
Go to Policies → Templates. Templates are grouped by category and searchable by name.
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.
Click Import. A modal opens where you can:
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 |
Group policies and attach groups to projects for bulk management.
Select Policy Groups on the Policies page.
Click Create Group. Set a name, description, and type (iac, configurations, or kubernetes).
Select policies to include.
Attach the group to one or more projects. All policies apply to all mapped projects.
When you delete a policy group:
| Method | Use when |
|---|---|
| Direct mapping | A specific policy applies to a few specific projects |
| Policy group | A set of policies applies to many projects |
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.
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].
After creating a Kyverno policy, deploy it to one or more connected Kubernetes clusters:
Navigate to Policies → Kubernetes Policies and click the policy.
Click the Deploy to Cluster button in the policy detail view.
A modal opens showing all connected clusters. Select one or more clusters.
For each cluster, choose:
Click Deploy. ops0 pushes the Kyverno ClusterPolicy YAML to each selected cluster via the Kubernetes API.
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.
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.
Policy types, severity levels, frameworks, and platform capabilities.
Monitor compliance posture and manage violations.
Step-by-step guide to setting up policy enforcement.
Configure blocking levels and default policy groups.