Packer’s CIS hardening isn’t about applying CIS benchmarks to an existing system; it’s about building images that start compliant.
Let’s say you’re spinning up a new fleet of EC2 instances, and your security team mandates adherence to CIS benchmarks for Amazon Linux 2. Instead of manually hardening each instance post-launch or trying to patch a running system, you use Packer to bake those security controls directly into your Amazon Machine Images (AMIs).
Here’s a look at how that process unfolds, focusing on a simplified example of hardening SSH access.
Imagine you have a Packer template (amazon-linux-2-ssh-hardened.pkr.hcl) that looks like this:
packer {
required_plugins {
amazon = {
version = ">= 1.0.0"
source = "github.com/hashicorp/amazon"
}
}
}
source "amazon-ebs" "ubuntu" {
ami_name = "ubuntu-2204-ssh-hardened-{{timestamp}}"
instance_type = "t3.micro"
region = "us-east-1"
source_ami_filter {
filters = {
name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"] # Canonical's AMI owner ID
}
ssh_username = "ubuntu"
}
build {
sources = ["source.amazon-ebs.ubuntu"]
provisioner "shell" {
inline = [
"echo 'Starting SSH hardening...'",
"sudo sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config",
"sudo sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config",
"sudo sed -i 's/^X11Forwarding yes/X11Forwarding no/' /etc/ssh/sshd_config",
"sudo systemctl restart sshd",
"echo 'SSH hardening complete.'"
]
}
}
When you run packer build amazon-linux-2-ssh-hardened.pkr.hcl, Packer will:
- Launch an EC2 Instance: It provisions a temporary EC2 instance based on the
source_ami_filter(a recent Ubuntu 22.04 AMI in this case) and the specifiedinstance_type. - Connect via SSH: It establishes an SSH connection to this new instance using the
ssh_usernameand a temporary key pair it generates. - Execute Provisioners: It runs the
shellprovisioner’sinlinecommands. These commands directly modify thesshd_configfile to disable root login, disable password authentication, and disable X11 forwarding, all common CIS recommendations. It then restarts the SSH service to apply these changes. - Create an AMI: Once the provisioning is complete, Packer stops the instance and creates a new AMI from its root volume. This AMI now contains the hardened SSH configuration.
- Clean Up: The temporary EC2 instance and key pair are terminated.
The result is an AMI (ubuntu-22.04-ssh-hardened-1678886400) that, when launched, will already have these SSH security settings in place. This is crucial for compliance because it ensures that the initial state of your instances meets security requirements, rather than relying on post-launch configuration management that might miss a step or be applied too late.
You can extend this pattern with more complex shell provisioners, or by using configuration management tools like Ansible or Chef within Packer. For example, to enforce a minimum password complexity or to ensure specific firewall rules are active, you’d add those commands or playbooks to the provisioner block. The core principle remains: build security in from the start.
What most people don’t realize is that Packer’s source_ami_filter is incredibly powerful for selecting precisely the right starting point. You can combine name, root-device-type, virtualization-type, and owners with most_recent or a specific AMI ID to ensure you’re always building on a known, trusted base image, further strengthening your security posture before you even begin hardening.
The next step after hardening SSH is often to tackle user account management and file permissions, ensuring only necessary users exist and sensitive files have restricted access.