AWS sts assume role in one command - amazon-web-services

To assume an AWS role in the CLI, I do the following command:
aws sts assume-role --role-arn arn:aws:iam::123456789123:role/myAwesomeRole --role-session-name test --region eu-central-1
This gives to me an output that follows the schema:
{
"Credentials": {
"AccessKeyId": "someAccessKeyId",
"SecretAccessKey": "someSecretAccessKey",
"SessionToken": "someSessionToken",
"Expiration": "2020-08-04T06:52:13+00:00"
},
"AssumedRoleUser": {
"AssumedRoleId": "idOfTheAssummedRole",
"Arn": "theARNOfTheRoleIWantToAssume"
}
}
And then I manually copy and paste the values of AccessKeyId, SecretAccessKey and SessionToken in a bunch of exports like this:
export AWS_ACCESS_KEY_ID="someAccessKeyId"
export AWS_SECRET_ACCESS_KEY="someSecretAccessKey"
export AWS_SESSION_TOKEN="someSessionToken"
To finally assume the role.
How can I do this in one go? I mean, without that manual intervention of copying and pasting the output of the aws sts ... command on the exports.

No jq, no eval, no multiple exports - using the printf built-in (i.e. no credential leakage through /proc) and command substitution:
export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s" \
$(aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/MyAssumedRole \
--role-session-name MySessionName \
--query "Credentials.[AccessKeyId,SecretAccessKey,SessionToken]" \
--output text))

Finally, a colleague shared with me this awesome snippet that gets the work done in one go:
eval $(aws sts assume-role --role-arn arn:aws:iam::123456789123:role/myAwesomeRole --role-session-name test | jq -r '.Credentials | "export AWS_ACCESS_KEY_ID=\(.AccessKeyId)\nexport AWS_SECRET_ACCESS_KEY=\(.SecretAccessKey)\nexport AWS_SESSION_TOKEN=\(.SessionToken)\n"')
Apart from the AWS CLI, it only requires jq which is usually installed in any Linux Desktop.

You can store an IAM Role as a profile in the AWS CLI and it will automatically assume the role for you.
Here is an example from Using an IAM role in the AWS CLI - AWS Command Line Interface:
[profile marketingadmin]
role_arn = arn:aws:iam::123456789012:role/marketingadminrole
source_profile = user1
This is saying:
If a user specifies --profile marketingadmin
Then use the credentials of profile user1
To call AssumeRole on the specified role
This means you can simply call a command like this and it will assume the role and use the returned credentials automatically:
aws s3 ls --profile marketingadmin

Arcones's answer is good but here's a way that doesn't require jq:
eval $(aws sts assume-role \
--role-arn arn:aws:iam::012345678901:role/TrustedThirdParty \
--role-session-name=test \
--query 'join(``, [`export `, `AWS_ACCESS_KEY_ID=`,
Credentials.AccessKeyId, ` ; export `, `AWS_SECRET_ACCESS_KEY=`,
Credentials.SecretAccessKey, `; export `, `AWS_SESSION_TOKEN=`,
Credentials.SessionToken])' \
--output text)

I have had the same problem and I managed using one of the runtimes that the CLI served me.
Once obtained the credentials I used this approach, even if not so much elegant (I used PHP runtime, but you could use what you have available in your CLI):
- export AWS_ACCESS_KEY_ID=`php -r 'echo json_decode(file_get_contents("credentials.json"))->Credentials->AccessKeyId;'`
- export AWS_SECRET_ACCESS_KEY=`php -r 'echo json_decode(file_get_contents("credentials.json"))->Credentials->SecretAccessKey;'`
- export AWS_SESSION_TOKEN=`php -r 'echo json_decode(file_get_contents("credentials.json"))->Credentials->SessionToken;'`
where credentials.json is the output of the assumed role:
aws sts assume-role --role-arn "arn-of-the-role" --role-session-name "arbitrary-session-name" > credentials.json
Obviously this is just an approach, particularly helping in case of you are automating the process. It worked to me, but I don't know if it's the best. For sure not the most linear.

