|Summary||Build your CloudFormation Templates with the latest Ubuntu AMI|
|Categories||cloud, server, aws|
|Author||Carlos Bravo email@example.com|
If you are already familiar with CloudFormation Templates, you know that it is a common practice to create a mapping with hard-coded AMI IDs with their respective regions for launching instances. While the unique AMI ID per region is solved, the Always get the latest AMI is not.
In this quick tutorial, I would like to show how to ensure you always get the latest AMI ID for any given version of Ubuntu.
Why is this important? Simple, it gives you faster boot times and less reboots. If the AMI you are choosing is an old build, the update & upgrade process will not only take longer, but it could also lead you into a reboot if the package being updated is none other than the kernel itself.
In short, we will be querying the SSM parameter store for getting the latest AMI ID.
What you’ll need
- An AWS account
- A basic knowledge of EC2
- A basic knowledge of AWS CloudFormation Templates
What you’ll learn
How to avoid hardcoding AMI IDs in your CloudFormation templates.
Instead of building a list of mapped and hard-coded AMI IDs into your template, you can query the SSM parameter store for getting the latest version in a very consistent way.
Regular (free) Ubuntu LTS
From the AWS Documentation, “Each Amazon Linux AMI now has its own Parameter Store namespace that is public and describable. Upon querying, an AMI namespace returns only its regional ImageID value.”
If you want to use the regular Ubuntu server version in your CloudFormation template, add the following to your Parameters section. You can change the Ubuntu version (e.g. jammy, focal, bionic) and also the architecture (ARM64 or AMD64):
LatestAmiId: Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>' Default: '/aws/service/canonical/ubuntu/server/jammy/stable/current/amd64/hvm/ebs-gp2/ami-id'
When launching the instance, in the Resources section, you can call this parameter (the AMI ID) as it follows:
MyInstance: Type: AWS::EC2::Instance Properties: ImageId: !Ref LatestAmiId
Ubuntu Pro now follows the same pattern as regular Ubuntu, changing only the product string:
LatestAmiId: Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>' Default: '/aws/service/canonical/ubuntu/pro-server/jammy/stable/current/amd64/hvm/ebs-gp2/ami-id'
Ubuntu Pro FIPS
Since Ubuntu Pro FIPS is available only at the AWS Marketplace, the parameters needed for getting Ubuntu Pro FIPS are different. Now you need to specify the product ID according to the following table:
|Ubuntu Pro FIPS 16.04 LTS||amd64||prod-hykkbajyverq4|
|Ubuntu Pro FIPS 18.04 LTS||amd64||prod-7izp2xqnddwdc|
|Ubuntu Pro FIPS 20.04 LTS||amd64||prod-k6fgbnayirmrc|
For ARM (Graviton) and other Ubuntu versions, please visit https://ubuntu.com/server/docs/cloud-images/amazon-ec2
The parameter in your CloudFormation template will look like this (change
<product-id> with one from the table above):
LatestAmiId: Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>' Default: '/aws/service/marketplace/<product-id>/latest'
Remember that if you are launching a marketplace product, you will need to subscribe to it prior to launch your CFT, even if the product is completely free of charge.
For EKS Ubuntu LTS
For Ubuntu-EKS AMI IDs, the search is as follows (you can replace Ubuntu version, EKS version and architecture):
LatestAmiId: Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>' Default: '/aws/service/canonical/ubuntu/eks/20.04/1.23/stable/current/amd64/hvm/ebs-gp2/ami-id'
Putting all together
This is how it would look like in a very basic template for Ubuntu LTS:
AWSTemplateFormatVersion: 2010-09-09 Description: Launch EC2 instance with the latest Ubuntu AMI Parameters: AvailabilityZone: Type: AWS::EC2::AvailabilityZone::Name LatestAmiId: Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>' Default: '/aws/service/canonical/ubuntu/server/jammy/stable/current/amd64/hvm/ebs-gp2/ami-id' KeyPair: Description: Amazon EC2 Key Pair used to ssh to the cluster nodes Type: "AWS::EC2::KeyPair::KeyName" InstanceType: Type: String Default: t2.micro AllowedValues: - t2.micro - t2.medium - t2.large - t2.xlarge - t2.2xlarge Resources: MyInstance: Type: AWS::EC2::Instance Properties: ImageId: !Ref LatestAmiId InstanceType: !Ref InstanceType AvailabilityZone: !Ref AvailabilityZone KeyName: !Ref KeyPair SecurityGroupIds: - !Ref MyBasicSecurityGroup MyBasicSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: "A very basic Security group" GroupDescription: "Allows SSH inbound traffic" SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 Outputs: InstanceIP: Value: !GetAtt MyInstance.PublicIp Description: Instance public IP
That’s all folks!
As you can see, once you know what the query string is, the process is the same for regular Ubuntu, Ubuntu Pro, Ubuntu Pro FIPS and EKS.
Additional reading and references
- Finding Ubuntu Images with the AWS SSM Parameter Store - Server
- Query for the latest Amazon Linux AMI IDs using AWS Systems Manager Parameter Store | AWS Compute Blog
- Integrating AWS CloudFormation with AWS Systems Manager Parameter Store | AWS Cloud Operations & Migrations Blog
- Ubuntu Cloud Images - Amazon EC2 | Ubuntu