Back to portfolioVamsi Krishna Samboju

// case study · public project

Automating AWS AMI Creation for Linux and Windows Build Environments

Infrastructure automation work from two roles: building repeatable, validated AMI creation pipelines for Linux build servers and Windows servers using Packer, Ansible, and InSpec — with independently written public repositories demonstrating the approach.

PackerAnsibleInSpecAWS AMIAWS CodePipelineAzure DevOpsWindowsLinuxIaC
01

Role & Context

Cleaver-Brooks

DevOps Engineer Lead

Aug 2022 – Sep 2023 · Milwaukee, USA

Dealer-FX

DevOps Engineer

Mar 2020 – Jun 2022 · Toronto, Canada

AMI automation was part of my infrastructure responsibilities at both Cleaver-Brooks and Dealer-FX. At both companies, manually built images caused consistency and auditability problems that I addressed by introducing automated, validated AMI pipelines. The toolchain was consistent — Packer, Ansible, and InSpec — and all three AMI types (Linux build server, Windows IIS web server, and Windows SQL Server) were in use at both companies, though the CI/CD tooling differed.

The public repositories linked at the bottom of this page are independent projects I built from scratch on my own machine to demonstrate this approach. They are not company exports.

02

Problem

Building AWS AMIs by hand — launching a base instance, configuring it manually, and snapshotting it — produces images that are difficult to reproduce, impossible to audit, and prone to configuration drift between environments. Each manual build is a one-off: there is no record of what was installed, in what order, or whether the final image met any compliance baseline.

At both companies, infrastructure teams relied on base AMIs without a systematic process for customising and validating them. The problem I was solving was making AMI creation repeatable, auditable, and validated. The same build that produces an image for a test account should produce an identical image for production, with automated checks confirming the result meets a defined baseline before the AMI is published.

03

My Contribution

I personally designed and implemented the AMI automation pipelines at both companies. The work I owned at each included:

Defining the Packer build templates — specifying the base AMI, instance configuration, provisioner sequence, and variable structure that kept environment-specific values out of source control.

Writing and organising the Ansible provisioners — structuring them so each installs exactly one component, making the provisioner list a readable manifest of what is in the image.

Building the InSpec compliance profiles — defining checks that run after provisioning and block AMI publication if the instance does not meet the baseline.

Wiring together the CI/CD pipeline — configuring branch-based account separation so feature branch builds target test and staging environments while only reviewed, merged builds reach production.

Documenting the AMI build process, the provisioner structure, and the compliance baseline for team use.

04

Approach & Toolchain

Packer

Build orchestration

Packer drives the entire AMI creation process. It launches a temporary EC2 instance from a base AMI, coordinates the provisioners, waits for them to complete, and creates the final AMI from the configured instance. The Packer template defines the builder, source AMI, instance type, VPC and subnet, and the sequence of provisioning steps. All environment-specific configuration is supplied through variables — no credentials or account details appear in the template.

Ansible

Package installation & configuration

Ansible playbooks handle software installation and configuration on the instance. Each playbook installs one component — a runtime, a build tool, a system library — and they run in sequence via Packer's provisioner list. This modular structure means playbooks can be added, removed, or reordered without touching the Packer template structure. For Linux, Ansible runs over SSH. For Windows, Packer bootstraps WinRM using a boot configuration script, then Ansible connects over WinRM.

InSpec

Compliance validation

After provisioning completes and the instance reboots, InSpec runs a compliance profile against the instance. The profile checks that each installed package or tool is present at the expected version — verifying by package manager query, command-line version output, or file existence depending on what each tool exposes. The build fails if InSpec checks do not pass, which means the AMI is only published once the instance has been confirmed to match the defined baseline.

CI/CD Pipeline

Automated delivery

The pipeline runs on every push. Branches other than main build and publish AMIs to test, development, and staging AWS accounts after InSpec validation passes. Merges to main target the production AWS account and, after InSpec validation, publish and share the final AMI to the configured production accounts. The AMI version number in the Packer template is incremented with each pull request to maintain a clear image version history. At Cleaver-Brooks, this pipeline was implemented with AWS CodePipeline, CodeBuild, CodeDeploy, and CodeCommit. At Dealer-FX, Azure DevOps served the same role.

05

Build Pipeline

Conceptual diagram — simplified for public presentation