You can use aws config with external source following the guide: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html.
Create a shell script, for example assume-role.sh:
#!/bin/sh
aws sts --profile $2 assume-role --role-arn arn:aws:iam::123456789012:role/$1 \
--role-session-name test \
--query "Credentials" \
| jq --arg version 1 '. + {Version: $version|tonumber}'
At ~/.aws/config config profile with shell script:
[profile desktop]
region=ap-southeast-1
output=json
[profile external-test]
credential_process = "/path/assume-role.sh" test desktop
[profile external-test2]
credential_process = "/path/assume-role.sh" test2 external-test

Incase anyone wants to use credential file login:
#!/bin/bash
# Replace the variables with your own values
ROLE_ARN=<role_arn>
PROFILE=<profile_name>
REGION=<region>
# Assume the role
TEMP_CREDS=$(aws sts assume-role --role-arn "$ROLE_ARN" --role-session-name "temp-session" --output json)
# Extract the necessary information from the response
ACCESS_KEY=$(echo $TEMP_CREDS | jq -r .Credentials.AccessKeyId)
SECRET_KEY=$(echo $TEMP_CREDS | jq -r .Credentials.SecretAccessKey)
SESSION_TOKEN=$(echo $TEMP_CREDS | jq -r .Credentials.SessionToken)
# Put the information into the AWS CLI credentials file
aws configure set aws_access_key_id "$ACCESS_KEY" --profile "$PROFILE"
aws configure set aws_secret_access_key "$SECRET_KEY" --profile "$PROFILE"
aws configure set aws_session_token "$SESSION_TOKEN" --profile "$PROFILE"
aws configure set region "$REGION" --profile "$PROFILE"
# Verify the changes have been made
aws configure list --profile "$PROFILE"

based on Nev Stokes's answer if you want to add credentials to a file
using printf
printf "
[ASSUME-ROLE]
aws_access_key_id = %s
aws_secret_access_key = %s
aws_session_token = %s
x_security_token_expires = %s" \
$(aws sts assume-role --role-arn "arn:aws:iam::<acct#>:role/<role-name>" \
--role-session-name <session-name> \
--query "Credentials.[AccessKeyId,SecretAccessKey,SessionToken,Expiration]" \
--output text) >> ~/.aws/credentials
if you prefere awk
aws sts assume-role \
--role-arn "arn:aws:iam::<acct#>:role/<role-name>" \
--role-session-name <session-name> \
--query "Credentials.[AccessKeyId,SecretAccessKey,SessionToken,Expiration]" \
--output text | awk '
BEGIN {print "[ROLE-NAME]"}
{ print "aws_access_key_id = " $1 }
{ print "aws_secret_access_key = " $2 }
{ print "aws_session_token = " $3 }
{ print "x_security_token_expires = " $4}' >> ~/.aws/credentials
to update credentials in ~/.aws/credentials file run blow sed command before running one of the above command.
sed -i -e '/ROLE-NAME/,+4d' ~/.aws/credentials

Related

Is there any way to figure out public ip belongs to which aws account?

