Skip to main content
  1. Posts/

Bulk tagging all instances in an Auto Scaling Group (ASG) using AWS CLI and JMESPath Expressions

··606 words·3 mins·
DevOps Tips & How-To's Aws Ec2 Tagging
Table of Contents

Thumbnail image generated by Stable Diffusion Online with the prompt: applying name tags to a server in a data center.

Why?
#

I wanted to tag all the instances in an AWS Auto Scaling Group (ASG) with some tags that would be used for reporting. The first order of business was to update the ASG with the relevant tags. This was done by applying the tag to the ASG using Infrastructure as Code (Terraform, in this case) so that all new instances launched would get the tag. However, the existing nodes would not inherit the tags.

While I could recycle the nodes, instance refresh makes it that much easier. Still, I figured bulk tagging the instances in the ASG was a simpler way to set the tags.

Filtering with AWS CLI
#

Since I wanted to tag instances of a specific ASG, I tried to use jq on the output of the aws ec2 describe-auto-scaling-groups command and further slice and dice the data. This was getting too painful, so I started to dig into AWS CLI’s docs and found out that the AWS CLI can apply client-side filtering using the --query option and server-side filtering using the --filter option.

Querying Auto Scaling Group Instances
#

The aws autoscaling describe-auto-scaling-groups command has a response structure as shown below:

[
    {
        "AutoScalingGroupName": "name",
        "AutoScalingGroupARN": "arn",
        "LaunchConfigurationName": "lc-name",
        "MinSize": 1,
        "MaxSize": 1,
        "DesiredCapacity": 1,
        "DefaultCooldown": 300,
        "AvailabilityZones": [
            "ap-southeast-1a",
            "ap-southeast-1c"
        ],
        "LoadBalancerNames": [],
        "TargetGroupARNs": [],
        "HealthCheckType": "EC2",
        "HealthCheckGracePeriod": 0,
        "Instances": [
            {
                "InstanceId": "",
                "InstanceType": "",
                "AvailabilityZone": "",
                "LifecycleState": "",
                "HealthStatus": "",
                "LaunchConfigurationName": "",
                "ProtectedFromScaleIn": false
            }
        ],
        "CreatedTime": "",
        "SuspendedProcesses": [],
        "VPCZoneIdentifier": "",
        "EnabledMetrics": [],
        "Tags": [],
        "TerminationPolicies": [
            "Default"
        ],
        "NewInstancesProtectedFromScaleIn": false,
        "ServiceLinkedRoleARN": "arn",
        "TrafficSources": []
    }
]

To query, the AWS CLI uses expressions created using JMESPath Syntax. From the response above, we want to select the instance IDs of a specific Auto Scaling Group. In JMESPath query, the question mark ? is used to filter and select elements. Thus, to filter based on AutoScaling Group name, the JMESPath Expression would be as shown below, replacing asg-name with the actual name of the Auto Scaling Group:

AutoScalingGroups[?AutoScalingGroupName==`asg-name`]

Filtering Instances Based on Auto Scaling Group
#

Since I further want to select only the instance IDs, the JMESPath expression of the instance ID .Instances[*].InstanceId can be chained to the above query condition. Thus, the command to fetch the instance IDs from a specific Auto Scaling Group becomes as shown below, taking care to replace region and asg-name with the region name and the ASG name, respectively.

aws autoscaling describe-auto-scaling-groups --region region --query 'AutoScalingGroups[?AutoScalingGroupName==`asg-name`].Instances[*].InstanceId'

Now that there’s a list of instance IDs, these IDs can be passed over to the aws ec2 create-tags command to apply the tag to all the instances.

aws ec2 create-tags --region ap-southeast-1 --tags Key=tagKey,Value=tagValue --resources $(aws autoscaling describe-auto-scaling-groups --region region --query 'AutoScalingGroups[?AutoScalingGroupName==`asg-name`].Instances[*].InstanceId' --output text)

Verifying the results
#

Applying what I learned above, I verified that all the instances have been correctly tagged by using the below command, taking care to replace region and asg-name with the region name and the ASG name, respectively.

aws ec2 describe-instances --region ap-southeast-1 --filters "Name=tag:aws:autoscaling:groupName,Values='asg-name'" --query "Reservations[].Instances[].{Instance:InstanceId,Name:Tags[?Key=='Name']|[0].Value}" --output table

-------------------------------------------
|            DescribeInstances            |
+----------------------+------------------+
|       Instance       |      Name        |
+----------------------+------------------+
|  i-0xdeadbeef456242  |  asg-nme-1234    |
|  i-0xdeadbeef454142  |  asg-nme-1235    |
-------------------------------------------

In the above command, the --filter option applies server-side filtering and fetches the instances that have the tag, tag:aws:autoscaling:groupName as the tag key and asg-name as the tag value. This is then chained with the client-side filter --query to display the instance ID and the name of the instance by fetching the tag with key Name.

Sathyajith Bhat
Author
Sathyajith Bhat
Author, AWS Container Hero and DevOps Specialist.

Related

How do you specify a target hostname for a https request?
··818 words·4 mins
DevOps Tips & How-To's Curl Sni Tls Https
I’ve been using hostname spoofing with curl for a while and I find out why hostname spoofing doesn’t work with TLS.
How to get fzf working in PowerShell
··462 words·3 mins
DevOps Tips & How-To's Fzf Powershell Opensource
Here’s how you can get the goodness of fuzzy search in your PowerShell terminal with fzf.
Self-hosting FreshRSS (for free) on Fly.io in under 10 minutes
··621 words·3 mins
DevOps Self-Hosting Fly.io
Here’s how you can self-host FreshRSS on Fly.io in under 10 minutes