Interroger les balises EC2 à partir de l'instance

96

Amazon a récemment ajouté la merveilleuse fonctionnalité de balisage des instances EC2 avec des paires clé-valeur pour faciliter la gestion d'un grand nombre de machines virtuelles.

Existe-t-il un moyen d'interroger ces balises de la même manière que certaines des autres données définies par l'utilisateur? Par exemple:

$ curl http://169.254.169.254/latest/meta-data/placement/availability-zone
us-east-1d

Existe-t-il un moyen similaire d'interroger les balises?

Josh Lindsey
la source

Réponses:

35

Vous pouvez utiliser une combinaison de l' outil de métadonnées AWS (pour récupérer votre ID d'instance) et de la nouvelle API Tag pour récupérer les balises de l'instance actuelle.

drxzcl
la source
OK, j'ai suivi ce lien, et il semble que ce soit la documentation de l'API. N'existe-t-il aucun outil que je puisse utiliser ou dois-je lire la documentation de l'API et écrire mon propre outil?
Edward Falk
3
La commande ec2-describe-tags est-elle facilement disponible? On suppose que c'est dans le paquet ec2-api-tools, mais je n'ai rien d'autre que des 404 quand j'ai essayé de l'installer.
Edward Falk
2
donnez un exemple, obtenez la valeur du rôle de balise: aws ec2 describe-tags --filters Name = resource-id, Values ​​= ec2metadata --instance-id--out = json | jq '.Tags [] | select (.Key == "role") | .Value '
jolestar
11
Ceci est un pointeur vers une réponse mais pas une réponse en soi
Roy Truelove
3
L' ec2metadataoutil est obsolète. Maintenant, vous interrogez l'URL «magique» à 169.254.169.254/latest/meta-data - appuyez dessus avec cURL et cela vous donne des points de terminaison magiques que vous pouvez utiliser pour obtenir divers bits de données. Dans ce cascurl http://169.254.169.254/latest/meta-data/instance-id
obtenez
52

