Make Policies Flexible with Variants
Use variants to change what a policy checks based on different conditions
Variants are checks that behave differently based on conditions you define. They're alternative versions of checks.
For example, suppose you want to ensure that Remote Desktop Protocol (RDP) is restricted from the internet. You want to perform this check both in GCP projects and in Terraform files. You can do this by creating one variant for GCP projects and another for Terraform files:
-
The GCP variant queries if the asset is a GCP project and checks RDP access using the GCP resource.
-
The Terraform variant queries if the asset is a Terraform file and checks RDP access using the Terraform resource.
-
If the asset is neither a GCP project nor a Terraform file, cnspec doesn't execute an RDP check.
Filters
cnspec relies on filters to determine which variant to run against an asset. A filter is a condition written in MQL. Any fields you can query about any resources can be the basis for a filter.
To learn more about filters, read Limit Target Assets with Filters.
Create variants
A bundle has two pieces:
- The policy's
groupsreference the parent check by UID. - The top-level
queriessection holds the parent check (with itsvariantslist) and each variant's definition (with its filter and MQL).
policies:
- uid: okta-security-example-with-variants
name: Example of a policy that uses variants
version: '1.0.0'
scoring_system: highest impact
authors:
- name: Lunalectric
email: security@lunalectric.com
groups:
- title: Password requirements
checks:
- uid: password-minimum-length
queries:
- uid: password-minimum-length
title: Minimum password length
impact: 30
variants:
- uid: password-minimum-length-runtime
- uid: password-minimum-length-terraform-hcl
- uid: password-minimum-length-terraform-plan
- uid: password-minimum-length-terraform-state
- uid: password-minimum-length-runtime
title: Minimum password length - runtime variant
filters: asset.platform == "okta-org"
impact: 30
mql: |
okta.policies.password.all( settings['password']['complexity']['minLength'] >= 15 )
- uid: password-minimum-length-terraform-hcl
title: Minimum password length - Terraform HCL variant
filters: asset.platform == "terraform-hcl" && terraform.providers.one( nameLabel == "okta" )
impact: 30
mql: |
terraform.resources.where( nameLabel == /okta_policy_password/ ).all( arguments['password_min_length'] == /var/ || arguments['password_min_length'] >= 15 )
- uid: password-minimum-length-terraform-plan
title: Minimum password length - Terraform plan variant
filters: asset.platform == "terraform-plan" && terraform.plan.resourceChanges.contains( providerName == /okta/ )
impact: 30
mql: |
terraform.plan.resourceChanges.where( type == /okta_policy_password/ ).all( change.after['password_min_length'] >= 15 )
- uid: password-minimum-length-terraform-state
title: Minimum password length - Terraform state variant
filters: asset.platform == "terraform-state" && terraform.state.resources.contains( type == /okta_policy_password/ )
impact: 30
mql: |
terraform.state.resources.where( type == /okta_policy_password/ ).all( values['password_min_length'] >= 15 )The groups block on lines 9-12 includes the password-minimum-length check in the policy. Lines 17-21 list the four variants for that check:
- Lines 22-27 define the
password-minimum-length-runtimevariant. The filter on line 24 tells cnspec to run this variant only when the asset is an Okta organization. Line 27 is the check to run when that filter matches. - Lines 28-33 define the
password-minimum-length-terraform-hclvariant. The filter on line 30 tells cnspec to run this variant only on Okta Terraform HCL files. Line 33 is the check to run. - Lines 34-39 define the
password-minimum-length-terraform-planvariant. The filter on line 36 tells cnspec to run this variant only on Okta Terraform plans. Line 39 is the check to run. - Lines 40-45 define the
password-minimum-length-terraform-statevariant. The filter on line 42 tells cnspec to run this variant only on Okta Terraform state files. Line 45 is the check to run.
Use one property for multiple variants
Often you use variants to ensure that different types of assets have one common property, as in the example above. All of the variants in the okta-security-example-with-variants policy check that the minimum password length is 15; they just check the value using different resources for different assets.
For efficiency and easier maintenance, you can write all four variants to use one property instead of defining 15 multiple times:
policies:
- uid: okta-security-example-with-variants
name: Example of a policy that uses variants
version: '1.0.0'
scoring_system: highest impact
authors:
- name: Lunalectric
email: security@lunalectric.com
groups:
- title: Password requirements
checks:
- uid: password-minimum-length
queries:
- uid: password-minimum-length
title: Minimum password length
impact: 30
variants:
- uid: password-minimum-length-runtime
- uid: password-minimum-length-terraform-hcl
- uid: password-minimum-length-terraform-plan
- uid: password-minimum-length-terraform-state
- uid: password-minimum-length-runtime
title: Minimum password length - runtime variant
filters: asset.platform == "okta-org"
impact: 30
mql: |
okta.policies.password.all( settings['password']['complexity']['minLength'] >= props.minPass )
- uid: password-minimum-length-terraform-hcl
title: Minimum password length - Terraform HCL variant
filters: asset.platform == "terraform-hcl" && terraform.providers.one( nameLabel == "okta" )
impact: 30
mql: |
terraform.resources.where( nameLabel == /okta_policy_password/ ).all( arguments['password_min_length'] == /var/ || arguments['password_min_length'] >= props.minPass )
- uid: password-minimum-length-terraform-plan
title: Minimum password length - Terraform plan variant
filters: asset.platform == "terraform-plan" && terraform.plan.resourceChanges.contains( providerName == /okta/ )
impact: 30
mql: |
terraform.plan.resourceChanges.where( type == /okta_policy_password/ ).all( change.after['password_min_length'] >= props.minPass )
- uid: password-minimum-length-terraform-state
title: Minimum password length - Terraform state variant
filters: asset.platform == "terraform-state" && terraform.state.resources.contains( type == /okta_policy_password/ )
impact: 30
mql: |
terraform.state.resources.where( type == /okta_policy_password/ ).all( values['password_min_length'] >= props.minPass )
props:
- uid: minPass
title: Minimum password length
mql: '15'Tip: To check for errors in the policy bundles you write, run
cnspec policy lint BUNDLE-NAME.mql.yaml. For BUNDLE-NAME, substitute the name of your file.
To learn more about properties, read Define Properties.
Next steps
-
If you're ready to create your own policy: To learn how to set up, validate, and store policy bundles, read Manage Policies.
-
Learn how to write MQL queries and checks.
-
Read about all the different resources from which MQL can retrieve information.