With Ubuntu 20.04 reaching end of standard support on May 31, 2025, AWS users need a fast way to identify which EC2 instances are still running outdated versions and whether those machines are covered by an Ubuntu Pro subscription for extended security.
This guide shows you how to audit your entire Ubuntu AWS fleet in minutes, by running custom scripts in your fleet using AWS Systems Manager (SSM). You’ll get an Excel-friendly list of each instance’s ID, Ubuntu version, and Pro subscription status
Requirements
To follow this guide, you need:
- A Linux machine: This could be your workstation or another EC2 instance.
- AWS CLI installed.
- SSM permissions: Either AWS CLI configured with an account that has permission to run SSM commands or an EC2 machine with SSM permissions attached as a role.
- SSM-managed instances: Your machines must appear under the “Fleet Management” menu in AWS Systems Manager.
The AWS CLI allows you to run SSM commands just like in the console, but with added flexibility for automation and integration.
Our goal is to generate an Excel-readable sheet containing the instance ID, Ubuntu version, and whether the instance is attached to an Ubuntu Pro subscription.
Below, we outline the process before presenting a complete Bash script to automate the task.
Step 1: Get all Your Ubuntu managed machines
We start by querying all managed instances and filtering for Ubuntu:
aws ssm describe-instance-information \
--query "InstanceInformationList[*].[InstanceId, PlatformName, PlatformVersion]" \
--no-paginate \
--output text | grep 'Ubuntu'
Note: There is no built-in OS filter in this command, so we use grep
to narrow down results.
Step 2: Send an Ad-hoc Command to Check Ubuntu Pro Status
To determine if an instance is attached to Ubuntu Pro, we need to run the following command inside each machine:
sudo pro status --format yaml | grep attached
This extracts the attached
status from the pro status
output in YAML format. If the instance is Pro-enabled, the output will be:
attached: true
To execute this command remotely on each instance, we use aws ssm send-command
with the AWS-RunShellScript
document:
aws ssm send-command \
--instance-ids "$instanceID" \
--document-name "AWS-RunShellScript" \
--comment "Pro Status" \
--parameters commands="sudo pro status --format yaml | grep attached" \
--query "Command.CommandId" \
--output text
Since this command runs asynchronously, it returns a CommandId
that we will use to retrieve the output later.
Step 3: Retrieve the command output
To check the command execution status:
aws ssm list-command-invocations \
--command-id "$command_id" \
--details \
--query "CommandInvocations[0].Status" \
--output text
If the status is Success
, we can extract the output:
aws ssm list-command-invocations \
--command-id "$command_id" \
--details \
--query "CommandInvocations[0].CommandPlugins[0].Output" \
--output text
This command fetches only the relevant output from the command invocation.
Step 4: Automate the process with a Bash script
Now that we know how to fetch information from a remote machine using SSM, the final step should be to automate the whole process to be run at scale with a single script.
The script will have to:
- Retrieve all Ubuntu instances managed by SSM.
- Send the
pro status
command to each instance. - Implement a retry mechanism to handle delays in command execution.
- Output instance details in a structured format.
#!/bin/bash
# Get all Ubuntu managed instances
instances=$(aws ssm describe-instance-information --query "InstanceInformationList[*].[InstanceId, PlatformName, PlatformVersion]" --no-paginate --output text | grep 'Ubuntu')
# Query each instance by running a shell-script command
while read -r line; do
# Extract the instance ID (first column)
instanceID=$(echo "$line" | awk '{print $1}')
# Send the command and capture the Command ID
command_id=$(aws ssm send-command \
--instance-ids "$instanceID" \
--document-name "AWS-RunShellScript" \
--comment "UA Status" \
--parameters commands="sudo pro status --format yaml | grep attached" \
--query "Command.CommandId" \
--output text)
if [[ -z "$command_id" ]]; then
echo "$line Failed to send command"
continue
fi
# Retry mechanism
max_retries=10
sleep_time=5
attempt=1
status="InProgress"
while [[ "$status" == "InProgress" || "$status" == "Pending" ]]; do
if (( attempt > max_retries )); then
echo "$line Max retries reached. Skipping..."
break
fi
status=$(aws ssm list-command-invocations \
--command-id "$command_id" \
--details \
--query "CommandInvocations[0].Status" \
--output text)
if [[ "$status" == "Success" ]]; then
output=$(aws ssm list-command-invocations \
--command-id "$command_id" \
--details \
--query "CommandInvocations[0].CommandPlugins[0].Output" \
--output text)
break
fi
sleep "$sleep_time"
((attempt++))
done
echo "$line $output"
done <<< "$instances"
Save this bash script with a name, say ubuntu-state.sh
add execute permissions with chmod +x ubuntu-state.sh
and run it as follows, to generate a csv file (it will be separated by tabs instead of commas):
./ubuntu-state.sh >> my_ubuntu_state.csv
Example Output
i-0f45639632b5b0a79 Ubuntu 22.04 attached: true
i-0027c5909b1d95b96 Ubuntu 24.04 attached: false
i-05837539fc263ddbe Ubuntu 20.04 attached: true
i-0d014199681cfa791 Ubuntu 22.04 attached: true
Customization Tips
- Add more commands (e.g., available ESM packages, security updates).
- Join this data with EC2 instance tags or metadata for better fleet reports.
- Integrate into monitoring dashboards or compliance checks.
Final Thoughts
By using AWS SSM and the AWS CLI, you can quickly audit Ubuntu versions and subscription statuses across all EC2 instances, avoiding manual checks and ensuring compliance as Ubuntu 20.04 reaches its end of life.
This solution is scalable, flexible, and easily customizable for your needs. Stay ahead of 20.04 End of Support risks and security gaps by automating this audit today.