From atmos
Validates Atmos stack configurations using JSON Schema, OPA/Rego policies, and EditorConfig before Terraform plan/apply. Supports component/stack validation commands.
npx claudepluginhub cloudposse/atmos --plugin atmosThis skill uses the workspace's default tool permissions.
Atmos provides a built-in validation framework that enforces policies and schema constraints on stack
Provides JSON Schemas for Atmos stack manifests and configs, enabling IDE auto-completion, validation, SchemaStore integration, and runtime checks in Atmos CLI.
Enforces policy-as-code using Open Policy Agent (OPA) and Rego for security, compliance validation, Kubernetes admissions, CI/CD checks, and config auditing.
Analyzes projects for config files in JSON, YAML, TOML, ENV formats. Validates correctness, detects security issues like exposed secrets, ensures env consistency, and generates schemas.
Share bugs, ideas, or general feedback.
Atmos provides a built-in validation framework that enforces policies and schema constraints on stack configurations before infrastructure is provisioned. Validation ensures clean, correct, and compliant configurations across teams and environments. Atmos supports three types of native validation:
Validation runs automatically before atmos terraform plan and atmos terraform apply, preventing
misconfigured infrastructure from being provisioned. It can also run on-demand using the
atmos validate component and atmos validate stacks commands.
atmos validate componentValidates a specific component in a stack against configured validation rules:
# Validate using rules defined in settings.validation
atmos validate component vpc -s plat-ue2-prod
# Validate with explicit schema path and type
atmos validate component vpc -s plat-ue2-prod \
--schema-path vpc/validate-vpc-component.rego \
--schema-type opa
# Validate with OPA and additional module paths
atmos validate component vpc -s plat-ue2-dev \
--schema-path vpc/validate-vpc-component.rego \
--schema-type opa \
--module-paths catalog/constants
# Validate with a timeout
atmos validate component vpc -s plat-ue2-dev --timeout 15
If --schema-path and --schema-type are not provided on the command line, Atmos uses the
settings.validation section from the component's stack configuration.
atmos validate stacksValidates all stack configurations and YAML syntax:
atmos validate stacks
This command checks:
If the same component is defined in multiple stack manifest files for the same stack with different configurations, Atmos reports it as an error.
atmos.yamlConfigure the base paths for validation schemas in atmos.yaml:
# atmos.yaml
schemas:
# JSON Schema validation
jsonschema:
# Supports absolute and relative paths
# Can be set via ATMOS_SCHEMAS_JSONSCHEMA_BASE_PATH env var
base_path: "stacks/schemas/jsonschema"
# OPA/Rego validation
opa:
# Supports absolute and relative paths
# Can be set via ATMOS_SCHEMAS_OPA_BASE_PATH env var
base_path: "stacks/schemas/opa"
# Atmos manifest validation
atmos:
# JSON Schema for validating Atmos manifests themselves
# Can be set via ATMOS_SCHEMAS_ATMOS_MANIFEST env var
manifest: "stacks/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json"
Define validation rules in the settings.validation section of component configurations:
components:
terraform:
vpc:
settings:
validation:
# JSON Schema validation step
validate-vpc-component-with-jsonschema:
schema_type: jsonschema
schema_path: "vpc/validate-vpc-component.json"
description: Validate 'vpc' component variables using JSON Schema
# OPA policy validation step
check-vpc-component-config-with-opa-policy:
schema_type: opa
schema_path: "vpc/validate-vpc-component.rego"
module_paths:
- "catalog/constants"
description: Check 'vpc' component configuration using OPA policy
disabled: false
timeout: 10
Each validation step supports these properties:
| Property | Type | Description |
|---|---|---|
schema_type | string | jsonschema or opa |
schema_path | string | Path to the schema file (absolute or relative to base_path) |
module_paths | list | (OPA only) Additional Rego module paths for imports |
description | string | Human-readable description of the validation step |
disabled | boolean | Set to true to skip this step (default: false) |
timeout | integer | Timeout in seconds for the validation step |
All validation steps must pass for the component to be provisioned. If any step fails, Atmos blocks the operation with the validation error messages.
JSON Schema validates the structure, types, and required fields of component configurations. Atmos supports the JSON Schema 2020-12 specification.
Place schema files in the schemas.jsonschema.base_path directory:
{
"$id": "vpc-component",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "vpc component validation",
"description": "JSON Schema for the 'vpc' Atmos component.",
"type": "object",
"properties": {
"vars": {
"type": "object",
"properties": {
"region": {
"type": "string"
},
"ipv4_primary_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",
"ipv4_primary_cidr_block",
"map_public_ip_on_launch"
]
}
}
}
The entire component configuration is passed as the JSON document. The schema validates against
the full configuration including vars, settings, env, backend, and other sections.
The Open Policy Agent (OPA) provides policy-as-code validation using the Rego language. OPA policies enable complex business rule validation that goes beyond structural schema checks.
All Atmos OPA policies must:
package atmoserrors rules that return a set of error message strings (sets are serialized as arrays in OPA query results)package atmos
import future.keywords.in
# Block public IPs in production
errors[message] {
input.vars.stage == "prod"
input.vars.map_public_ip_on_launch == true
message = "Mapping public IPs on launch is not allowed in 'prod'"
}
# Enforce naming conventions
errors[message] {
not re_match("^[a-zA-Z0-9]{2,20}$", input.vars.name)
message = "Component name must be 2-20 alphanumeric characters"
}
The input object contains the full component configuration as returned by
atmos describe component. Key fields include:
input.vars -- Component variablesinput.settings -- Component settingsinput.env -- Environment variablesinput.backend -- Backend configurationinput.metadata -- Component metadatainput.workspace -- Terraform workspace nameWhen Atmos executes commands like terraform plan or terraform apply, additional context
is provided to OPA policies:
input.process_env -- Map of environment variables in the current processinput.cli_args -- List of CLI arguments (e.g., ["terraform", "apply"])input.tf_cli_vars -- Map of variables from command-line -var argumentsinput.env_tf_cli_args -- List of arguments from TF_CLI_ARGS env varinput.env_tf_cli_vars -- Map of variables from TF_CLI_ARGS env varThis enables context-aware policies such as:
package atmos
# Don't allow terraform apply if foo is set to "foo"
errors[message] {
count(input.cli_args) >= 2
input.cli_args[0] == "terraform"
input.cli_args[1] == "apply"
input.vars.foo == "foo"
message = "Cannot apply when 'foo' variable is set to 'foo'"
}
Atmos supports splitting OPA policies across multiple Rego files. Define reusable constants and helper functions in separate files:
# stacks/schemas/opa/catalog/constants/constants.rego
package atmos.constants
vpc_dev_max_azs_error := "In 'dev', only 2 Availability Zones are allowed"
vpc_name_regex := "^[a-zA-Z0-9]{2,20}$"
Import them in your main policy:
package atmos
import data.atmos.constants.vpc_dev_max_azs_error
import data.atmos.constants.vpc_name_regex
errors[vpc_dev_max_azs_error] {
input.vars.stage == "dev"
count(input.vars.availability_zones) != 2
}
Specify the module paths in the component's validation configuration:
settings:
validation:
check-vpc:
schema_type: opa
schema_path: "vpc/validate-vpc-component.rego"
module_paths:
- "catalog/constants"
If module_paths specifies a folder, Atmos recursively loads all .rego files from that
folder and its subfolders.
Atmos includes an embedded JSON Schema for validating the structure of Atmos manifests themselves (not component vars, but the manifest file format). To override the embedded schema:
# atmos.yaml
schemas:
atmos:
manifest: "stacks/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json"
# Also supports URLs:
# manifest: "https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json"
The manifest schema can also be provided via:
ATMOS_SCHEMAS_ATMOS_MANIFEST--schemas-atmos-manifestAtmos supports the EditorConfig Checker for ensuring consistent coding styles. This validates
adherence to rules defined in .editorconfig files across the project.
Add a validation step early in your CI/CD pipeline:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Atmos
uses: cloudposse/github-action-setup-atmos@v2
with:
atmos-version: 1.88.0
- name: Validate All Stacks
run: atmos validate stacks
- name: Validate Specific Components
run: |
atmos validate component vpc -s plat-ue2-dev
atmos validate component vpc -s plat-ue2-prod
Atmos automatically runs validation before terraform plan and terraform apply. If any
validation policy fails, the operation is blocked:
$ atmos terraform apply vpc -s plat-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 stacks before plan/applydisabled: true to temporarily skip a validation step during migrationpackage atmos
errors[message] {
required_tags := ["Environment", "Team", "CostCenter"]
tag := required_tags[_]
not input.vars.tags[tag]
message = sprintf("Required tag '%s' is missing", [tag])
}
package atmos
errors[message] {
input.vars.stage == "dev"
input.vars.instance_count > 3
message = sprintf("Dev environment limited to 3 instances, got %d", [input.vars.instance_count])
}
errors[message] {
input.vars.stage == "prod"
input.vars.instance_count < 2
message = sprintf("Prod environment requires at least 2 instances, got %d", [input.vars.instance_count])
}
package atmos
errors[message] {
not re_match("^[a-z][a-z0-9-]*[a-z0-9]$", input.vars.name)
message = sprintf("Name '%s' must be lowercase alphanumeric with hyphens, starting with a letter", [input.vars.name])
}
package atmos
errors[message] {
count(input.cli_args) >= 2
input.cli_args[0] == "terraform"
input.cli_args[1] == "apply"
input.process_env.ENVIRONMENT == "production"
not input.process_env.DEPLOYMENT_APPROVED
message = "Production deployments require DEPLOYMENT_APPROVED environment variable"
}
package atmos
errors[message] {
input.vars.stage == "prod"
cidr := input.vars.allowed_cidr_blocks[_]
cidr == "0.0.0.0/0"
message = "Open CIDR blocks (0.0.0.0/0) are not allowed in production"
}
\\. not \.import future.keywords.in for the in keywordpackage atmos declaration is required in all Atmos OPA policieserrors output -- if it contains any strings, the policy fails