AWS for DevOps — AMIs & Key Pairs

3 minute read

3.2 — AMIs & Key Pairs

An AMI (Amazon Machine Image) is a template that contains the OS, application server, and applications needed to launch an instance. Key pairs are the SSH credentials used to connect.

What Is an AMI?

Think of an AMI as a snapshot of a fully configured server. It includes:

  • Operating system (Amazon Linux, Ubuntu, Windows, etc.)
  • Pre-installed software
  • Configuration files
  • Data on attached storage volumes
  AMI: custom-web-server-v1.2
  ┌──────────────────────────────────────┐
  │  Amazon Linux 2023                   │
  │  + Nginx 1.24                        │
  │  + Node.js 20 LTS                    │
  │  + CloudWatch Agent                  │
  │  + /etc/nginx/nginx.conf (custom)    │
  │  + /opt/app/ (your application)      │
  └──────────────────────────────────────┘
         │              │              │
         ▼              ▼              ▼
      Instance 1     Instance 2     Instance 3
      (identical)    (identical)    (identical)

Types of AMIs

Source Examples Cost
AWS-provided Amazon Linux, Ubuntu, Windows Server Free (OS may have licence cost)
Marketplace Pre-built appliances (firewalls, databases) May have hourly software fee
Community Shared by other users Free, but use with caution
Custom (yours) Your golden image Storage cost for the snapshot

Finding an AMI

# Find the latest Amazon Linux 2023 AMI
$ aws ec2 describe-images \
    --owners amazon \
    --filters "Name=name,Values=al2023-ami-2023*-x86_64" \
              "Name=state,Values=available" \
    --query 'sort_by(Images,&CreationDate)[-1].[ImageId,Name]' \
    --output text
ami-0abcdef1234567890   al2023-ami-2023.4.20260328.0-kernel-6.1-x86_64

# Find the latest Ubuntu 22.04 AMI
$ aws ec2 describe-images \
    --owners 099720109477 \
    --filters "Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*" \
              "Name=state,Values=available" \
    --query 'sort_by(Images,&CreationDate)[-1].[ImageId,Name]' \
    --output text
ami-0xyz987654321abcde   ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-20260325

Creating a Custom AMI

The golden image workflow:

  1. Launch a base instance
  2. Install and configure your software
  3. Create an AMI from the running (or stopped) instance
  4. Use the AMI to launch identical instances
# Step 1 — Launch and configure a base instance
$ aws ec2 run-instances \
    --image-id ami-0abcdef1234567890 \
    --instance-type t3.micro \
    --key-name my-key-pair

# Step 2 — SSH in and configure
$ ssh -i my-key-pair.pem ec2-user@<public-ip>
$ sudo yum install -y nginx nodejs
$ sudo systemctl enable nginx
$ exit

# Step 3 — Create the AMI
$ aws ec2 create-image \
    --instance-id i-0abc123def456 \
    --name "web-server-v1.0-$(date +%Y%m%d)" \
    --description "Nginx + Node.js on Amazon Linux 2023" \
    --no-reboot
{
    "ImageId": "ami-0custom123456"
}

# Step 4 — Wait for it to be available
$ aws ec2 describe-images --image-ids ami-0custom123456 \
    --query 'Images[0].State'
"available"

# Step 5 — Launch new instances from the custom AMI
$ aws ec2 run-instances \
    --image-id ami-0custom123456 \
    --instance-type t3.medium \
    --count 3

--no-reboot: Creates the AMI without stopping the instance. The file system may not be perfectly consistent. For production golden images, stop the instance first.

AMI Lifecycle Management

Over time, you accumulate many AMIs. Clean up old ones:

# List your custom AMIs
$ aws ec2 describe-images --owners self \
    --query 'Images[*].[ImageId,Name,CreationDate]' \
    --output table

# Deregister an old AMI
$ aws ec2 deregister-image --image-id ami-0old123456

# Delete the associated snapshot (AMI doesn't auto-delete it)
$ aws ec2 describe-snapshots --owner-ids self \
    --filters "Name=description,Values=*ami-0old123456*" \
    --query 'Snapshots[*].SnapshotId'
["snap-0abc123"]

$ aws ec2 delete-snapshot --snapshot-id snap-0abc123

Key Pairs

A key pair consists of a public key (stored by AWS) and a private key (you download once). AWS uses the public key to encrypt a login challenge, and your private key decrypts it.

# Create a key pair
$ aws ec2 create-key-pair \
    --key-name devops-key \
    --key-type ed25519 \
    --query 'KeyMaterial' \
    --output text > devops-key.pem

# Set permissions (SSH refuses keys with open permissions)
$ chmod 400 devops-key.pem

# Use it to connect
$ ssh -i devops-key.pem ec2-user@<public-ip>
Key Type Security Speed
RSA (2048-bit) Good Slower
ED25519 Better Faster

Recommendation: Use ED25519 for new key pairs. It is more secure and generates smaller keys.

Key Pair Best Practices

Practice Why
One key pair per environment Limit blast radius if a key leaks
Store private keys in a secrets manager Not in Git, not on laptops
Use SSM Session Manager instead of SSH No keys needed, full audit trail
Rotate keys periodically Reduce window of compromise
Never share private keys between team members Use IAM users or SSM for individual access

Common Mistakes

Mistake Why It Hurts Fix
Not deregistering old AMIs Paying for snapshot storage Automate AMI lifecycle
Using community AMIs blindly Could contain malware Stick to AWS or Marketplace AMIs
Losing the private key Locked out of instances Use SSM Session Manager as backup
Creating AMIs from running instances with active writes Inconsistent file system Stop the instance first or use --no-reboot with caution

Quick Reference

Task Command
Find latest Amazon Linux AMI aws ec2 describe-images --owners amazon --filters "Name=name,Values=al2023-*"
Create custom AMI aws ec2 create-image --instance-id ID --name NAME
List your AMIs aws ec2 describe-images --owners self
Deregister AMI aws ec2 deregister-image --image-id AMI_ID
Create key pair aws ec2 create-key-pair --key-name NAME --key-type ed25519
List key pairs aws ec2 describe-key-pairs
Delete key pair aws ec2 delete-key-pair --key-name NAME

Next → Security Groups

Updated: