Skip to content

Releases: cloudposse/atmos

v1.189.0-rc.0

26 Aug 01:08
7a4abbc
Compare
Choose a tag to compare
v1.189.0-rc.0 Pre-release
Pre-release
  • No changes

v1.188.0

25 Aug 03:51
7a4abbc
Compare
Choose a tag to compare
Update `atmos describe affected` and `atmos describe dependents` commands @aknysh (#1414)

what

  • Update atmos describe affected and atmos describe dependents commands
  • Update docs
  • Add tests

why

  • atmos describe affected --include dependents should respect the flags --process-templates and --process-functions in the dependent components

    • atmos describe affected --include dependents will process templates and YAML functions in the affected components and in the dependents

    • atmos describe affected --include dependents --process-templates=false --process-functions=false will not process templates and YAML functions in the affected components and in the dependents for each affected component

  • Add --exclude-locked flag to atmos describe affected

  • Add --process-templates and --process-functions flags to atmos describe dependents to explicitly disable templates and YAML functions processing (similar to atmos describe affected)

    • atmos describe dependents will process templates and YAML functions in all components
    • atmos describe dependents --process-templates=false --process-functions=false will not process templates and YAML functions in all components
Fix Workflow Error Message @milldr (#1404)

what

  • Fix workflow path for workflow error message

why

  • If the workflow is in a subdirectory, we need to return the path to the workflow, starting from the workflow base dir
Insert workflow-level stack flag before `--` in workflow args @j4zzcat (#1411)

What

  • Updates the workflow utils so that when a workflow-level stack is provided, the generated -s <stack> flag is placed before any -- argument in the command args (instead of always at the end).

The -- marker indicates the end of Atmos CLI arguments; anything after it is passed directly to the underlying tool or script. Appending -s <stack> after -- caused the stack flag to be ignored in such cases.

Why

Before

atmos workflow deploy -- foo bar
# produces args: ["deploy", "--", "foo", "bar", "-s", "my-stack"]
# "-s my-stack" is ignored since it's after `--`

After

atmos workflow deploy -- foo bar
# produces args: ["deploy", "-s", "my-stack", "--", "foo", "bar"]
# stack flag is correctly passed to Atmos

v1.188.0-test.2

20 Aug 18:38
84c42ca
Compare
Choose a tag to compare
v1.188.0-test.2 Pre-release
Pre-release

🚀 Feature Preview Release

This is a feature preview based on an open pull request. It is intended for testing artifacts and validating functionality before the feature is merged.

Warning

This release is temporary and may be removed at any time without notice.

v1.188.0-test.1

20 Aug 18:17
4e70553
Compare
Choose a tag to compare
v1.188.0-test.1 Pre-release
Pre-release

🚀 Feature Preview Release

This is a feature preview based on an open pull request. It is intended for testing artifacts and validating functionality before the feature is merged.

Warning

This release is temporary and may be removed at any time without notice.

v1.188.0-test.0

19 Aug 18:38
fbe6cdb
Compare
Choose a tag to compare
v1.188.0-test.0 Pre-release
Pre-release

🚀 Feature Preview Release

This is a feature preview based on an open pull request. It is intended for testing artifacts and validating functionality before the feature is merged.

Warning

This release is temporary and may be removed at any time without notice.

v1.188.0-rc.0

18 Aug 01:14
26b1147
Compare
Choose a tag to compare
v1.188.0-rc.0 Pre-release
Pre-release
  • No changes

v1.187.0

18 Aug 00:19
26b1147
Compare
Choose a tag to compare
Update `atmos terraform generate planfile` and `atmos terraform plan-diff` commands. Update `depends_on` for component dependencies @aknysh (#1405)

what

  • Update atmos terraform generate planfile and atmos terraform plan-diff commands. Process templates and Atmos YAML functions before executing the commands.

  • Update depends_on for component dependencies. Add stack attribute as one of the context variables in depends_on

  • Update docs

  • Add tests

why

  • The atmos terraform generate planfile and atmos terraform plan-diff commands did not process templates and Atmos YAML functions, but they should

  • Add stack attribute as one of the context variables in depends_on to allow specifying an Atmos stack where the dependent component is provisioned

description

Atmos supports configuring the relationships between components in the same or different stacks. You can define dependencies between components to ensure that components are deployed in the correct order.

You can define component dependencies by using the settings.depends_on section. The section used to define all the Atmos components (in the same or different stacks) that the current component depends on.

The settings.depends_on section is a map of objects. The map keys are just the descriptions of dependencies and can be strings or numbers. Provide meaningful descriptions or numbering so that people can understand what the dependencies are about.

If component is specified, you can provide the other context variables to define an Atmos stack other than the current stack.

For example, you can specify:

  • stack if the component is from a different Atmos stack
  • namespace if the component is from a different Organization
  • tenant if the component is from a different Organizational Unit
  • environment if the component is from a different region
  • stage if the component is from a different account
  • tenant, environment and stage if the component is from a different Atmos stack (e.g. tenant1-ue2-dev)

NOTE:
If stack is specified, it's processed first and the namespace, tenant, environment and stage attributes are ignored.

NOTE:
You can use Atmos Stack Manifest Templating in depends_on.
Atmos processes the templates first, and then detects all the dependencies, allowing you to provide the parameters to
depends_on dynamically.

In the following example, we specify that the component1 component depends on the following:

  • The component2 component in the same Atmos stack as component1
  • The component3 component from the prod stage
  • The component4 component from the tenant1 tenant, ue2 environment and staging stage (tenant1-ue2-staging Atmos stack)
  • The component5 component from the tenant1-ue2-prod Atmos stack
  • The component6 component from the same Atmos stack as component1
  • The component7 component from the same tenant and stage as component1, but uw2 environment
vars:
  tenant: "tenant1"
  environment: "ue1"
  stage: "dev"

components:
  terraform:
    component1:
      settings:
        depends_on:
          1:
            # If the context (`stack`, `namespace`, `tenant`, `environment`, `stage`) is not
            # provided, the `component` is from the same Atmos stack as `component1`
            component: "component2"
          2:
            # `component1` (in any stage) depends on `component3`
            # from the `prod` stage (in any `environment` and any `tenant`)
            component: "component3"
            stage: "prod"
          3:
            # `component1` depends on `component4`
            # from the the `tenant1` tenant, `ue2` environment and `staging` stage
            # (`tenant1-ue2-staging` Atmos stack)
            component: "component4"
            tenant: "tenant1"
            environment: "ue2"
            stage: "staging"
          4:
            # `component1` depends on `component5`
            # from the `tenant1-ue2-prod` Atmos stack
            component: "component5"
            stack: "tenant1-ue2-prod"
          5:
            # `component1` depends on `component6`
            # from the same Atmos stack
            component: "component6"
            stack: "{{ .vars.tenant }}-{{ .vars.environment }}-{{ .vars.stage }}"
          6:
            # `component1` depends on `component7`
            # from the same tenant and stage as `component1`, but `uw2` environment
            component: "component7"
            stack: "{{ .vars.tenant }}-uw2-{{ .vars.stage }}"
      vars:
        enabled: true

Specifying stack

The stack attribute has higher precedence than the other context variables.
If stack is specified, the namespace, tenant, environment and stage attributes are ignored.

As you can see in the examples above, we can use Atmos Stack Manifest Templating in the stack attribute to dynamically specify the stack.

This is useful when configuring
stacks.name_template in atmos.yaml to define and refer to stacks. In this case, you can't use the context variables namespace, tenant, environment and stage in depends_on.

For example, in atmos.yaml, we specify stacks.name_template to define Atmos stacks, and enable templating:

stacks:
  base_path: "stacks"
  name_template: "{{ .settings.context.tenant }}-{{ .settings.context.environment }}-{{ .settings.context.stage }}"

# `Go` templates in Atmos manifests
templates:
  settings:
    enabled: true

NOTE:
In this example, stacks are defined by the settings.context section, not vars.

In the tenant1-uw2-dev Atmos stack, we can use the following depends_on configuration to define the component dependencies:

settings:
  context:
    tenant: "tenant1"
    environment: "uw2"
    stage: "dev"

components:
  terraform:
    vpc:
      vars:
        enabled: true

    tgw/attachment:
      settings:
        depends_on:
          1:
            # `tgw/attachment` depends on the `vpc` component
            # from the same Atmos stack (same tenant, account and region)
            component: vpc
            # NOTE: The same stack can be specified by using exactly the same template as in
            # `stacks.name_template` in `atmos.yaml`, but it's not required and not recommended.
            # If the dependent component is from the same stack, just omit the `stack` attribute completely.
            # stack: "{{ .settings.context.tenant }}-{{ .settings.context.environment }}-{{ .settings.context.stage }}"
          2:
            # `tgw/attachment` depends on the `tgw/hub` components
            # from the same tenant and account, but in `us-east-1` region (`ue1` environment)
            component: tgw/hub
            stack: "{{ .settings.context.tenant }}-ue1-{{ .settings.context.stage }}"

    tgw/cross-region-hub-connector:
      settings:
        depends_on:
          1:
            # `tgw/cross-region-hub-connector` depends on `tgw/hub` components
            # in the same tenant and account, but in `us-east-1` region (`ue1` environment)
            component: tgw/hub
            stack: "{{ .settings.context.tenant }}-ue1-{{ .settings.context.stage }}"

Execute the following Atmos commands to see the component dependencies:

> atmos describe dependents vpc -s tenant1-uw2-dev --pager off
[
  {
    "component": "tgw/attachment",
    "component_type": "terraform",
    "stack": "tenant1-uw2-dev",
    "stack_slug": "tenant1-uw2-dev-tgw-attachment"
  }
]
> atmos describe dependents tgw/hub -s tenant1-ue1-dev --pager off
[
  {
    "component": "tgw/attachment",
    "component_type": "terraform",
    "stack": "tenant1-uw2-dev",
    "stack_slug": "tenant1-uw2-dev-tgw-attachment"
  },
  {
    "component": "tgw/cross-region-hub-connector",
    "component_type": "terraform",
    "stack": "tenant1-uw2-dev",
    "stack_slug": "tenant1-uw2-dev-tgw-cross-region-hub-connector"
  }
]
Add `!store.get` YAML function for arbitrary key retrieval @jamengual (#1352)

what

  • Add the !store.get YAML function, enabling retrieval of arbitrary keys from any supported store (Azure Key Vault, AWS SSM, Redis, Google Secret Manager, Artifactory)

why

  • Unlike the existing !store function, !store.get does not require keys to follow the Atmos stack/component/key naming pattern. Users can retrieve any key by specifying its exact name or path.

usage examples

# Retrieve a key from Redis by its exact name
my_config: !store.get redis global-config

# Retrieve a secret from Azure Key Vault by its name
my_secret: !store.get azure-keyvault my-arbitrary-secret

# Retrieve a parameter from AWS SSM by its full path
ssm_value: !store.get aws-ssm-parameter-store /custom/path/to/parameter

Notable Differences from !store

  • !store.get does not construct keys using stack/component/key; it expects the full key or path.
  • Useful for retrieving values stored outside of Atmos or not following the standard naming convention.
Move `github.event.release.prerelease` logic to shared workflows @goruha (#1400)

what

  • Move github.event.release.prerelease logic to shared workflows

why

  • Having a single point responsible for the conditions

v1.187.0-rc.0

08 Aug 01:14
9179bd8
Compare
Choose a tag to compare
v1.187.0-rc.0 Pre-release
Pre-release
  • No changes

v1.186.0

07 Aug 23:00
9179bd8
Compare
Choose a tag to compare
Add native Packer support (Atmos loves Packer) @aknysh (#1394)

what

why

  • Use the power of Atmos components, stacks, imports, inheritance, templating and YAML functions to configure and provision Packer components to build machine images for multiple cloud platforms from Packer templates

description

Atmos natively supports HashiCorp Packer and lets you create identical machine images for multiple platforms from a single source template using the power of Atmos components, stacks, imports, inheritance, templating and YAML functions. It's compatible with every version of Packer and designed to work with multiple different versions of it concurrently.

Configure Packer in atmos.yaml

base_path: "./"

components:
  packer:
    # Can also be set using 'ATMOS_COMPONENTS_PACKER_COMMAND' ENV var, or '--packer-command' command-line argument
    command: packer
    # Can also be set using 'ATMOS_COMPONENTS_PACKER_BASE_PATH' ENV var, or '--packer-dir' command-line argument
    base_path: "components/packer"

stacks:
  base_path: "stacks"
  included_paths:
    - "deploy/**/*"
  excluded_paths:
    - "**/_defaults.yaml"
  name_template: "{{ .vars.stage }}"

Add Packer template (Packer component)

packer {
  required_plugins {
    # https://developer.hashicorp.com/packer/integrations/hashicorp/amazon
    amazon = {
      source  = "github.com/hashicorp/amazon"
      version = "~> 1"
    }
  }
}

variable "region" {
  type        = string
  description = "AWS Region"
}

variable "stage" {
  type    = string
  default = null
}

variable "ami_org_arns" {
  type        = list(string)
  description = "List of Amazon Resource Names (ARN) of AWS Organizations that have access to launch the resulting AMI(s). By default no organizations have permission to launch the AMI"
  default     = []
}

variable "ami_ou_arns" {
  type        = list(string)
  description = "List of Amazon Resource Names (ARN) of AWS Organizations organizational units (OU) that have access to launch the resulting AMI(s). By default no organizational units have permission to launch the AMI."
  default     = []
}

variable "ami_users" {
  type        = list(string)
  description = "List of account IDs that have access to launch the resulting AMI(s). By default no additional users other than the user creating the AMI has permissions to launch it."
  default     = []
}

# https://developer.hashicorp.com/packer/integrations/hashicorp/amazon#authentication
variable "assume_role_arn" {
  type        = string
  description = "Amazon Resource Name (ARN) of the IAM Role to assume. Refer to https://developer.hashicorp.com/packer/integrations/hashicorp/amazon#authentication"
}

variable "provisioner_shell_commands" {
  type        = list(string)
  description = "List of commands to execute on the machine that Packer builds"
  default     = []
}

source "amazon-ebs" "al2023" {
  ami_name      = var.ami_name
  source_ami    = var.source_ami
  instance_type = var.instance_type
  region        = var.region
  ssh_username  = var.ssh_username
  ami_org_arns  = var.ami_org_arns
  ami_ou_arns   = var.ami_ou_arns
  ami_users     = var.ami_users
  kms_key_id    = var.kms_key_arn
  encrypt_boot  = var.encrypt_boot

  force_deregister      = var.force_deregister
  force_delete_snapshot = var.force_delete_snapshot

  associate_public_ip_address = var.associate_public_ip_address

  ami_block_device_mappings {
    device_name           = "/dev/xvda"
    volume_size           = var.volume_size
    volume_type           = var.volume_type
    delete_on_termination = true
  }

  assume_role {
    role_arn         = var.assume_role_arn
    session_name     = var.assume_role_session_name
    duration_seconds = var.assume_role_duration_seconds
  }

  aws_polling {
    delay_seconds = 5
    max_attempts  = 100
  }

  tags = var.ami_tags
}

build {
  sources = ["source.amazon-ebs.al2023"]

  provisioner "shell" {
    inline = var.provisioner_shell_commands
  }

  # https://developer.hashicorp.com/packer/tutorials/docker-get-started/docker-get-started-post-processors
  # https://developer.hashicorp.com/packer/docs/post-processors
  # https://developer.hashicorp.com/packer/docs/post-processors/manifest
  post-processor "manifest" {
    output     = var.manifest_file_name
    strip_path = var.manifest_strip_path
  }
}

Configure defaults for the Packer component in the catalog

components:
  packer:
    aws/bastion:
      settings:
        packer:
          template: "main.pkr.hcl"
          source_ami: "ami-0013ceeff668b979b"
          source_ami_name: "al2023-ami-2023.7.20250527.1-kernel-6.12-arm64"
          source_ami_description: "Amazon Linux 2023 AMI 2023.7.20250527.1 arm64 HVM kernel-6.12"
          source_ami_owner_account_id: "137112412989"
          region: "us-east-2"
          org_id: "o-xxxxxxxxx"
          org_management_account_id: "xxxxxxxxxxxx"
      metadata:
        component: aws/bastion
      vars:
        # https://masterminds.github.io/sprig/date.html
        ami_name: "bastion-al2023-{{ now | unixEpoch }}"
        source_ami: "{{ .settings.packer.source_ami }}"
        region: "{{ .settings.packer.region }}"
        ami_org_arns:
          - "arn:aws:organizations::{{ .settings.packer.org_management_account_id }}:organization/{{ .settings.packer.org_id }}"
        ami_ou_arns: []
        ami_users: []
        kms_key_arn: null
        encrypt_boot: false
        ssh_username: "ec2-user"
        associate_public_ip_address: true
        volume_type: "gp3"
        skip_create_ami: false
        manifest_file_name: "manifest.json"
        manifest_strip_path: false
        assume_role_session_name: "atmos-packer"
        assume_role_duration_seconds: 1800
        force_deregister: false
        force_delete_snapshot: false
        # SSM Agent is pre-installed on AL2023 AMIs but should be enabled explicitly as done above.
        # `dnf clean all` removes cached metadata and packages to reduce AMI size.
        # `cloud-init clean` ensures the image will boot as a new instance on the next launch.
        provisioner_shell_commands:
          # Enable and start the SSM agent (already installed by default on AL2023)
          - "sudo systemctl enable --now amazon-ssm-agent"
          # Install packages, clean metadata and cloud-init
          - "sudo -E bash -c 'dnf install -y jq && dnf clean all && cloud-init clean'"
          # Install other packages
        ami_tags:
          SourceAMI: "{{ .settings.packer.source_ami }}"
          SourceAMIName: "{{ .settings.packer.source_ami_name }}"
          SourceAMIDescription: "{{ .settings.packer.source_ami_description }}"
          SourceAMIOwnerAccountId: "{{ .settings.packer.source_ami_owner_account_id }}"
          ScanStatus: pending

Define Atmos nonprod and prod stacks

vars:
  stage: nonprod

import:
  - catalog/aws/bastion/defaults

components:
  packer:
    aws/bastion:
      vars:
        # Define the variables specific to the `nonprod` account
        instance_type: "t4g.small"
        volume_size: 8
        assume_role_arn: "arn:aws:iam::NONPROD_ACCOUNT_ID:role/ROLE_NAME"
        ami_tags:
          Stage: nonprod
vars:
  stage: prod

import:
  - catalog/aws/bastion/defaults

components:
  packer:
    aws/bastion:
      vars:
        # Define the variables specific to the `prod` account
        instance_type: "t4g.medium"
        volume_size: 16
        assume_role_arn: "arn:aws:iam::PROD_ACCOUNT_ID:role/ROLE_NAME"
        ami_tags:
          Stage: prod

Execute Atmos Packer commands

> atmos packer version

Packer v1.14.1
# https://developer.hashicorp.com/packer/docs/commands/validate

> atmos packer validate aws/bastion -s nonprod

The configuration is valid.
# https://developer.hashicorp.com/packer/docs/commands/inspect

> atmos packer inspect aws/bastion -s nonprod

Packer Inspect: HCL2 mode

> input-variables:

var.ami_name: "bastion-al2023-1754457104"
var.ami_org_arns: "[\n  \"arn:aws:organizations::xxxxxxxxxxxx:organization/o-xxxxxxxxx\",\n]"
var.ami_ou_arns: "[]"
var.ami_tags: "{\n  \"ScanStatus\" = \"pending\"\n  \"SourceAMI\" = \"ami-0013ceeff668b979b\"\n  \"SourceAMIDescription\" = \"Amazon Linux 2023 AMI 2023.7.20250527.1 arm64 HVM kernel-6.12\"\n  \"SourceAMIName\" = \"al2023-ami-2023.7.20250527.1-kernel-6.12-arm64\"\n  \"SourceAMIOwnerAccountId\" = \"137112412989\"\n  \"Stage\" = \"nonprod\"\n}"
var.ami_users: "[]"

> local-variables:

> builds:

  > <0>:
    sources:
      amazon-ebs.al2023

    provisioners:
      shell

    post-processors:
      0:
        manifest
# https://developer.hashicorp.com/packer/docs/commands/init

> atmos packer init aws/bastion -s nonprod

Installed plugin github.com/hashicorp/amazon v1.3.9 in "~/.config/packer/plugins/github.com/hashicorp/amazon/packer-plugin-amazon_v1.3.9_x5.0_darwin_arm64"
# https://developer.hashicorp.com/packer/docs/commands/build

> atmos packer build aws/bastion -s nonprod

amazon-ebs.al2023:

==> amazon-ebs.al2023: Prevalidating any provided VPC information
==> amazon-ebs.al2023: Prevalidating AMI Name: bastion-al2023-1754025080
==> amazon-ebs.al2023: Found Image ID: ami-0013ceeff668b979b
==> amazon-ebs.al2023: Setting public IP add...
Read more

v1.185.1-test.3

07 Aug 19:05
aca35dd
Compare
Choose a tag to compare
v1.185.1-test.3 Pre-release
Pre-release

🚀 Feature Preview Release

This is a feature preview based on an open pull request. It is intended for testing artifacts and validating functionality before the feature is merged.

Warning

This release is temporary and may be removed at any time without notice.