Component Validation
Validation is critical to maintaining hygienic configurations in distributed team environments.
Atmos component validation allows:
Validate component config (
vars
,settings
,backend
,env
, and other sections) using JSON SchemaCheck if the component config (including relations between different component variables) is correct to allow or deny component provisioning using OPA/Rego policies
Refer to atmos validate component CLI command for more information
JSON Schema
Atmos has native support for JSON Schema, which can validate the schema of configurations. JSON Schema is an industry standard and provides a vocabulary to annotate and validate JSON documents for correctness.
This is powerful stuff: because you can define many schemas, it's possible to validate components differently for different environments or teams.
Open Policy Agent (OPA)
The Open Policy Agent (OPA, pronounced “oh-pa”) is another open-source industry standard that provides a general-purpose policy engine to unify policy enforcement across your stacks. The OPA language (Rego) is a high-level declarative language for specifying policy as code. Atmos has native support for the OPA decision-making engine to enforce policies across all the components in your stacks (e.g. for microservice configurations).
Usage
Atmos validate component
command supports --schema-path
, --schema-type
and --module-paths
command line arguments.
If the arguments are not provided, Atmos will try to find and use the settings.validation
section defined in the component's YAML config.
atmos validate component infra/vpc -s tenant1-ue2-prod --schema-path vpc/validate-infra-vpc-component.json --schema-type jsonschema
atmos validate component infra/vpc -s tenant1-ue2-prod --schema-path vpc/validate-infra-vpc-component.rego --schema-type opa
atmos validate component infra/vpc -s tenant1-ue2-dev --schema-path vpc/validate-infra-vpc-component.rego --schema-type opa --module-paths catalog/constants
atmos validate component infra/vpc -s tenant1-ue2-dev --schema-path vpc/validate-infra-vpc-component.rego --schema-type opa --module-paths catalog
atmos validate component infra/vpc -s tenant1-ue2-prod
atmos validate component infra/vpc -s tenant1-ue2-dev
atmos validate component infra/vpc -s tenant1-ue2-dev --timeout 15
Configure Component Validation
In atmos.yaml
, add the schemas
config:
# Validation schemas (for validating atmos stacks and components)
schemas:
# https://json-schema.org
jsonschema:
# Can also be set using `ATMOS_SCHEMAS_JSONSCHEMA_BASE_PATH` ENV var, or `--schemas-jsonschema-dir` command-line arguments
# Supports both absolute and relative paths
base_path: "stacks/schemas/jsonschema"
# https://www.openpolicyagent.org
opa:
# Can also be set using `ATMOS_SCHEMAS_OPA_BASE_PATH` ENV var, or `--schemas-opa-dir` command-line arguments
# Supports both absolute and relative paths
base_path: "stacks/schemas/opa"
In the component YAML config, add the settings.validation
section:
components:
terraform:
infra/vpc:
settings:
# Validation
# Supports JSON Schema and OPA policies
# All validation steps must succeed to allow the component to be provisioned
validation:
validate-infra-vpc-component-with-jsonschema:
schema_type: jsonschema
# 'schema_path' can be an absolute path or a path relative to 'schemas.jsonschema.base_path' defined in `atmos.yaml`
schema_path: "vpc/validate-infra-vpc-component.json"
description: Validate 'infra/vpc' component variables using JSON Schema
check-infra-vpc-component-config-with-opa-policy:
schema_type: opa
# 'schema_path' can be an absolute path or a path relative to 'schemas.opa.base_path' defined in `atmos.yaml`
schema_path: "vpc/validate-infra-vpc-component.rego"
# An array of filesystem paths (folders or individual files) to the additional modules for schema validation
# Each path can be an absolute path or a path relative to `schemas.opa.base_path` defined in `atmos.yaml`
# In this example, we have the additional Rego modules in `stacks/schemas/opa/catalog/constants`
module_paths:
- "catalog/constants"
description: Check 'infra/vpc' component configuration using OPA policy
# Set `disabled` to `true` to skip the validation step
# `disabled` is set to `false` by default, the step is allowed if `disabled` is not declared
disabled: false
# Validation timeout in seconds
timeout: 10
Add the following JSON Schema in the file stacks/schemas/jsonschema/vpc/validate-infra-vpc-component.json
:
{
"$id": "infra-vpc-component",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "infra/vpc component validation",
"description": "JSON Schema for infra/vpc atmos component.",
"type": "object",
"properties": {
"vars": {
"type": "object",
"properties": {
"region": {
"type": "string"
},
"cidr_block": {
"type": "string",
"pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$"
},
"map_public_ip_on_launch": {
"type": "boolean"
}
},
"additionalProperties": true,
"required": [
"region",
"cidr_block",
"map_public_ip_on_launch"
]
}
}
}
Add the following Rego package in the file stacks/schemas/opa/catalog/constants/constants.rego
:
package atmos.constants
vpc_dev_max_availability_zones_error_message := "In 'dev', only 2 Availability Zones are allowed"
vpc_prod_map_public_ip_on_launch_error_message := "Mapping public IPs on launch is not allowed in 'prod'. Set 'map_public_ip_on_launch' variable to 'false'"
vpc_name_regex := "^[a-zA-Z0-9]{2,20}$"
vpc_name_regex_error_message := "VPC name must be a valid string from 2 to 20 alphanumeric chars"
Add the following OPA policy in the file stacks/schemas/opa/vpc/validate-infra-vpc-component.rego
:
# Atmos looks for the 'errors' (array of strings) output from all OPA policies
# If the 'errors' output contains one or more error messages, Atmos considers the policy failed
# 'package atmos' is required in all Atmos OPA policies
package atmos
import future.keywords.in
# Import the constants from the file `stacks/schemas/opa/catalog/constants/constants.rego`
import data.atmos.constants.vpc_dev_max_availability_zones_error_message
import data.atmos.constants.vpc_prod_map_public_ip_on_launch_error_message
import data.atmos.constants.vpc_name_regex
import data.atmos.constants.vpc_name_regex_error_message
# In production, don't allow mapping public IPs on launch
errors[vpc_prod_map_public_ip_on_launch_error_message] {
input.vars.stage == "prod"
input.vars.map_public_ip_on_launch == true
}
# In 'dev', only 2 Availability Zones are allowed
errors[vpc_dev_max_availability_zones_error_message] {
input.vars.stage == "dev"
count(input.vars.availability_zones) != 2
}
# Check VPC name
errors[vpc_name_regex_error_message] {
not re_match(vpc_name_regex, input.vars.name)
}
Atmos supports OPA policies for components validation in a single Rego file and in multiple Rego files.
As shown in the example above, you can define some Rego constants, modules and helper functions in a separate
file stacks/schemas/opa/catalog/constants/constants.rego
, and then import them into the main policy
file stacks/schemas/opa/vpc/validate-infra-vpc-component.rego
.
You also need to specify the module_paths
attribute in the component's settings.validation
section.
The module_paths
attribute is an array of filesystem paths (folders or individual files) to the additional modules for schema validation.
Each path can be an absolute path or a path relative to schemas.opa.base_path
defined in atmos.yaml
.
If a folder is specified in module_paths
, Atmos will recursively process the folder and all its sub-folders and load all Rego files into the OPA
engine.
This allows you to separate the common OPA modules, constants and helper functions into a catalog of reusable Rego modules, and to structure your OPA policies to make them DRY.
Run the following commands to validate the component in the stacks:
> atmos validate component infra/vpc -s tenant1-ue2-prod
Mapping public IPs on launch is not allowed in 'prod'. Set 'map_public_ip_on_launch' variable to 'false'
exit status 1
> atmos validate component infra/vpc -s tenant1-ue2-dev
In 'dev', only 2 Availability Zones are allowed
VPC name must be a valid string from 2 to 20 alphanumeric chars
exit status 1
> atmos validate component infra/vpc -s tenant1-ue2-staging
Validate 'infra/vpc' component variables using JSON Schema
{
"valid": false,
"errors": [
{
"keywordLocation": "",
"absoluteKeywordLocation": "file:///examples/complete/stacks/schemas/jsonschema/infra-vpc-component#",
"instanceLocation": "",
"error": "doesn't validate with file:///examples/complete/stacks/schemas/jsonschema/infra-vpc-component#"
},
{
"keywordLocation": "/properties/vars/properties/cidr_block/pattern",
"absoluteKeywordLocation": "file:///examples/complete/stacks/schemas/jsonschema/infra-vpc-component#/properties/vars/properties/cidr_block/pattern",
"instanceLocation": "/vars/cidr_block",
"error": "does not match pattern '^([0-9]{1,3}\\\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$'"
}
]
}
exit status 1
Try to run the following commands to provision the component in the stacks:
atmos terraform apply infra/vpc -s tenant1-ue2-prod
atmos terraform apply infra/vpc -s tenant1-ue2-dev
Since the OPA validation policies don't pass, Atmos does not allow provisioning the component in the stacks: