Build, Scan, Approve & Share AWS AMIs with Atmos + Packer + GitHub Actions
Configure and use Atmos with Packer to build, scan, approve, and share a hardened Amazon Linux 2023 AMI — automated end-to-end with a GitHub Actions pipeline and a tree of custom commands.
In detail, this gist builds a hardened Amazon Linux 2023 AMI with Packer, validates it on a live test instance, optionally scans it, gates promotion behind a manual approval, tags the approved image ScanStatus=approved, and shares it across AWS accounts — all orchestrated by Atmos and driven from a GitHub Actions pipeline.
Gist, not a maintained example. This is a reference recipe shared as-is to demonstrate the pattern. Unlike the CI-tested examples, gists are not continuously validated, so adapt it to your environment and your current version of Atmos before relying on it.
It combines several Atmos features into a single production-shaped workflow you can clone and adapt.
What it teaches
This gist combines, in one project:
- Packer components in Atmos —
components.packerconfig andatmos packer init/build/output. - Stacks for Packer — every build input (source AMI, networking, encryption, tags, provisioner list) is a stack var, not hardcoded HCL.
- Go templating in stacks — the source AMI name resolves from an environment variable at build time.
- Nested custom commands — an
atmos ami <subcommand>command tree (get-ami-id, tag, list-tags, get-tag, launch-instance, list/terminate-instances, share) that wraps small, reviewable scripts. - CI/CD with a governance gate — a GitHub Actions pipeline using OIDC auth, ephemeral runners, and a manual approval Environment.
- Tag-based launch governance — a reference IAM/SCP policy that restricts EC2 launches to AMIs tagged
ScanStatus=approved.
Architecture
┌──────────────────────────────────────────────────────────────┐
│ GitHub Actions Pipeline (.github/workflows/ami.yml) │
├──────────────────────────────────────────────────────────────┤
│ build (Packer via Atmos) → launch test instance │
│ → health check → [optional] scan │
│ → ⏸ manual approval gate (GitHub Environment) │
│ → tag ScanStatus=approved → share AMI → cleanup │
└───────────────┬──────────────────────────────────────────────┘
│ atmos packer build / atmos ami …
┌───────────────▼──────────────────────────────────────────────┐
│ Atmos │
│ • Packer component (components/packer/al2023/main.pkr.hcl) │
│ • Stack (stacks/al2023.yaml) — all build inputs as vars │
│ • Custom commands (atmos ami …) → scripts/atmos/*.sh │
└───────────────┬──────────────────────────────────────────────┘
│ packer build
┌───────────────▼──────────────────────────────────────────────┐
│ Packer (amazon-ebs) │
│ provisioners: patch-os → harden → [optional] scan agent │
│ → install-packages → finalize │
│ post-processor: manifest.json │
└──────────────────────────────────────────────────────────────┘
Repository layout
aws-ami-packer-github-actions/
├── atmos.yaml # Packer config + `atmos ami` custom command tree
├── components/packer/al2023/
│ ├── main.pkr.hcl # Parameterized amazon-ebs Packer template
│ └── scripts/ # Provisioners run *inside* the image (in order)
│ ├── patch-os.sh
│ ├── harden.sh
│ ├── install-scan-agent.sh # OPTIONAL, off by default
│ ├── install-packages.sh # Edit this list for your image
│ └── finalize.sh
├── stacks/al2023.yaml # All build inputs as vars (placeholders marked)