Kion Policy Engine (KPE) lets you define YAML-based rules that discover cloud resources, evaluate them against conditions, and apply actions — all in a single declarative file. KPE is the engine that powers Automation Policies within Kion. This guide provides you with information on how to construct (or modify) policies for KPE so that you can take maximum advantage of the power available in Kion.
What is a Policy?
A policy is a YAML file with the following keys:
name: "My Policy" # Human-readable label
filters: # List of conditions to match resources
- field: State.Name
op: eq
value: running
actions: # What to do with matched resources
- type: tag
params:
key: Environment
value: production
variables: # Optional — define inputs referenced in filters/actions
environment:
type: string
required: true
options: # Optional — execution behavior
dry_run: false
variables , filters, and options are optional. All other keys are required.
Resource Types
Resources follow the format <provider>.<resource_type>. Resources are selected in the UI when making a policy definition.
| Provider | Example Resource Types |
|---|---|
aws |
aws.ec2, aws.s3, aws.iam_role, aws.rdsinstance, aws.kms_key, aws.lambda, aws.eks_node_group
|
azure |
azure.storage_account, azure.virtual_machine
|
gcp |
gcp.storage, gcp.gke_node_pool, gcp.vertex_custom_job
|
Syntax Basics
Filters
Filters are the conditions used to select resources. Each filter is an object with a field, an op (operator), and usually a value.
filters:
- field: State.Name
op: eq
value: running
Multiple filters at the same level are implicitly AND-ed — all conditions must be true for a resource to match.
filters:
- field: State.Name
op: eq
value: running
- field: Tags.Owner # AND this must also be true
op: not_exists
Operators
| Operator | Description | Accepts Value? | Valid Types |
|---|---|---|---|
eq |
Equal to | Yes | string, int, float, bool, time |
ne |
Not equal to | Yes | string, int, float, bool, time |
gt |
Greater than | Yes | int, float, time |
gte |
Greater than or equal | Yes | int, float, time |
lt |
Less than | Yes | int, float, time |
lte |
Less than or equal | Yes | int, float, time |
in |
Value is in list | Yes (array) | string, int, float, bool |
not_in |
Value is not in list | Yes (array) | string, int, float, bool |
contains |
String or array contains value | Yes | string, array |
regex |
Matches a regular expression | Yes (string) | string |
exists |
Field is present | No | any |
not_exists |
Field is absent | No | any |
Time values must be full ISO 8601 / RFC 3339 strings, e.g. "2025-01-01T00:00:00Z".
Field Access
Use dot notation to reach nested fields:
- field: State.Name # nested object field - field: ScalingConfig.DesiredSize # deeper nesting - field: PublicAccessBlockConfiguration.BlockPublicAcls
Tags are accessed with the Tags. prefix:
- field: Tags.Environment # matches tag key "Environment" - field: Tags.Owner # use exists / not_exists to check presence
Logical Operators
Use and:, or:, and not: blocks to compose complex conditions.
OR — at least one sub-condition must match:
filters:
- or:
- field: Tags.Owner
op: not_exists
- field: Tags.Owner
op: eq
value: ""NOT — the sub-condition must not match:
filters:
- not:
field: Tags.Managed
op: eq
value: "true"AND — all sub-conditions must match (explicit form):
filters:
- and:
- field: VpcId
op: exists
- field: Tags.Owner
op: not_existsand:, or:, and not: blocks can be nested inside each other.
Function Filters
Filters can call named functions instead of using field/op/value. Use the function key, with an optional args key for functions that accept parameters.
filters:
- function: hasActiveInstances # matches resources where the function returns true
- not:
function: hasActiveInstances # matches resources where it returns falseSome functions accept arguments:
filters:
- function: hasTag
args:
key: "Environment"
value: "production"Generic functions
These are available on every resource type:
| Function | Description |
|---|---|
hasTag |
Checks whether a resource has a specific tag key, optionally matching a value |
hasTags |
Checks whether a resource has all of a given set of tag key-value pairs |
has |
Checks whether a field path exists on the resource |
get |
Retrieves a value at a dot-separated field path |
contains |
Checks whether a string contains a substring |
matches |
Checks whether a string matches a regex pattern |
startsWith / endsWith
|
Prefix and suffix checks |
isEmpty |
Checks whether a value is empty |
length |
Returns the length of a string, array, or map |
Resource-specific functions
Each resource type may expose additional functions. These are only valid for the resource type they belong to. Resource-specific functions are defined for each resource on the Technical Overview page under the Supported Resources section.
Actions
Actions run against every resource that passes the filters.
| Action | Description |
|---|---|
tag |
Add or update a single tag |
bulk_tag |
Add or update multiple tags at once |
delete |
Delete the resource |
stop |
Stop a running resource (compute/cluster) |
start |
Start a stopped resource |
Single tag
actions:
- type: tag
params:
key: ComplianceStatus
value: "review-required"
overwrite: false # skip if tag already exists
Multiple tags
actions:
- type: bulk_tag
params:
tags:
ManagedBy: "kion-policy-engine"
LastTagged: "{{.Timestamp}}" # template variable
overwrite: true
Custom Variables
Custom variables must be declared in the policy body (for now). We will explore removing this requirement in the future. Define reusable inputs in a variables block and reference them anywhere in filters or actions using ${var.name}.
variables:
environment:
type: string
description: "Target environment"
required: true # must be supplied at execution time
region:
type: string
default: "us-east-1" # used if not supplied
filters:
- field: Tags.Environment
op: eq
value: "${var.environment}"
actions:
- type: bulk_tag
params:
tags:
Region: "${var.region}"
Each variable must declare a type and either required: true or a default value — not both.
| Type | Accepted values |
|---|---|
string |
Text |
int |
Whole number |
float |
Decimal number |
bool |
true / false
|
list |
Array of values |
map |
Key-value object |
Policy Examples
Example 1: Multi-Condition Filter with Tagging
This policy finds S3 buckets where versioning is not enabled and tags them for a compliance review.
name: "Flag Unversioned S3 Buckets
filters:
- field: Versioning.Status
op: ne
value: Enabled
- field: Tags.ComplianceReview
op: not_exists
actions:
- type: bulk_tag
params:
tags:
ComplianceReview: "versioning-disabled"
LastChecked: "{{.Timestamp}}"
overwrite: false
What this shows:
- Multiple top-level filters are implicitly AND-ed — both conditions must be true
- Dot notation reaches nested fields (
Versioning.Status) -
not_existschecks for a missing tag key -
{{.Timestamp}}is a template variable resolved at execution time
Example 2: Function Filters
This policy deletes Classic ELBs that have no registered instances — using a resource-specific function rather than a field comparison.
name: "Delete Unused Classic ELBs"
filters:
- not:
function: hasActiveInstances
actions:
- type: delete
The same pattern works for functions that accept arguments. This policy uses the generic hasTag function to find EC2 instances missing a required tag:
name: "Flag EC2 Instances Missing Owner Tag"
filters:
- not:
function: hasTag
args:
key: "Owner"
actions:
- type: tag
params:
key: ReviewStatus
value: "missing-owner"
overwrite: false
What this shows:
-
function:replacesfield/op/valueentirely — the two forms cannot be mixed in a single filter entry -
not:wraps a function filter the same way it wraps a field filter - Generic functions like
hasTagwork on any resource; resource-specific functions likehasActiveInstancesare only valid on the resource type they belong to (aws.elbin this case)
Example 3: Parameterized Policy with Variables
This policy uses variables so the same policy file can be applied to different environments without editing the YAML.
name: "Tag Resources by Environment"
variables:
environment:
type: string
description: "The target environment (e.g. production, staging)"
required: true
cost_center:
type: string
default: "unassigned"
filters:
- field: Tags.Environment
op: eq
value: "${var.environment}"
- field: Tags.CostCenter
op: not_exists
actions:
- type: bulk_tag
params:
tags:
CostCenter: "${var.cost_center}"
ManagedBy: "kion-policy-engine"
overwrite: fal
What this shows:
- Variables are declared under
variables:with atypeand eitherrequired: trueor adefault - They are referenced in filters and action params using
${var.name} -
required: truemeans the value must be supplied at execution time;defaultis used when it is not - The same policy file can run against production, staging, or any other environment by passing a different
environmentvalue