Skip to content

v1.38.0

Compare
Choose a tag to compare
@aknysh aknysh released this 22 Jun 20:09
· 85 commits to master since this release
1a5e322

what

  • Refactor Atmos components validation with OPA
  • Allow creating a catalog of reusable Rego modules, constants and helper functions to be used in OPA policies
  • Update docs

why

Atmos supports OPA policies for component validation in a single Rego file and in multiple Rego files.

As shown in the example below, 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.

example

Add the settings.validation section to the component's config:

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 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)
}

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