BRANCH: non-mainGit pushfeature branchCI/CD Pipelinepipeline triggersPacker validate + buildtest AWS accountAnsible provisionersinstall & configure packagesInSpec validationcompliance checks passAMI publishedtest / dev / staging accountsBRANCH: mainMerge to mainPR approvedCI/CD Pipelinepipeline triggersPacker buildproduction AWS accountAnsible provisionersinstall & configure packagesInSpec validationgates AMI publishAMI publishedproduction accountsAMI version incremented in Packer template with each pull request
06

What the Repositories Contain

Linux_AMI

Custom Linux build server AMI. Installs a broad set of language runtimes and development tools needed for CI/CD build agents.

Ruby

Ansible provisioners

Java 11Node v8Node v12PythonRuby.NET SDK 2.2.NET SDK 3.1.NET SDK 5.NET SDK 6MavenGulp CLIKarmaDockerGitPowerShellKerberosPyWinRMFontconfigAnsiblePackerInSpecAzure DevOps Agent

InSpec: Verifies each installed runtime and tool by version — package manager checks, command-line version output, and file existence (e.g. Azure DevOps agent run.sh). Build fails if any check does not pass.

Windows_Webserver_AMI

Custom Windows web server AMI. Configures IIS with ASP.NET MVC, URL rewriting, and Web Deploy for application hosting.

PowerShell

Ansible provisioners

IIS web serverASP.NET MVCASP.NET MVC 4URL RewriteWeb DeployDefault IIS cleanup

InSpec: Automated compliance testing confirms the IIS configuration, ASP.NET components, and tooling are correctly installed before the AMI is published. WinRM is bootstrapped via a boot_config script so Packer can communicate with the Windows instance.

Windows_SQLserver_AMI

Custom Windows SQL Server AMI. Provisions and configures SQL Server for use as a database instance in AWS environments.

PowerShell

Ansible provisioners

SQL ServerWinRM bootstrap

InSpec: InSpec validates the SQL Server installation and configuration meet the defined baseline before the AMI is published and shared to target accounts.

07

Engineering Decisions

One playbook per component

Each Ansible playbook installs exactly one thing. This makes the provisioner list in the Packer template a readable manifest of what is in the image, and means components can be added, removed, or updated independently. A single large playbook would be harder to debug when one step fails and harder to maintain when one component needs updating.

InSpec as a build gate, not a post-build audit

InSpec runs as part of the Packer build before the AMI is created. If the compliance checks fail, the build fails and no AMI is published. This means the published AMI is always a validated artifact — there is no risk of a non-compliant image reaching production because validation was skipped or treated as advisory.

Branch-based account separation

Feature branches build and publish AMIs to test, development, and staging AWS accounts after InSpec validation passes. Merges to main build and publish to the production account only. This keeps production AMI registries clean — only reviewed, PR-approved builds reach production — while still giving lower environments a validated AMI from every branch.

WinRM bootstrap for Windows provisioning

Packer cannot use SSH to provision Windows instances. A WinRM setup script is injected as user data on instance launch, bootstrapping the WinRM listener before Ansible attempts to connect. This allows the same Packer + Ansible pattern used for Linux to apply to Windows instances without requiring any manual instance configuration.

Environment variables for all secrets and configuration

No credentials, account IDs, VPC IDs, or subnet IDs appear in the committed Packer templates. All are passed as environment variables at build time — from the CI/CD pipeline's variable store, and locally from the engineer's shell. This keeps the repository clean of environment-specific configuration and avoids credential exposure in source control.

08

Outcomes

  • →Replaced manually built, undocumented AMIs with a fully automated, version-controlled pipeline at both companies.
  • →Every published AMI was validated against a defined compliance baseline before reaching any environment — InSpec failures blocked the build rather than producing a non-compliant image.
  • →Infrastructure teams gained a clear, readable record of what each AMI contained through the structured Ansible provisioner list and Packer template.
  • →Branch-based account separation gave teams validated AMIs in test and staging from every branch, while keeping the production AMI registry restricted to reviewed, merged builds.
  • →The same Packer + Ansible + InSpec pattern scaled across all three AMI types — Linux build server, Windows IIS web server, and Windows SQL Server — at both companies.

Disclosure

This case study summarizes my engineering experience at Cleaver-Brooks and Dealer-FX. Technical descriptions and diagrams are simplified for public presentation. No proprietary company code, confidential data, or internal configuration is included.