Skip to content

v1.226.0-rc.7

Pre-release
Pre-release

Choose a tag to compare

@cloudposse-releaser cloudposse-releaser released this 14 Aug 00:53
· 2 commits to main since this release
ba152b4
feat(auth): add Azure AKS/ACR integrations mirroring EKS/ECR Erik Osterman (Cloud Posse) (@osterman) (#2790) ## what
  • Adds atmos azure aks token, atmos azure aks update-kubeconfig, and atmos azure acr login, mirroring the existing atmos aws eks/atmos aws ecr integrations.
  • Generalizes pkg/auth/cloud/kube.KubeconfigManager from AWS-specific to a cloud-agnostic writer shared by EKS and AKS, with a regression suite locking in byte-identical AWS output.
  • Widens the existing IntegrationSpec.Cluster/.Registry schema structs (renamed from EKSCluster/ECRRegistry to Cluster/Registry) so spec.cluster/spec.registry are reused verbatim across aws/eks+azure/aks and aws/ecr+azure/acr — no new per-cloud config keys.
  • Adds AKS-scoped AAD token acquisition to all three Azure identity providers (device-code, OIDC, Azure CLI), alongside their existing Graph/KeyVault token acquisition, since Azure AAD tokens are scope-bound at issuance (unlike AWS SigV4).
  • Adds docs (website/docs/cli/commands/azure/), a changelog post, a roadmap update, two new agent skills (atmos-azure-aks, atmos-azure-acr), and a PRD documenting the design (docs/prd/azure-aks-acr-integrations.md).
  • Remediates 4 open Dependabot alerts found on push: google.golang.org/grpc (xDS RBAC auth bypass / HTTP2 rapid-reset bypass), and three transitive website npm packages (fast-uri, svgo, dompurify).

why

  • Atmos already lets an AWS identity configure kubectl and Docker credentials in one step via atmos auth login. Azure had the same auth foundation (providers, identities) but no equivalent for AKS/ACR, so Azure users still needed the az CLI — and for AAD-enabled clusters, the separate kubelogin binary — outside of Atmos entirely.
  • This closes that gap using the same integration pattern, with no new external tool dependency: AKS cluster description parses the exec-format kubeconfig Azure returns and points the exec plugin at atmos azure aks token instead of kubelogin; ACR login is a plain OAuth2 token exchange, matching what az acr login does under the hood.

references

  • Design: docs/prd/azure-aks-acr-integrations.md
  • Precedent: EKS kubeconfig PRD (docs/prd/eks-kubeconfig.md), ECR authentication PRD (docs/prd/ecr-authentication.md)

manual testing

Exercised end-to-end against a live AAD-enabled AKS cluster (Azure CNI Overlay + Cilium, AAD + Azure RBAC, local accounts disabled) — the live path that PRD Success Metric #2 had previously left to unit tests only. This surfaced, and fixed, a registration gap.

Bug found + fixed. atmos azure aks update-kubeconfig --integration <name> failed with unknown integration kind: azure/aks. The pkg/auth/integrations/azure package self-registers azure/aks and azure/acr in its init(), but nothing blank-imported that package in pkg/auth/manager.go (unlike the aws and github integration packages), so init() never ran and the kinds never registered. The unit suites import the azure package directly, which registered the kinds incidentally and masked the missing production import. Fixed by adding the blank import alongside aws/github.

Integration mode — describe the cluster and write kubeconfig via the Go SDK (no az, no kubelogin):

$ atmos azure aks update-kubeconfig --integration dev/aks
✓ AKS kubeconfig: dev-aks → ~/.config/atmos/kube/config

$ export KUBECONFIG=~/.config/atmos/kube/config
$ kubectl config current-context
dev-aks

$ kubectl get pods -A
NAMESPACE     NAME                              READY   STATUS    RESTARTS   AGE
kube-system   cilium-8trqv                      3/3     Running   0          134m
kube-system   coredns-5d474ff6db-pknhn          1/1     Running   0          132m
kube-system   metrics-server-5b879b45fc-5nxzs   2/2     Running   0          129m
...

The kubeconfig Atmos wrote drives its exec plugin through atmos azure aks token (not kubelogin), with --server-id discovered from the cluster (here the well-known AKS AAD server app):

$ kubectl config view --raw -o jsonpath='{.users[0].user.exec.command} {.users[0].user.exec.args}'
atmos [azure aks token --cluster-name aks-dev --resource-group rg-aks-cus \
       --server-id 6dae42f8-4368-4678-94ff-3960e28e3630 --subscription-id <redacted> --identity=dev]

auth exec mode — Atmos injects KUBECONFIG into the child process from the integration's Environment() (works even with auto_provision: false, which only suppresses the auto-write on login, not the env composition), so no manual export is needed:

$ atmos auth exec --identity dev -- kubectl get nodes
NAME                             STATUS   ROLES    AGE    VERSION
aks-system-64934532-vmss000000   Ready    <none>   139m   v1.35.6
aks-system-64934532-vmss000001   Ready    <none>   139m   v1.35.6

Both paths mint bearer tokens through atmos azure aks token against the Atmos-managed identity — no az CLI and no kubelogin binary. (ACR login against a live registry remains unit-test-only.)

Summary by CodeRabbit

  • New Features
    • Added native Azure authentication for AKS and ACR.
    • Added ACR login, AKS kubeconfig update, and AKS token commands.
    • Added identity-based integrations, Docker credential provisioning, and Kubernetes ExecCredential support.
    • Added shared AWS and Azure registry and cluster configuration.
  • Bug Fixes
    • Improved cluster selection, token handling, kubeconfig updates, and authentication errors.
    • Improved Packer and Ansible component command resolution.
  • Documentation
    • Added Azure command guides, integration references, examples, and roadmap updates.

🚀 Enhancements

fix(secret): inherit the component's default identity for stores Juan A. (@jaguer0) (#2746) ## what
  • atmos secret (set/get/init/validate) now inherits the component's effective identity for store-backed secrets whose store declares no explicit identity:, instead of falling back to the default AWS credential chain (→ EC2 IMDS, which fails off-EC2).

why

  • injectSecretStoreAuthResolver (cmd/secret/shared.go) called atmosConfig.Stores.SetAuthContextResolver(resolver), which passes an empty identity to every store, so an identity-less store fell back to the AWS default chain → EC2 IMDS and failed off-EC2 (e.g. no EC2 IMDS role found ... dial tcp 169.254.169.254:80: connect: host is down).
  • The terraform paths (cmd/terraform/utils.go, internal/exec/terraform_execute_helpers.go) already call SetAuthContextResolverWithDefaultIdentity; the secret CLI even computed the same DefaultIdentity (into SecretsAuth) but never applied it to the stores.
  • This aligns the code with documented behavior — website/docs/cli/configuration/secrets.mdx: "When omitted and the secret is resolved within a component scope, the component's effective identity is inherited."
  • Stores with an explicit identity, and an explicit --identity, are unaffected (defaultIdentityForStore only fills empty-identity stores). atmos terraform and atmos secret list behavior is unchanged.

Suggested label: patch (user-visible bug fix, no new surface; no blog/roadmap required).

references

  • Related: #2662 (terraform store-output hooks inherit the run's default identity — sibling fix).
  • Fix write-up: docs/fixes/2026-07-13-secret-cli-inherit-default-identity.md

Summary by CodeRabbit

  • Bug Fixes
    • Store-backed atmos secret operations now inherit the component’s effective default identity when no store identity is configured.
    • Prevents unintended fallback to the default AWS credential chain across store-backed actions.
  • Tests
    • Added coverage for default identity inheritance and resolver setup.
  • Documentation
    • Added guidance on identity inheritance and override precedence.
fix(merge): resolve deferred YAML functions losing data on merge (#2888) Erik Osterman (Cloud Posse) (@osterman) (#2892) ## what

Fixes #2888 — deferred YAML functions silently losing data on merge

  • Every production call site of ApplyDeferredMerges passed processor = nil, so deferred YAML
    functions (!template, !terraform.output, !terraform.state, !store, !exec, !env) were
    never actually resolved-and-merged — they silently lost data whenever a concrete value at another
    config layer collided with them. On top of that, !labels/!tags/!labels.keys/!labels.values
    weren't in the defer list at all, which is the literal scenario reported in the issue.
  • Adds a real Stage 3 resolution pass (internal/exec/deferred_contexts.go, plus changes across
    internal/exec/stack_processor_*.go, internal/exec/yaml_processor.go,
    internal/exec/yaml_func_tags.go, pkg/merge/deferred.go, pkg/merge/merge_yaml_functions.go)
    that resolves deferred functions per-invocation (auth- and template-context-aware) and deep-merges
    the result against any concrete override at the same path — including the mirror-precedence
    direction (a concrete value at a lower-precedence layer than the function), which the original
    design didn't handle.
  • Fixes a nondeterministic parent/child collision found while field-testing: ApplyDeferredMerges
    now processes deferred paths ancestor-before-descendant, so a descendant leaf can never be
    clobbered by a later wholesale replace of its ancestor map (see
    docs/fixes/2026-08-07-deferred-merge-nested-function-collision.md).

Fixes a double-execution regression introduced by the Stage 3 pass

  • Reviewing the Stage 3 wiring surfaced a behavior regression: with --process-functions=true, the
    document-wide ProcessCustomYamlTags pass already resolves each surviving function, and Stage 3
    then re-resolved every deferred path unconditionally — so each deferred function ran twice
    per component. Harmless for pure/cached functions (!template, !terraform.output/state,
    !labels, !tags, !env), but !exec (uncached — runs the shell again) and !store
    (an extra backend read) were executed twice. Confirmed live: a non-colliding vars.foo: !exec
    ran the shell on this branch vs on main.
  • Fix (pkg/merge/merge_yaml_functions.go): for a single-contribution (no-collision) deferred path
    whose value is already resolved in the result, ApplyDeferredMerges now reuses that value instead
    of re-invoking the processor. Tightly guarded so genuine collisions (len > 1) still fully
    resolve-and-merge — the #2888 fix is untouched. See
    docs/fixes/2026-08-13-deferred-merge-double-execution.md.

Housekeeping

  • Introduces named types StackComponentDeferredContexts and AllStacksDeferredContexts in place
    of the raw map[string]map[string][...]ComponentDeferredContexts signatures threaded through the
    stack processor (readability only; no behavior change).
  • Also bundled in this branch (unrelated to #2888, surfaced during field-test CI runs): transient-error
    retry logic for the Aqua registry and GitHub releases/rate-limit fetches
    (pkg/toolchain/registry/*), and a stack-completion fix so completion lists all project stacks
    including local (cmd/emulator/completions.go).

why

  • vars.tags: !labels (and other deferred functions) silently lost data when another config layer
    set a conflicting value at the same path — a correctness bug with no error or warning, so it was
    hard to detect in real stacks.
  • The double-execution fix prevents side-effecting/uncached functions (!exec, !store) from
    running twice, which could surprise users with duplicated side effects or extra load.
  • Per this repo's bug-fixing workflow, regression tests were written and confirmed failing first,
    then the fixes were implemented and verified against them (including live before/after runs of a
    real !exec fixture and end-to-end assertions through ExecuteDescribeComponent).

references

Summary by CodeRabbit

  • New Features

    • Deferred YAML functions now resolve across merged configurations, including templates, labels, and tags.
    • Deep merging preserves nested maps, lists, and concrete overrides across precedence levels.
    • Stack completion now lists all project stacks, including local.
  • Bug Fixes

    • Terraform backend and variable-file generation now retain deferred configuration values.
    • Toolchain and Aqua registry requests retry transient network, rate-limit, and server errors.
  • Tests

    • Added broad regression coverage for deferred merges, stack processing, generation, and network retries.
Fix const variable interpolation in Terraform module sources Marko Petrovic (@gitbluf) (#2914) ## What

Updates terraform-config-inspect to support static (const = true) variable
interpolation in Terraform module.source values.

Adds regression coverage for:

  • Successfully describing a component with source = "./mods/${var.org}".
  • Preserving real HCL syntax failures when loading Terraform components.
  • Returning parsed Terraform configuration as *tfconfig.Module in the OpenTofu
    interpolation test.

Why

Atmos previously failed while parsing valid Terraform 1.15+
configurations that interpolate a static variable in module.source:

variable "org" {
  const   = true
  type    = string
  default = "myorg"
}

module "greeting" {
  source = "./mods/${var.org}"
}

The previous terraform-config-inspect version evaluated module.source without an HCL
evaluation context and returned Variables not allowed before Terraform or OpenTofu was
invoked.

Fixes: #2913

Summary by CodeRabbit

  • New Features

    • Added support for Terraform local module sources using static constant interpolation.
    • Components using these sources now load successfully, with variables and outputs parsed correctly.
  • Bug Fixes

    • Preserved clear failure handling for genuine Terraform syntax errors.
  • Documentation

    • Added guidance covering supported interpolation behavior and validation.
  • Tests

    • Added coverage for valid interpolated module sources and malformed Terraform configurations.
    • Expanded scenario validation for module outputs and component configuration.