Skip to main content

Writing Custom Rules

Learn how to write custom compliance rules for InfraGuard.

Rule Structure

Rules are written in Rego (Open Policy Agent language) with the following structure:

package infraguard.rules.aliyun.my_custom_rule

import rego.v1
import data.infraguard.helpers

rule_meta := {
"id": "my-custom-rule",
"name": {
"en": "My Custom Rule",
"zh": "我的自定义规则",
},
"severity": "high",
"description": {
"en": "Checks for custom compliance requirement",
"zh": "检查自定义合规要求",
},
"reason": {
"en": "Resource does not meet requirement",
"zh": "资源不符合要求",
},
"recommendation": {
"en": "Configure resource properly",
"zh": "正确配置资源",
},
"resource_types": ["ALIYUN::ECS::Instance"],
}

deny contains result if {
some name, resource in helpers.resources_by_type("ALIYUN::ECS::Instance")
# Your compliance logic here
not is_compliant(resource)
result := {
"id": rule_meta.id,
"resource_id": name,
"violation_path": ["Properties", "SomeProperty"],
"meta": {
"severity": rule_meta.severity,
"reason": rule_meta.reason,
"recommendation": rule_meta.recommendation,
},
}
}

is_compliant(resource) if {
# Your compliance check logic
}

For Terraform rules, use the Terraform package namespace, import the Terraform helpers, set iac_type, and use Terraform resource type names:

package infraguard.rules.terraform.my_custom_rule

import rego.v1
import data.infraguard.helpers.terraform as tf

rule_meta := {
"id": "my-custom-rule",
"severity": "high",
"name": {
"en": "My Custom Rule",
"zh": "我的自定义规则",
},
"description": {
"en": "Checks for custom compliance requirement",
"zh": "检查自定义合规要求",
},
"reason": {
"en": "Resource does not meet requirement",
"zh": "资源不符合要求",
},
"recommendation": {
"en": "Configure resource properly",
"zh": "正确配置资源",
},
"resource_types": ["alicloud_instance"],
"iac_type": "terraform",
}

deny contains result if {
some name, resource in tf.resources_by_type("alicloud_instance")
# Your compliance logic here
not is_compliant(resource)
result := {
"id": rule_meta.id,
"resource_id": sprintf("alicloud_instance.%s", [name]),
"meta": {
"severity": rule_meta.severity,
"reason": rule_meta.reason,
"recommendation": rule_meta.recommendation,
},
}
}

is_compliant(resource) if {
tf.get_attribute(resource, "instance_type", "") != ""
}

Key Components

Package Name

For ROS rules, use infraguard.rules.<provider>.<rule_name_snake_case>.

For Terraform rules, use infraguard.rules.terraform.<rule_name_snake_case>.

Note: Use underscores, not hyphens in package names.

Rule Metadata

Required fields:

  • id: Rule identifier (kebab-case)
  • name: Display name (i18n map)
  • severity: high, medium, or low
  • description: What the rule checks
  • reason: Why it failed
  • recommendation: How to fix
  • resource_types: Affected resource types (optional)
  • iac_type: IaC type for Terraform rules ("terraform"); ROS rules default to ROS when omitted

Deny Rule

Must return results with:

  • id: Rule ID
  • resource_id: Resource name from template
  • violation_path: Path to problematic property
  • meta: Severity, reason, recommendation

Terraform rules usually omit violation_path; InfraGuard maps violations back to the matching Terraform resource block when resource_id follows the resource_type.resource_name format.

Helper Functions

See Helper Functions for available utility functions.

Validation

Always validate your rules:

infraguard policy validate my-rule.rego

Debugging Rules

Use print statements to debug your rules during development:

deny contains result if {
print("Checking resource:", name)
print("Resource properties:", object.keys(resource.Properties))
# Your logic here
}

See Debugging Policies for comprehensive debugging techniques.

Next Steps