Rules Configuration
Rules are defined in YAML files and specify what Kexa should check in your infrastructure. This document explains how to create and configure rules.
Basic Rule Structure
Here's a basic example of a rule:
- name: "azure-disk-orphan"
description: "Check for orphaned disks"
applied: true
level: 1 # warn
cloudProvider: azure
objectName: disk
conditions:
- property: diskState
condition: DIFFERENT
value: Unattached
Rule Fields
Required Fields
name: Unique identifier for the ruledescription: Description of what the rule checksapplied: Whether the rule is activelevel: Severity level (0: info, 1: warn, 2: error, 3: fatal)cloudProvider: Provider to check (azure, aws, gcp, etc.)objectName: Type of resource to checkconditions: List of conditions to check
Objects Names
To check all available objects name, your can refer to this page of our website Kexa Addons and click on the addon you want to see objects name from.
Else you can look at the Javascript/Node SDK of the associated addon, we are using the same name.
Conditions
Conditions are the core comparison operators used to evaluate resources in your infrastructure. Each condition consists of three main components:
property: The field or attribute of the resource to checkcondition: The comparison operator to usevalue: The value to compare against
Available Conditions
-
Basic Comparisons:
EQUAL: Checks if the property exactly matches the valueDIFFERENT: Checks if the property is not equal to the valueCONTAINS: Checks if the property contains the specified valueNOT_CONTAINS: Checks if the property does not contain the value
-
Numeric Comparisons:
SUP: Greater thanINF: Less thanSUP_OR_EQUAL: Greater than or equal toINF_OR_EQUAL: Less than or equal to
-
Date & Time Comparisons:
DATE_EQUAL: Exact date matchDATE_SUP: Date is afterDATE_INF: Date is beforeDATE_SUP_OR_EQUAL: Date is on or afterDATE_INF_OR_EQUAL: Date is on or beforeINTERVAL: Checks if within a time intervalDATE_INTERVAL: Checks if within a date range
-
List Operators
These operators are designed to perform checks on properties that are lists (or arrays) of items. They introduce two unique behaviors:
-
List Iteration: To check the items within a list, use . as the value for property inside a nested condition. This . acts as a placeholder for each item in the list being evaluated.
-
Nested Conditions: The value for these operators is not a simple string or number, but a block of one or more conditions that will be applied to the items of the list.
-
-
ALL: Checks if all elements in a list satisfy the nested condition(s).
-
NOT_ANY: Checks if no element in a list satisfies the nested condition(s).
-
SOME: Checks if at least one element in the list satisfies the nested condition(s).
-
ONE: Checks if exactly one element in the list satisfies the nested condition(s).
Example Usage for List Operators:
Example Usage
conditions:
# Basic comparison
- property: diskState
condition: DIFFERENT
value: Unattached
# Numeric comparison
- property: size
condition: SUP
value: 100
# Date comparison
- property: lastModified
condition: DATE_SUP
value: "2024-01-01T00:00:00.000Z"
# Example Usage for List Operators
# Rule to check if SOME disk in a VM is larger than 500 GB.
conditions:
- property: storageProfile.dataDisks # This is a list of disks
condition: SOME
value:
- property: diskSizeGB
condition: SUP
value: 500
# Rule to verify that EXACTLY ONE tag has the key 'owner'.
conditions:
- property: tags # This is a list of tags
condition: ONE
value:
- property: key
condition: EQUAL
value: "owner"
# Rule to verify that got at least ONE disk with the key/value 'project:Kexa'.
conditions:
- property: . # This is a list of disks gathered
condition: SOME
value:
- property: tags # This is a list of tags
condition: ONE
value:
- operator: AND # Check for both key and value (Logical Operators see in the next section)
criteria:
- property: key
condition: EQUAL
value: "project"
- property: value
condition: EQUAL
value: "Kexa"
Logical Operators
Conditions can be combined using logical operators:
AND: All conditions must be trueOR: At least one condition must be trueNOT: Inverts the result of a condition
Example with logical operators:
conditions:
- operator: OR
criteria:
- property: networkAccessPolicy
condition: DIFFERENT
value: AllowAll
- property: encryption.type
condition: EQUAL
value: EncryptionAtRestWithPlatformKey
Date & Time Criteria
You can set up date and time comparisons:
property: string
condition: (
DATE_EQUAL |
DATE_SUP |
DATE_INF |
DATE_SUP_OR_EQUAL |
DATE_INF_OR_EQUAL |
INTERVAL |
DATE_INTERVAL
)
value: 0 0 0 0 0 0 # datetime comparison
date: "YYYY-MM-DDThh:mm:ss.SSSZ" # the datetime format used in the property
Notifications
Configure notifications at the top of your rules file:
alert:
info:
enabled: true
type:
- email
- teams
to:
- admin@example.com
- https://webhook.example.com
warn:
enabled: true
type:
- email
to:
- admin@example.com
error:
enabled: true
type:
- email
- sms
to:
- admin@example.com
- +1234567890
fatal:
enabled: true
type:
- email
- sms
- teams
to:
- admin@example.com
- +1234567890
- https://webhook.example.com
global:
enabled: true
type:
- email
to:
- admin@example.com
conditions:
- level: 0
min: 1
- level: 1
min: 1
- level: 2
min: 1
- level: 3
min: 1
To know more about notifications possibilities, refer to Notifications Addons Documentation
Variabilization
To simplify maintenance, it is possible to variabilize rules either for values or for complete blocks of the YAML file.
The main advantage of setting up a remote repo for your instances is that you can manage and administer general rules for all your productions.
Initialization
Initializing a value or block variable is done in the same way.
At the same indentation level as version or date, insert the name of your variable, a colon then an ampersand, followed by the name of your variable again.
We follow the yaml syntax as much as possible. In our example "name" :
name: &name
Use
The use of a variable can vary, depending on whether you want to use it as a value or as a block.
-
Use as a value: You can insert the name of your variable preceded by an asterisk, anywhere you'd put a conventional value. It's can be usefull to check element like name or quantity
- version: 1.0.0
date: 12-12-2024
name: &name
...
rules:
- name: "Generalize-test"
description : generic test for a project test if X exist
applied: true
level: 1
cloudProvider: XXXX
objectName : YYYY
conditions:
- property : name
condition : EQUAL
value : *name -
Use as a block: You can insert the name of your variable preceded by "
<<: *", anywhere you'd put a key. In this example, we variabilize theappliedandlevelsections to define groups and their level of importance. Another possible example is the notifications section, to variabilize the recipients.- version: 1.0.0
date: 12-12-2024
applied_and_level: &applied_and_level
...
rules:
- name: "Generalize-test"
description : generic test for a project test if A exist
<<: *applied_and_level
cloudProvider: XXXX
objectName : YYYY
conditions:
- property : A
condition : EQUAL
value : A
- name: "Generalize-test-2"
description : generic test for a project test if B exist
<<: *applied_and_level
cloudProvider: XXXX
objectName : YYYY
conditions:
- property : B
condition : EQUAL
value : B
Best Practices
- Use descriptive names and descriptions
- Set appropriate severity levels
- Use logical operators for complex conditions
- Configure notifications appropriately
- Use variabilization for reusable components
- Keep rules focused and specific
- Document complex rules
- Test rules before deployment