How to Use AWS CLI to Find Untagged Instances

[rt_reading_time label=”Read Time:” postfix=”minutes” postfix_singular=”minute”]

AWS How-To Guide

Using Amazon Web Services Command Line Interface (AWS CLI) to Find Instances without a ‘Name’ Tag

Many times I’ve needed to find AWS EC2 instances without a certain tag. Usually it’s the Nametag, but other tags come up from time to time (we use a tag of Owner quite a bit here). After coming across this Reddit post and this Stack Overflow question, I made it my mission to figure out how to get instances that were missing a tag through AWS CLI instead of using external tools like jq or python.

The --Query Parameter, JMESPath and filtering

JMESPath is the ‘engine’ behind the --query parameter in AWS CLI. In its most basic form, it’ll help you filter out or traverse JSON. AWS has some nice documentation on how to use it at a basic level. In this post, we will focus on the filter ability of JMESPath.

Using the bracket and a question mark will trigger the JMESPath filter: [? ... ]

For example, many people have wanted to get the instance Name tag along with the InstanceId. This is achieved by using the filter for the Tags → Key=='Name':

aws ec2 describe-instances \
 --output text \
 --query 'Reservations[].Instances[].[Tags[?Key==`Name`].Value|[0],InstanceId]'

While this is useful, we’re looking to do the actual opposite. First, we’ll want to dive down into each instance:

aws ec2 describe-instances \
 --query 'Reservations[].Instances[]'

This will spit out each of the instances. We want to create a filter on each of these where the Name tag doesn’t exist. A tag that exists would look like:

aws ec2 describe-instances \
 --query 'Reservations[].Instances[?Tags[?Key != `Name`]]'

The problem with this filter is that as we loop through the Tags array, we’ll most likely hit an instance that has more than one tag. That instance will register true because the first tag may have "Key:" "SomeTag" (but the second could be "Key:" "Name"). So we want to look for the object with the Name key but with no Value (aka null).

First, lets get the Value from the Name tag:

aws ec2 describe-instances \
 --query 'Reservations[].Instances[].Tags[?Key == `Name`].Value'

Now we can use JMESPath’s not_null() function to filter for ones that exist:

aws ec2 describe-instances \
 --query 'Reservations[].Instances[?not_null(Tags[?Key == `Name`].Value)]'

The problem is that this still captures anything with a Name tag. So we negate it. IE: anything that isn’t not_null aka not not null 🙂

aws ec2 describe-instances \
 --query 'Reservations[].Instances[?!not_null(Tags[?Key == `Name`].Value)]'

Which will return something like the following:

[
    [
        {
            "Monitoring": {
                "State": "disabled"
            }, 
            "PublicDnsName": "", 
            "RootDeviceType": "ebs"
            ...
        }
    ], 
    [], 
    [], 
    [], 
    [], 
    [], 
    [], 
    [
        {
            "Monitoring": {
                "State": "disabled"
            }, 
            "PublicDnsName": "", 
            "RootDeviceType": "ebs"
            ...
        }
    ], 
    []
]

We don’t want to have these empty arrays, so we’ll flatten the instance object with a pipe:

aws ec2 describe-instances \
  --query 'Reservations[].Instances[?!not_null(Tags[?Key == `Name`].Value)] | []'

And thats it! If you’d like a few more examples of some common uses, here you go:

Display InstanceId of instances which have no Name tag:

aws ec2 describe-instances \
  --output text \
  --query 'Reservations[].Instances[?!not_null(Tags[?Key == `Name`].Value)] | [].[InstanceId]'

 

Display InstanceId of running instances which have no Owner tag:

aws ec2 describe-instances \
  --output text \
  --filters Name=instance-state-name,Values=running \
  --query 'Reservations[].Instances[?!not_null(Tags[?Key == `Owner`].Value)] | [].[InstanceId]'

 

Display VolumeId and Size of volumes which have no Name tag:

aws ec2 describe-volumes \
 --output text \
 --query 'Volumes[?!not_null(Tags[?Key == `Name`].Value)] | [].[VolumeId,Size]'

 

Display SnapshotId and StartTime of my snapshots which have no CreatedBy tag:

aws ec2 describe-snapshots \
 --output text \
 --owner-ids self \
 --query 'Snapshots[?!not_null(Tags[?Key == `CreatedBy`].Value)] | [].[SnapshotId,StartTime]'

Why search for untagged instances with AWS CLI?

There are a number of reasons to tag instances including automation and console organization, but at Onica, our biggest driver is cost. Employing a tagging policy to help track the cost allocation of your instances is an important step in optimizing your AWS cost!

 

For more tips and tricks to lower your monthly AWS cost by up to 50%, download our eBook!

Hidden layer

Share on linkedin
Share on twitter
Share on facebook
Share on email

Onica Insights

Stay up to date with the latest perspectives, tips, and news directly to your inbox.

Explore More Cloud Insights from Onica

Blogs

The latest perspectives on navigating an ever-changing cloud landscape

Case Studies

Explore how our customers are driving cloud innovation in their industries

Videos

Watch an on-demand library of cloud tutorials, tips and tricks

Publications

Learn how to succeed in the cloud with deep-dives into pressing cloud topics