I have multiple aws accounts and i don't remember in which aws account this EC2 instance was created, is there any optimal way to figure out in very less time?
Note: i need to know account DNS name or Alias name.(Not account number)
If you have access to the instance you could use Instance metadata API:
[ec2-user ~]$ curl http://169.254.169.254/latest/dynamic/instance-identity/document
It returns json with accountId field.
If you configure AWS CLI for all account, then you can get the Account ID, ARN and user ID.
The script does the following.
Get the list of AWS configuration profile
Loop over all profile
Get a list of All Ec2 public IP address
print account info if IP matched and exit
RUN
./script.sh 52.x.x.x
script.sh
#!/bin/bash
INSTANCE_IP="${1}"
if [ -z "${INSTANCE_IP}" ]; then
echo "pls provide instance IP"
echo "./scipt.sh 54.x.x.x"
exit 1
fi
PROFILE_LIST=$(grep -o "\\[[^]]*]" < ~/.aws/credentials | tr -d "[]")
for PROFILE in $PROFILE_LIST; do
ALL_IPS=$(aws ec2 describe-instances --profile "${PROFILE}" --query "Reservations[].Instances[][PublicIpAddress]" --output text | tr '\r\n' ' ')
echo "looking against profile ${PROFILE}"
for IP in $ALL_IPS; do
if [ "${INSTANCE_IP}" == "${IP}" ]; then
echo "Instance IP matched in below account"
aws sts get-caller-identity
exit 0
fi
done
done
echo "seems like instance not belong to these profile"
echo "${PROFILE_LIST}"
exit 1
loop over accounts
loop over regions
also be aware of lightsail!
I came up with the following and helped me. I didn't exclude the regions that did not have lightsail
for region in `aws ec2 describe-regions --output text --query 'Regions[*].[RegionName]' --region eu-west-1` ; do \
echo $region; \
aws ec2 describe-network-interfaces --output text --filters Name=addresses.private-ip-address,Values="IPv4 address" --region $region ; \
aws lightsail get-instances --region eu-west-1 --output text --query 'instances[*].[name,publicIpAddress]' --region $region; \
done

Given a role ARN, how do you find out which stack and region created the role?

