Tags and Labels: a First-Class Way to Categorize and Select Anything in Atmos
Your stack hierarchy picks one way to organize your infrastructure — org, account, region, component type — and it can only pick one. vpc in stacks/orgs/acme/prod/network.yaml tells you where it lives in that tree; it doesn't tell you it's tier-1, or that platform owns it, or that it's in scope for SOX. Those characteristics don't belong to one branch of the tree — they apply across many stacks and many components at once, and a single component is usually several of them simultaneously. Your AWS accounts and auth identities have the same problem: prod-admin doesn't tell you it's the production one, or the elevated one, until you already know that.
Tags and labels give components that organizational context directly — components get both; auth identities and providers get tags — so you can select and act on infrastructure by what it is instead of by where you filed it.
The Problem
A hierarchy can only organize infrastructure one way, but you need to operate on it along lines that hierarchy doesn't capture:
- A component's path describes its place in the tree, not what it is. It tells you the org, account, and region; it says nothing about tier, ownership, or compliance scope — and those apply across stacks and component types, not within one branch.
- That context ended up living outside the system instead of on the resource. A
--queryexpression like.settings.tier == "network"encoded "tier-1" for one command; a hand-maintained--componentslist encoded it for another. Neither traveled with the component, and both went stale the moment something changed. - The same gap showed up wherever Atmos manages many things. Components across every type (Terraform, Kubernetes, Helm, containers), plus auth identities and providers, all needed a way to carry their own organizational context instead of relying on someone remembering it.
The Fix
Atmos now carries that organizational context as metadata, in two shapes:
- Tags — a simple list of words, for basic categorical membership. Filtering matches any of the given tags.
- Labels — a set of key-value pairs, for richer metadata. Filtering requires all of the given key=value pairs, the same semantics as a Kubernetes label selector.
components:
terraform:
vpc:
metadata:
tags: [production, networking, tier-1]
labels:
cost-center: platform
compliance: sox
auth:
providers:
sso-prod:
kind: aws/iam-identity-center
start_url: https://my-org.awsapps.com/start
tags: [production, aws, sso]
identities:
prod-admin:
kind: aws/permission-set
via:
provider: sso-prod
principal:
name: AdministratorAccess
account: {name: production}
tags: [admin, production, elevated-access]
How to Use It
Listing and filtering components:
atmos list components --tags production,tier-1
atmos list components --labels cost-center=platform,compliance=sox
Bulk operations — --tags/--labels compose with --all/--affected everywhere Atmos already supports bulk selection, across every component type:
atmos terraform apply --affected --tags production
atmos kubernetes apply --all --labels cost-center=platform
atmos helm apply --affected --tags production
atmos container up --all --tags production
The same selection syntax works across supported component types, so you can reuse your labels when operating on different kinds of infrastructure.
The same filtering works for auth, since providers and identities are tagged the same way:
atmos auth list --tags production
atmos auth login --tags admin,production # auto-selects if exactly one match, else prompts
atmos auth logout --tags production # logs out every matching provider
Bridging into your modules — four new YAML functions read a component's own metadata.tags/metadata.labels without the usual !template/toJson boilerplate: !tags and !labels return the values directly, and !labels.keys/!labels.values return just the label map's keys or values. The most common use is feeding metadata.labels into the var.tags a terraform-null-label-style module expects (Terraform and AWS call a map "tags"; Atmos calls it a "label" — same data, different name):
components:
terraform:
vpc:
metadata:
labels:
Namespace: eg
Environment: prod
vars:
tags: !labels # var.tags (map) <- metadata.labels
To read an individual label in a template, use {{ .metadata.labels.runner }}. See the template context reference for accessing component configuration.
Get Involved
Tags and labels are supported today on components across Terraform, Kubernetes, Helm, and container components; auth identities and providers support tags. Auto-discovering tags/labels from cloud provider metadata (for example, mapping AWS SSO PermissionSet tags into Atmos labels automatically) is a natural next step — if that's something you need, open an issue and let us know your use case.