Le script bash suivant renvoie le nom de votre instance ec2 actuelle (la valeur de la balise "Name"). Modifiez TAG_NAME selon votre cas spécifique.

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`"

Pour installer le aws cli

sudo apt-get install python-pip -y
sudo pip install awscli

Si vous utilisez IAM au lieu d'informations d'identification explicites, utilisez ces autorisations IAM:

{
  "Version": "2012-10-17",
  "Statement": [
    {    
      "Effect": "Allow",
      "Action": [ "ec2:DescribeTags"],
      "Resource": ["*"]
    }
  ]
}
itaifrenkel
la source
J'obtenais "Vous n'êtes pas autorisé à effectuer cette opération" avec aws ec2 describe-tags. J'avais besoin d'ajouter cet IAM aux stratégies en ligne de mon rôle IAM. Merci!
Victor D.
Une très légère optimisation POURRAIT être de remplacer le | cut -f5par --query="Tags[0].Value".
Richard A Quadling le
47

Une fois que vous avez ec2-metadataet ec2-describe-tagsinstallé (comme mentionné dans la réponse de Ranieri ci-dessus ), voici un exemple de commande shell pour obtenir le "nom" de l'instance actuelle, en supposant que vous ayez une balise "Name = Foo" dessus.

Suppose que les variables d'environnement EC2_PRIVATE_KEY et EC2_CERT sont définies.

ec2-describe-tags \
  --filter "resource-type=instance" \
  --filter "resource-id=$(ec2-metadata -i | cut -d ' ' -f2)" \
  --filter "key=Name" | cut -f5

Cela revient Foo.

réfléchir
la source
17
Cela aurait été bien si mes processus pouvaient obtenir les balises pour l'instance actuelle sans avoir à avoir l'EC2_PRIVATE_KEY sur l'instance également. :-(
William Payne
1
@ william-payne Ouais, c'est vraiment nul. Peut-être qu'en utilisant l'IAM d'Amazon, vous pourriez au moins utiliser un utilisateur avec un accès très limité à tout. FWIW, je n'utilise plus cette approche et n'utilise que des scripts externes pour configurer la boîte.
Overhink
12
@WilliamPayne Vous pouvez configurer un rôle IAM avec la stratégie "Amazon EC2 Read Only Access" et créer l'instance ayant ce rôle. Il est également possible de créer une stratégie personnalisée ayant uniquement le privilège «DescribeTags» si vous souhaitez être plus granulaire.
roverwolf
@WilliamPayne J'ai aimé la suggestion de roverwolf. Cela a très bien fonctionné. En fait, j'ai répondu à une autre question avec les détails si vous voulez la voir: stackoverflow.com/questions/9950586/...
Tony
2
Notez que la valeur par ec2-describe-tagsdéfaut est us-east-2. Veuillez passer le --regiondrapeau pour utiliser une région différente.
Avance
15

Vous pouvez ajouter ce script à vos données utilisateur cloud-init pour télécharger les balises EC2 dans un fichier local:

#!/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

Vous avez besoin des outils AWS CLI installés sur votre système: vous pouvez les installer avec une packagessection dans un fichier de configuration cloud avant le script, utiliser une AMI qui les inclut déjà, ou ajouter un aptouyum commande au début du script.

Pour accéder aux balises EC2, vous avez besoin d'une stratégie comme celle-ci dans le rôle IAM de votre instance:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1409309287000",
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeTags"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

Les balises EC2 de l'instance seront disponibles /etc/ec2-tagsdans ce format:

FOO="Bar"
Name="EC2 tags with cloud-init"

Vous pouvez inclure le fichier tel quel dans un script shell en utilisant . /etc/ec2-tags, par exemple:

#!/bin/sh
. /etc/ec2-tags
echo $Name

Les balises sont téléchargées lors de l'initialisation de l'instance, elles ne refléteront donc pas les modifications ultérieures.


Le script et la stratégie IAM sont basés sur la réponse d'itaifrenkel.

Andrea
la source
a + préférez cette méthode
Cmag
dommage que cela casse pour les tags créés par des groupes d' aws:autoscaling:groupName
autoscaling
2
Alors essayez ceci:aws ec2 describe-tags --region $REGION --filter "Name=resource-id,Values=$INSTANCE_ID" --output=text | sed -r 's/TAGS\t(.*)\t.*\t.*\t(.*)/EC2_TAG_\1="\2"/' |sed -r 's/aws:autoscaling:/aws_autoscaling_/' > /etc/ec2-tags
Ryan Gooler
10

Si vous n'êtes pas dans la zone de disponibilité par défaut, les résultats de la réflexion excessive reviendraient vides.

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)

Si vous souhaitez ajouter un filtre pour obtenir une balise spécifique (élastiquebeanstalk: nom d'environnement dans mon cas), vous pouvez le faire.

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

Et pour obtenir uniquement la valeur de la balise sur laquelle j'ai filtré, nous faisons un tuyau pour couper et obtenir le cinquième champ.

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
Michael Connor
la source
excellent travail, merci, avoir une autre instance-data DNS ne fonctionne pas pour moi, pour le dernier si vous avez besoin de remplacer le tag de nom elasticbeanstalk:environment-nameparName
detzu
5

Pour 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)
Sergei
la source
Légitime. Les lecteurs notent que pour les informations locales de base, vous n'avez même pas besoin d'informations d'identification, juste leinstance_metadata = utils.get_instance_metadata(timeout=0.5, num_retries=1)
Bartvds
En outre, cela joue bien avec les rôles IAM - si vous définissez un rôle d'instance, boto détectera automatiquement l'ID et la clé.
dbn le
5

Vous pouvez également utiliser l' describe-instancesappel cli plutôt quedescribe-tags :

Cet exemple montre comment obtenir la valeur de la balise 'my-tag-name' pour l'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

Changez la région en fonction de vos circonstances locales. Cela peut être utile lorsque votre instance dispose du privilège describe-instances mais pas de balises describe-tags dans la stratégie de profil d'instance

utilisateur Linux shonky
la source
3

En utilisant les API AWS 'user data' et 'meta data', il est possible d'écrire un script qui enveloppe la marionnette pour démarrer une exécution de marionnette avec un nom de certificat personnalisé.

Commencez par démarrer une instance aws avec des données utilisateur personnalisées: '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 

Cela appelle marionnette avec un nom de certificat comme «webserver.i-hfg453.aws», vous pouvez ensuite créer un manifeste de nœud appelé «serveur Web» et les marionnettes «correspondance de nœud flou» signifieront qu'il est utilisé pour provisionner tous les serveurs Web.

Cet exemple suppose que vous construisez sur une image de base avec la marionnette installée, etc.

Avantages:

1) Vous n'avez pas à passer vos informations d'identification

2) Vous pouvez être aussi précis que vous le souhaitez avec les configurations de rôle.

Ben Waine
la source
3

J'ai rassemblé ce qui suit qui, espérons-le, est plus simple et plus propre que certaines des réponses existantes et utilise uniquement l'AWS CLI et aucun outil supplémentaire.

Cet exemple de code montre comment obtenir la valeur de la balise 'myTag' pour l'instance EC2 actuelle:

Utilisation des balises describe :

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

Ou, alternativement, en utilisant des instances de description :

aws ec2 describe-instances --instance-id $instance_id \
  --query 'Reservations[].Instances[].Tags[?Key==`myTag`].Value' --output text
Alex Harvey
la source
2

Une variante de certaines des réponses ci-dessus, mais c'est ainsi que j'ai obtenu la valeur d'une balise spécifique à partir du script de données utilisateur sur une 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')
ActualAl
la source
1

Installez l'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

Récupérez les balises de l'instance actuelle:

aws ec2 describe-tags --filters "Name=resource-id,Values=`ec2metadata --instance-id`"

Les sorties:

{
    "Tags": [
        {
            "ResourceType": "instance", 
            "ResourceId": "i-6a7e559d", 
            "Value": "Webserver", 
            "Key": "Name"
        }
    ]
}

Utilisez un peu de perl pour extraire les balises:

aws ec2 describe-tags --filters \
"Name=resource-id,Values=`ec2metadata --instance-id`" | \
perl -ne 'print "$1\n" if /\"Value\": \"(.*?)\"/'

Retour:

Webserver
Patrick Collins
la source
ec2metadatan'est pas dans aws-cli, mais il peut être remplacé par curl --silent http://169.254.169.254/latest/meta-data/instance-id. aussi, jqpeut analyser le json plus facilement, ou un format de sortie différent est encore plus facile.
tedder42
Cela fonctionne, mais je dois ajouter ce qui suit: sudo apt-get -y install pythonetexport AWS_DEFAULT_REGION=us-west-1
Eugene
Cela ne fonctionnera pas ... 1. ec2metadata est une commande incorrecte. 2. ec2-metadata --instance-id reviendrainstance-id: i-07f59f3564618f148
Daniel Hornik le
1

Téléchargez et exécutez un exécutable autonome pour ce faire.

Parfois, on ne peut pas installer awscli qui dépend de python. docker pourrait également être hors de propos.

Voici mon implémentation en golang: https://github.com/hmalphettes/go-ec2-describe-tags

hmalphettes
la source
1

Jq + ec2metadata le rend un peu plus agréable. J'utilise cf et ai accès à la région. Sinon, vous pouvez l'attraper en bash.

aws ec2 describe-tags --region $REGION \
--filters "Name=resource-id,Values=`ec2metadata --instance-id`" | jq --raw-output \
'.Tags[] | select(.Key=="TAG_NAME") | .Value'
pbsladek
la source
0

Pour ceux qui sont assez fous pour utiliser Fish shell sur EC2, voici un extrait pratique pour votre /home/ec2-user/.config/fish/config.fish. La commande hostdata listera maintenant toutes vos balises ainsi que l'adresse IP publique et le nom d'hôte.

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
BooTooBeaucoup
la source