Can anyone please provide CLI command to get the stack name and region that created a particular IAM role?
you will have to write a small looping script that goes through all the region and all the stack (with let's say 'CREATE_COMPLETE' status) and use the describe-stack-resources CLI command.
https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-stack-resources.html
Here is a small example:
#!/bin/bash
for region in us-east-2 us-east-1 us-west-1 us-west-2 ap-east-1 ap-south-1 ap-northeast-3 ap-northeast-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 ca-central-1 cn-north-1 cn-northwest-1 eu-central-1 eu-west-1 eu-west-2 eu-west-3 eu-north-1 me-south-1 sa-east-1
do
echo "Processing region $region ..."
for stack in $(aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE --output json --region $region | jq '.StackSummaries[] | .StackId' | sed -e 's/^"//' -e 's/"$//')
do
echo "Processing stack $stack ..."
aws cloudformation describe-stack-resources --stack-name $stack --output json --region $region | jq '.StackResources[] | select(.ResourceType=="AWS::IAM::Role") | select(.PhysicalResourceId=="PUT_YOUR_ROLE_NAME_HERE")'
done
done
Don't forget that if you have your role ARN you can easily get your account number and you role name. The format being
arn:aws:iam::account-id:role/role-name
I hope that helps, sorry about the oneliner, it's less readable.
aws cloudformation describe-stacks --stack-name myteststack

AWS CLI: Get parent user details after sts-assume-role

I'm trying to automate some tagging with Ansible playbooks. One of the things I want to accomplish is tagging a resource with a username of the person who created it. The issue is the sts-assume-role obfuscates the user data of the top-level account.
# cat ~/.aws/credentials
[default]
aws_secret_access_key = gggggggggggggggggggggggggggggggggg
aws_access_key_id = JJJJJJJJJJJJJJJJJJJJ
[childaccount]
role_arn = arn:aws:iam::0123456789:role/child-acct-admin
source_profile = default
# aws iam get-user
{
"User": {
"Arn": "arn:aws:iam::4567891230:user/someuser",
"UserName": "someuser",
"UserId": "CCCCCCCCCCCCCCCCC",
"Path": "/",
"CreateDate": "2018-01-04T15:21:51Z",
"PasswordLastUsed": "2019-01-11T15:24:32Z"
}
}
# aws opsworks --region us-east-1 describe-my-user-profile
{
"UserProfile": {
"IamUserArn": "arn:aws:iam::4567891230:user/someuser",
"Name": "someuser",
"SshUsername": "someuser"
}
}
# export AWS_DEFAULT_PROFILE=childaccount
# aws opsworks --region us-east-1 describe-my-user-profile
{
"UserProfile": {
"SshUsername": "child-acct-admin-botocore-sess",
"Name": "child-acct-admin/botocore-session-123456789",
"IamUserArn": "arn:aws:sts::234567898:assumed-role/child-acct-admin/botocore-session-123456789"
}
}
# aws iam get-user
An error occurred (ValidationError) when calling the GetUser operation: Must specify userName when calling with non-User credentials
I need some command I can execute to give me the top-level account details. The only avenue I can think of is to parse the credentials file and try and use the assumed-role name to map back to the profile loaded, and the parent profile. Then pass the keys directly of the top-level account (in this example, default) to give the actual username. It's a lot more involved than it should be.
I took the long way. This approach assumes that the credentials and child account role are defined in your ~/.aws/credentials file. Written in Ansible.
- name: Query AWS role loaded
shell: aws opsworks --region us-east-1 describe-my-user-profile --query 'UserProfile.Name' | awk -F'["/]' '{print $2}'
register: role_in_use
- name: Discover AWS profile loaded
shell: awk '/\[/{prefix=$0; next} $1{print prefix $0}' ~/.aws/credentials | grep role/{{ role_in_use.stdout }} | awk -F'[][]' '{print $2}'
register: profile_in_use
- name: Find AWS source profile
shell: awk '/\[/{prefix=$0; next} $1{print prefix $0}' ~/.aws/credentials| grep "\[{{ profile_in_use.stdout }}\]source_profile =" | awk '{print $3}'
register: src_profile
- name: Set AWS source user
shell: aws opsworks --region us-east-1 describe-my-user-profile --query 'UserProfile.Name' --profile {{ src_profile.stdout }} | awk -F'["/]' '{print $2}'
register: src_user
From there, you can reference the username ala: {{ src_user.stdout }}

AWS SSM Parameters Store

Is there anyway to just nuke / remove all items in AWS Parameters Store?
All the command line I found are to remove it either one by one or remove it given a list of names.
I also tried using
aws ssm delete-parameters --cli-input-json test.json
with test.json file looks like this
{
"Names": [
"test1",
"test2"
]
}
still does not work..
Ideally if I can use --query and use it as is, that'd be great.
I'm using --query like so
aws ssm get-parameters-by-path --path / --max-items 2 --query 'Parameters[*].[Name]'
When you need to delete all parameters by path in AWS Systems Manager Parameter Store and there are more than 10 parameters you have to deal with pagination.
Otherwise, an the command will fail with the error:
An error occurred (ValidationException) when calling the DeleteParameters operation: 1 validation error detected: Value '[/config/application/prop1, ...]' at 'names' failed to satisfy constraint: Member must have length less than or equal to 10
The following Bash script using AWS CLI pagination options deletes any number of parameters from AWS SSM Parameter Store by path:
#!/bin/bash
path=/config/application_dev/
while : ; do
aws ssm delete-parameters --names $(aws ssm get-parameters-by-path --path "$path" --query "Parameters[*].Name" --output text --max-items 10 $starting_token | grep -v None)
next_token=$(aws ssm get-parameters-by-path --path "$path" --query NextToken --output text --max-items 10 | grep -v None)
if [ -z "$next_token" ]; then
starting_token=""
break
else
starting_token="--starting-token $next_token"
fi
done
You can combine get-parameters-by-path with delete-parameters:
aws ssm delete-parameters --names `aws ssm get-parameters-by-path --path / --query Parameters[].Name --output text`
I tested it by creating two parameters, then running the above command. It successfully deleted by parameters.
try this and execute multiple times
aws ssm delete-parameters --names `aws ssm get-parameters-by-path --path / --recursive --query Parameters[].Name --output text --max-items 9`
Adding to the above. I had to delete around 400 params from the parameter store. Ran the below in command line and it did it! (Change 45 in for loop to whatever number you like);
for ((n=0;n<**45**;n++)); do
aws ssm delete-parameters --names `aws ssm get-parameters-by-path --path / --recursive --query Parameters[].Name --output text --max-items 9`
done
This is my one line solution for this:
$ for key in $(aws ssm get-parameters-by-path --path "/" --recursive | jq -r '.Parameters[] | .Name' | tr '\r\n' ' '); do aws ssm delete-parameter --name ${key}; done
NOTE: Be careful if you copy & paste this as it will remove everything under "/"

Query EC2 tags from within instance

Amazon recently added the wonderful feature of tagging EC2 instances with key-value pairs to make management of large numbers of VMs a bit easier.
Is there some way to query these tags in the same way as some of the other user-set data? For example:
$ curl http://169.254.169.254/latest/meta-data/placement/availability-zone
us-east-1d
Is there some similar way to query the tags?
The following bash script returns the Name of your current ec2 instance (the value of the "Name" tag). Modify TAG_NAME to your specific case.
TAG_NAME="Name"
INSTANCE_ID="`wget -qO- http://instance-data/latest/meta-data/instance-id`"
REGION="`wget -qO- http://instance-data/latest/meta-data/placement/availability-zone | sed -e 's:\([0-9][0-9]*\)[a-z]*\$:\\1:'`"
TAG_VALUE="`aws ec2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values=$TAG_NAME" --region $REGION --output=text | cut -f5`"
To install the aws cli
sudo apt-get install python-pip -y
sudo pip install awscli
In case you use IAM instead of explicit credentials, use these IAM permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [ "ec2:DescribeTags"],
"Resource": ["*"]
}
]
}
Once you've got ec2-metadata and ec2-describe-tags installed (as mentioned in Ranieri's answer above), here's an example shell command to get the "name" of the current instance, assuming you have a "Name=Foo" tag on it.
Assumes EC2_PRIVATE_KEY and EC2_CERT environment variables are set.
ec2-describe-tags \
--filter "resource-type=instance" \
--filter "resource-id=$(ec2-metadata -i | cut -d ' ' -f2)" \
--filter "key=Name" | cut -f5
This returns Foo.
You can use a combination of the AWS metadata tool (to retrieve your instance ID) and the new Tag API to retrieve the tags for the current instance.
You can add this script to your cloud-init user data to download EC2 tags to a local file:
#!/bin/sh
INSTANCE_ID=`wget -qO- http://instance-data/latest/meta-data/instance-id`
REGION=`wget -qO- http://instance-data/latest/meta-data/placement/availability-zone | sed 's/.$//'`
aws ec2 describe-tags --region $REGION --filter "Name=resource-id,Values=$INSTANCE_ID" --output=text | sed -r 's/TAGS\t(.*)\t.*\t.*\t(.*)/\1="\2"/' > /etc/ec2-tags
You need the AWS CLI tools installed on your system: you can either install them with a packages section in a cloud-config file before the script, use an AMI that already includes them, or add an apt or yum command at the beginning of the script.
In order to access EC2 tags you need a policy like this one in your instance's IAM role:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1409309287000",
"Effect": "Allow",
"Action": [
"ec2:DescribeTags"
],
"Resource": [
"*"
]
}
]
}
The instance's EC2 tags will available in /etc/ec2-tags in this format:
FOO="Bar"
Name="EC2 tags with cloud-init"
You can include the file as-is in a shell script using . /etc/ec2-tags, for example:
#!/bin/sh
. /etc/ec2-tags
echo $Name
The tags are downloaded during instance initialization, so they will not reflect subsequent changes.
The script and IAM policy are based on itaifrenkel's answer.
If you are not in the default availability zone the results from overthink would return empty.
ec2-describe-tags \
--region \
$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e "s/.$//") \
--filter \
resource-id=$(curl --silent http://169.254.169.254/latest/meta-data/instance-id)
If you want to add a filter to get a specific tag (elasticbeanstalk:environment-name in my case) then you can do this.
ec2-describe-tags \
--region \
$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e "s/.$//") \
--filter \
resource-id=$(curl --silent http://169.254.169.254/latest/meta-data/instance-id) \
--filter \
key=elasticbeanstalk:environment-name | cut -f5
And to get only the value for the tag that I filtered on, we pipe to cut and get the fifth field.
ec2-describe-tags \
--region \
$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e "s/.$//") \
--filter \
resource-id=$(curl --silent http://169.254.169.254/latest/meta-data/instance-id) \
--filter \
key=elasticbeanstalk:environment-name | cut -f5
You can alternatively use the describe-instances cli call rather than describe-tags:
This example shows how to get the value of tag 'my-tag-name' for the instance:
aws ec2 describe-instances \
--instance-id $(curl -s http://169.254.169.254/latest/meta-data/instance-id) \
--query "Reservations[*].Instances[*].Tags[?Key=='my-tag-name'].Value" \
--region ap-southeast-2 --output text
Change the region to suit your local circumstances. This may be useful where your instance has the describe-instances privilege but not describe-tags in the instance profile policy
I have pieced together the following that is hopefully simpler and cleaner than some of the existing answers and uses only the AWS CLI and no additional tools.
This code example shows how to get the value of tag 'myTag' for the current EC2 instance:
Using describe-tags:
export AWS_DEFAULT_REGION=us-east-1
instance_id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
aws ec2 describe-tags \
--filters "Name=resource-id,Values=$instance_id" 'Name=key,Values=myTag' \
--query 'Tags[].Value' --output text
Or, alternatively, using describe-instances:
aws ec2 describe-instances --instance-id $instance_id \
--query 'Reservations[].Instances[].Tags[?Key==`myTag`].Value' --output text
For Python:
from boto import utils, ec2
from os import environ
# import keys from os.env or use default (not secure)
aws_access_key_id = environ.get('AWS_ACCESS_KEY_ID', failobj='XXXXXXXXXXX')
aws_secret_access_key = environ.get('AWS_SECRET_ACCESS_KEY', failobj='XXXXXXXXXXXXXXXXXXXXX')
#load metadata , if = {} we are on localhost
# http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AESDG-chapter-instancedata.html
instance_metadata = utils.get_instance_metadata(timeout=0.5, num_retries=1)
region = instance_metadata['placement']['availability-zone'][:-1]
instance_id = instance_metadata['instance-id']
conn = ec2.connect_to_region(region, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key)
# get tag status for our instance_id using filters
# http://docs.aws.amazon.com/AWSEC2/latest/CommandLineReference/ApiReference-cmd-DescribeTags.html
tags = conn.get_all_tags(filters={'resource-id': instance_id, 'key': 'status'})
if tags:
instance_status = tags[0].value
else:
instance_status = None
logging.error('no status tag for '+region+' '+instance_id)
A variation on some of the answers above but this is how I got the value of a specific tag from the user-data script on an instance
REGION=$(curl http://instance-data/latest/meta-data/placement/availability-zone | sed 's/.$//')
INSTANCE_ID=$(curl -s http://instance-data/latest/meta-data/instance-id)
TAG_VALUE=$(aws ec2 describe-tags --region $REGION --filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values='<TAG_NAME_HERE>'" | jq -r '.Tags[].Value')
Starting January 2022, this should be also available directly via ec2 metadata api (if enabled).
curl http://169.254.169.254/latest/meta-data/tags/instance
https://aws.amazon.com/about-aws/whats-new/2022/01/instance-tags-amazon-ec2-instance-metadata-service/
Using the AWS 'user data' and 'meta data' APIs its possible to write a script which wraps puppet to start a puppet run with a custom cert name.
First start an aws instance with custom user data: 'role:webserver'
#!/bin/bash
# Find the name from the user data passed in on instance creation
USER=$(curl -s "http://169.254.169.254/latest/user-data")
IFS=':' read -ra UDATA <<< "$USER"
# Find the instance ID from the meta data api
ID=$(curl -s "http://169.254.169.254/latest/meta-data/instance-id")
CERTNAME=${UDATA[1]}.$ID.aws
echo "Running Puppet for certname: " $CERTNAME
puppet agent -t --certname=$CERTNAME
This calls puppet with a certname like 'webserver.i-hfg453.aws' you can then create a node manifest called 'webserver' and puppets 'fuzzy node matching' will mean it is used to provision all webservers.
This example assumes you build on a base image with puppet installed etc.
Benefits:
1) You don't have to pass round your credentials
2) You can be as granular as you like with the role configs.
Jq + ec2metadata makes it a little nicer. I'm using cf and have access to the region. Otherwise you can grab it in bash.
aws ec2 describe-tags --region $REGION \
--filters "Name=resource-id,Values=`ec2metadata --instance-id`" | jq --raw-output \
'.Tags[] | select(.Key=="TAG_NAME") | .Value'
No jq.
aws ec2 describe-tags --region us-west-2 \
--filters "Name=resource-id,Values=`ec2-metadata --instance-id | cut -d " " -f 2`" \
--query 'Tags[?Key==`Name`].Value' \
--output text
Download and run a standalone executable to do that.
Sometimes one cannot install awscli that depends on python. docker might be out of the picture too.
Here is my implementation in golang:
https://github.com/hmalphettes/go-ec2-describe-tags
The Metadata tool seems to no longer be available, but that was an unnecessary dependency anyway.
Follow the AWS documentation to have the instance's profile grant it the "ec2:DescribeTags" action in a policy, restricting the target resources as much as you wish. (If you need a profile for another reason then you'll need to merge policies into a new profile-linked role).
Then:
aws --region $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//') ec2 describe-tags --filters Name=resource-type,Values=instance Name=resource-id,Values=$(curl http://169.254.169.254/latest/meta-data/instance-id) Name=key,Values=Name |
perl -nwe 'print "$1\n" if /"Value": "([^"]+)/;'
Well there are lots of good answers here but none quite worked for me exactly out of the box, I think the CLI has been updated since some of them and I do like using the CLI. The following single command works out of the box for me in 2021 (as long as the instance's IAM role is allowed to describe-tags).
aws ec2 describe-tags \
--region "$(ec2-metadata -z | cut -d' ' -f2 | sed 's/.$//')" \
--filters "Name=resource-id,Values=$(ec2-metadata --instance-id | cut -d " " -f 2)" \
--query 'Tags[?Key==`Name`].Value' \
--output text
AWS has recently announced support for instance tags in Instance Metadata Service: https://aws.amazon.com/about-aws/whats-new/2022/01/instance-tags-amazon-ec2-instance-metadata-service/
If you have have the tag metadata option enabled for an instance, you can simply do
$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 900"`
$ curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/tags/instance
It is possible to get Instance tags from within the instance via metadata.
First, allow access to tags in instance metadata as explained here
Then, run this command for IMDSv1, Refer
curl http://169.254.169.254/latest/meta-data/tags/instance/Name
or this command for IMDSv2
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/tags/instance
Install AWS CLI:
curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"
sudo apt-get install unzip
unzip awscli-bundle.zip
sudo ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
Get the tags for the current instance:
aws ec2 describe-tags --filters "Name=resource-id,Values=`ec2metadata --instance-id`"
Outputs:
{
"Tags": [
{
"ResourceType": "instance",
"ResourceId": "i-6a7e559d",
"Value": "Webserver",
"Key": "Name"
}
]
}
Use a bit of perl to extract the tags:
aws ec2 describe-tags --filters \
"Name=resource-id,Values=`ec2metadata --instance-id`" | \
perl -ne 'print "$1\n" if /\"Value\": \"(.*?)\"/'
Returns:
Webserver
For those crazy enough to use Fish shell on EC2, here's a handy snippet for your /home/ec2-user/.config/fish/config.fish. The hostdata command now will list all your tags as well as the public IP and hostname.
set -x INSTANCE_ID (wget -qO- http://instance-data/latest/meta-data/instance-id)
set -x REGION (wget -qO- http://instance-data/latest/meta-data/placement/availability-zone | sed 's/.$//')
function hostdata
aws ec2 describe-tags --region $REGION --filter "Name=resource-id,Values=$INSTANCE_ID" --output=text | sed -r 's/TAGS\t(.*)\t.*\t.*\t(.*)/\1="\2"/'
ec2-metadata | grep public-hostname
ec2-metadata | grep public-ipv4
end