Comment savoir si une machine est une instance EC2

43

J'aimerais exécuter des scripts sur des hôtes qui sont des instances EC2, mais je ne sais pas comment m'assurer que l'hôte est vraiment une instance EC2.

J'ai fait des tests, mais cela ne suffit pas:

  • Testez que b2 ec2_userdata est disponible (mais ce ne sera pas toujours vrai)
  • Disponibilité de test de " http://169.254.169.254/latest/meta-data " (mais cela sera-t-il toujours vrai? Et quelle est cette "adresse magique"?)
Kelindil
la source
C'est en fait une adresse APIPA, ce qui est assez étrange à utiliser comme référence pour un service critique comme la récupération de métadonnées.
Matthieu Cerda
2
Les plages d'adresses IP des EC2 sont publiques (bien que variables d'une fois à l'autre). Si vous suivez une liste en cours, vous pouvez vérifier l'IP des instances par rapport à cette plage.
Karma Fusebox
2
Ne vous fiez pas à 169.254.169.254 si vous voulez EC2 et seuls les systèmes similaires à EC2 - EC2 comme Eucalyptus le prennent également en charge. engage.eucalyptus.com/customer/portal/articles/…
ceejayoz
1
Avez-vous besoin de cette méthode pour lutter contre un attaquant qui a la racine sur l'hôte et essaie de vous faire croire que c'est une instance EC2 à ses propres fins malveillantes? Si vous le faites, ce sera beaucoup plus difficile.
Mike Scott

Réponses:

3

En fait, il existe un moyen très simple de détecter si l'hôte est une instance EC2: vérifiez la recherche inversée de votre adresse IP publique. Les revers de l'EC2 sont assez difficiles à manquer.

De plus, si vous ne le modifiez pas, le nom d’hôte doit être votre inverse, ce qui le rend plus facile à repérer.

Vous pouvez également utiliser "l'adresse IP magique" dont vous avez parlé, car il s'agit en effet du moyen standard d'obtenir les balises d'instance EC2. Toutefois, si vous ne travaillez pas sur un réseau EC2, vous devrez attendre un délai d'expiration, ce qui n'est généralement pas le cas. souhaitable...

Si ces méthodes ne suffisent pas, il suffit de faire un whois de votre adresse IP et de vérifier si vous vous trouvez dans le bloc IP Amazon EC2.

EDIT: Vous pouvez utiliser ce petit bit shell:

#!/bin/bash
LOCAL_HOSTNAME=$(hostname -d)
if [[ ${LOCAL_HOSTNAME} =~ .*\.amazonaws\.com ]]
then
        echo "This is an EC2 instance"
else
        echo "This is not an EC2 instance, or a reverse-customized one"
fi

Attention cependant, [[est un bashisme. Vous pouvez également utiliser un Python ou Perl Uniline, YMMV.

Matthieu Cerda
la source
13
cela ne fonctionne pas dans un VPC ou un environnement dans lequel vous avez changé le nom d'hôte; par exemple. si vos machines sont dans domain.local
Preflightsiren
2
le bit de nom d’hôte est voué à l’échec.
Dan Pritts
3
hostname -dretourseu-west-1.compute.internal
Bulletmagnet
42

Modification de la réponse de Hannes pour éviter les messages d'erreur et inclure un exemple d'utilisation dans le script:

if [ -f /sys/hypervisor/uuid ] && [ `head -c 3 /sys/hypervisor/uuid` == ec2 ]; then
    echo yes
else
    echo no
fi

Cela ne fonctionne pas dans les instances Windows. L'avantage par rapport au curl est qu'il est presque instantané sur les EC2 et les non-EC2.

Qwertzguy
la source
4
AWS semble également recommander de procéder ainsi docs.aws.amazon.com/AWSEC2/latest/UserGuide/…
Mike
3
J'aime cette méthode. Sachez simplement qu'un système non EC2 exécuté sous un hyperviseur peut générer un UUID qui commence par ec2- un faux positif. Il est peu probable (une chance sur 256) et uniquement si vous utilisez un hyperviseur qui remplit ce fichier. C'est pourquoi la documentation liée ci-dessus indique «vous êtes probablement en train de regarder une instance EC2».
Nate
1
@Nate, bon point, mais cela ne devrait-il pas être une chance sur 4096? (16 x 16 x 16)
Wildcard
2
@Wildcard: Je ne peux pas éditer mon commentaire, mais c'est vrai.
Nate
7
DANGER! Cette méthode fonctionnait de manière fiable pour nous depuis des années ... jusqu'à tout récemment, avec les derniers types c5 et m5 ne contenant pas ce fichier . Je dois donc ajouter une vérification de secours de 169.254.169.254 pour gérer ces instances.
Josh Kupershmidt
20

Premièrement, j’ai ressenti le besoin de publier une nouvelle réponse en raison des problèmes subtils suivants avec les réponses existantes et après avoir reçu une question à propos de mon commentaire sur la réponse de @ qwertzguy . Voici les problèmes avec les réponses actuelles:

  1. La réponse acceptée de @MatthieuCerda ne fonctionne certainement pas de manière fiable, du moins pas sur les instances de VPC que j'ai vérifiées. (Sur mes instances, je reçois un nom de VPC pour hostname -d, qui est utilisé pour le DNS interne, mais pas avec "amazonaws.com".)
  2. La réponse la plus votée de @qwertzguy ne fonctionne pas sur les nouvelles instances m5 ou c5 , qui ne possèdent pas ce fichier. Amazon néglige de documenter ce changement de comportement autant que je sache, bien que la page de documentation sur ce sujet indique "... Si / sys / hypervisor / uuid existe ...". J'ai demandé à l'assistance d'AWS si ce changement était intentionnel, voir ci-dessous †.
  3. La réponse de @Jer ne fonctionne pas nécessairement partout car la instance-data.ec2.internalrecherche DNS peut ne pas fonctionner. Sur une instance de VPC Ubuntu EC2 que je viens de tester, je vois: $ curl http://instance-data.ec2.internal curl: (6) Could not resolve host: instance-data.ec2.internal ce qui ferait que le code s’appuyant sur cette méthode conclurait à tort qu’il ne s’agissait pas de EC2!
  4. La réponse à utiliser àdmidecode partir de @tamale peut fonctionner, mais dépend de vous: a)) avoir dmidecodeà votre disposition sur votre instance, et b.) Avoir sudoune capacité root ou sans mot de passe à partir de votre code.
  5. La réponse à vérifier / sys / devices / virtual / dmi / id / bios_version de @spkane est dangereusement trompeuse! J'ai vérifié une instance Ubuntu 14,04 m5 et obtenu un exemple bios_versionde 1.0. Ce fichier n'est pas du tout documenté dans la documentation d'Amazon , je ne le ferais donc vraiment pas.
  6. La première partie de la réponse de @ Chris-Montanaro visant à vérifier une URL tierce non fiable et à utiliser whoissur le résultat pose problème à plusieurs niveaux. Notez que l'URL suggérée dans cette réponse est une page 404 en ce moment! Même si vous trouviez un service tiers qui fonctionnait, il serait comparativement très lent (par rapport à la vérification locale d'un fichier) et risquerait peut-être de rencontrer des problèmes de limitation de débit ou de réseau, ou votre instance EC2 n'a peut-être même pas accès réseau extérieur.
  7. La deuxième suggestion dans la réponse de @ Chris-Montanaro de vérifier http://169.254.169.254/ est un peu meilleure, mais un autre intervenant note que d'autres fournisseurs de cloud offrent cette URL de métadonnées d'instance disponible. Vous devez donc faire attention à éviter les faux points positifs. En outre, il sera toujours beaucoup plus lent qu'un fichier local. J'ai vu cette vérification être particulièrement lente (plusieurs secondes pour revenir) sur des instances très chargées. De plus, vous devez vous rappeler de passer un -mou --max-timeargument curl pour éviter la pendaison pendant très longtemps, en particulier sur une instance non-EC2 où cette adresse peut conduire à nulle part et se bloquer (comme dans la réponse de @ algale ).

En outre, je ne vois pas que quiconque ait mentionné le recours documenté d'Amazon consistant à rechercher le fichier (possible) /sys/devices/virtual/dmi/id/product_uuid.

Qui savait que déterminer si vous utilisiez EC2 pouvait être si compliqué?! OK, maintenant que nous avons (la plupart) des problèmes avec les approches énumérées, voici un extrait de code suggéré pour vérifier si vous utilisez bien EC2. Je pense que cela devrait fonctionner généralement sur presque toutes les instances Linux, les instances Windows étant un exercice pour le lecteur.

#!/bin/bash

# This first, simple check will work for many older instance types.
if [ -f /sys/hypervisor/uuid ]; then
  # File should be readable by non-root users.
  if [ `head -c 3 /sys/hypervisor/uuid` == "ec2" ]; then
    echo yes
  else
    echo no
  fi

# This check will work on newer m5/c5 instances, but only if you have root!
elif [ -r /sys/devices/virtual/dmi/id/product_uuid ]; then
  # If the file exists AND is readable by us, we can rely on it.
  if [ `head -c 3 /sys/devices/virtual/dmi/id/product_uuid` == "EC2" ]; then
    echo yes
  else
    echo no
  fi

else
  # Fallback check of http://169.254.169.254/. If we wanted to be REALLY
  # authoritative, we could follow Amazon's suggestions for cryptographically
  # verifying their signature, see here:
  #    https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
  # but this is almost certainly overkill for this purpose (and the above
  # checks of "EC2" prefixes have a higher false positive potential, anyway).
  if $(curl -s -m 5 http://169.254.169.254/latest/dynamic/instance-identity/document | grep -q availabilityZone) ; then
    echo yes
  else
    echo no
  fi

fi

Évidemment, vous pourriez élargir ceci avec encore plus de vérifications de substitution et inclure la paranoïa au sujet de la gestion, par exemple d'un faux positif /sys/hypervisor/uuidpour commencer avec "ec2" par hasard, etc. Mais il s’agit là d’une solution suffisante pour illustrer notre propos et probablement pour presque tous les cas d’utilisation non pathologiques.

[†] Vous avez obtenu cette explication du support AWS à propos de la modification des instances c5 / m5:

Les instances C5 et M5 utilisent une nouvelle pile d'hyperviseur et les pilotes de noyau associés ne créent pas de fichiers dans sysfs (monté sur / sys), contrairement aux pilotes Xen utilisés par les autres types d'instance / anciens . Le meilleur moyen de détecter si le système d'exploitation s'exécute sur une instance EC2 consiste à prendre en compte les différentes possibilités répertoriées dans la documentation que vous avez liée .

Josh Kupershmidt
la source
4
Oui compagnon de voyage en 2018 ... c'est la réponse que vous cherchiez.
russellpierce
reading / sys / devices / virtual / dmi / id / product_uuid requiert également des privilèges root
Thayne le
@ Thane correct - c'est ce que elifdit le commentaire au-dessus de ce bloc, et c'est pourquoi le eliftest utilise l' -ropérateur de test, qui vérifie si le fichier existe et si vous avez les droits de lecture requis.
Josh Kupershmidt le
Une note supplémentaire sur les métadonnées 169.254.169.254 - elle n’est pas toujours prête au démarrage. Si vous avez besoin de ces métadonnées pour un script de démarrage, vous devrez continuer à interroger jusqu'à ce qu'il soit prêt. Je l'ai vu prendre jusqu'à 30 secondes après que l'instance a commencé à exécuter ses scripts de démarrage cloud-init.
vacri
15

Recherchez les métadonnées par le nom de domaine interne EC2 au lieu de l'adresse IP, ce qui renverra une défaillance DNS rapide si vous n'êtes pas sur EC2 et évite les conflits IP ou les problèmes de routage:

curl -s http://instance-data.ec2.internal && echo "EC2 instance!" || echo "Non EC2 instance!"

Sur certains systèmes, distros très basiques, ou très tôt à des stades de installion boucle ne sont pas disponibles. Utiliser wget à la place:

wget -q http://instance-data.ec2.internal && echo "EC2 instance!" || echo "Non EC2 instance!"
Jer
la source
4
Malheureusement, semble échouer dans VPC!
Ashe
2
De plus , ne pas utiliser le caractère point d'exclamation guillemets doubles - votre écho peut sauter avec -bash: !": event not found. Utilisez des guillemets simples pour ceux à la echoplace.
Josh Kupershmidt
1
cela suppose probablement que le serveur utilise toujours des serveurs DNS EC2 qui connaissent la zone ec2.internal et que personne n'a modifié /etc/resolv.conf en 8.8.8.8 ni lancé sa propre infrastructure DNS.
Lamont
1
AWS semble avoir cassé cela. Je ne peux plus résoudre instance-data.ec2.internal. instance-data.us-west-2.compute.internal fonctionne bien, du moins pour le moment.
Bryan Larsen
14

Si l'objectif est de déterminer s'il s'agit d'une instance EC2 OU d'un autre type d'instance de cloud, telle que Google, dmidecodefonctionne très bien et qu'aucun réseau n'est requis. J'aime cela par rapport à d'autres approches car le chemin de l'URL des métadonnées est différent pour EC2 et GCE.

# From a google compute VM
$ sudo dmidecode -s bios-version
Google

# From an amazon ec2 VM
$ sudo dmidecode -s bios-version
4.2.amazon
Tamale
la source
Je m'attendrais à ce que cela fonctionne correctement dans d'autres environnements de machine virtuelle et même sur du matériel réel - je ne m'attends pas à ce que les fournisseurs de matériel envoient des systèmes où la version du bios dit "amazon" ...
Guss
Sur mes instances Ubuntu EC2, cela renvoie 1.0- aucune mention de amazon.
Nate
5

Les noms d'hôte sont susceptibles de changer, lancez un whois contre votre IP publique:

if [[ ! -z $(whois $(curl -s shtuff.it/myip/short) | grep -i amazon) ]]; then 
  echo "I'm Amazon"
else 
  echo "I'm not Amazon"
fi

ou cliquez sur l'URL de méta-données AWS

if [[ ! -z $(curl -s http://169.254.169.254/1.0/) ]]; then 
  echo "I'm Amazon"
else 
  echo "I'm not Amazon"
fi
Chris Montanaro
la source
2
Ajoutez un --connect-timeout 1 à la deuxième instruction curl pour un échec rapide si vous n’exécutez pas sur EC2.
Jonathan Oliver
1
FWIW, l’utilisation de l’URL de métadonnées peut indiquer qu’elle s’exécute en tant qu’instance cloud, mais ne peut pas déterminer avec certitude si c’est spécifiquement EC2. OpenStack et Eucalyptus utilisent également le même URI de métadonnées. Je sais que cela ne va pas sans mal, mais pour mon travail, le fournisseur de cloud computing compte.
EmmEff
5

Cela fonctionne également bien pour les hôtes Linux dans ec2 et ne nécessite pas le réseau ni les délais d'attente associés:

grep -q amazon /sys/devices/virtual/dmi/id/bios_version

Cela fonctionne car Amazon définit cette entrée comme suit:

$ cat /sys/devices/virtual/dmi/id/bios_version 4.2.amazon

Spkane
la source
2018-05-01; semble être invalide sur les instances M5 exécutant Ubuntu.
russellpierce
Sur mes instances Ubuntu EC2, cela retourne 1.0. Aucune mention de amazon.
Nate
3
test -f /sys/hypervisor/uuid -a `head -c 3 /sys/hypervisor/uuid` == ec2 && echo yes

mais je ne sais pas à quel point c'est portable dans toutes les distributions.

Hannes
la source
2
Eh bien, cela ne fonctionnera certainement pas sur les instances Windows EC2.
ceejayoz
1
Je préfère cette méthode car elle n'implique pas une interaction réseau pouvant se bloquer pour toutes sortes de raisons. L'utilisation des délais d'attente pour un échange HTTP n'est pas garantie pour empêcher les blocages. Je me fiche des instances de Windows.
Hannes
C'est exactement ce dont j'avais besoin! Bien mieux que de boucler quelque chose, merci!
Qwertzguy
1
Pensez à utiliser l’UUID complet, au cas où un UUID d’hyperviseur d’un autre fournisseur commence également par «ec2». La probabilité que cela se produise est de 1 sur 4096, ce qui n’est pas négligeable.
Hannes
1
En fait, comparer l’UUID entier ne fonctionne pas car j’ai vu plusieurs UUID d’hyperviseurs différents dans la nature. Ils commencent tous par "ec2" cependant, donc cette réponse fonctionne telle quelle.
Hannes
3

Réponse rapide:

if [[ -f /sys/devices/virtual/dmi/id/product_uuid ]] && \
    grep -q "^EC2" /sys/devices/virtual/dmi/id/product_uuid
then
    echo "IS EC2"
else
    echo "NOT EC2"
fi

J'utilisais l'une des réponses publiées ici depuis plus d'un an, mais cela ne fonctionnait pas avec les nouveaux types d'instances «c5» (je travaille actuellement à la mise à niveau à partir de «c4»).

J'aime cette solution car elle semble être la moins susceptible de se briser à l'avenir.

Sur les types d'instance les plus anciens et les plus récents, ce fichier est présent et commence par «EC2». J'ai vérifié Ubuntu sous VirtualBox (que je dois également prendre en charge) et il contient la chaîne 'VirtualBox'.

Comme l'a noté une affiche précédente (mais c'était facile à manquer) - il existe une documentation d'Amazon sur les moyens de le faire - qui inclut ma réponse.

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html

Zach Anthony
la source
2

Peut-être que vous pouvez utiliser "facter":

"Facter est une bibliothèque multi-plateforme permettant de récupérer des informations simples sur le système d’exploitation, telles que le système d’exploitation, la distribution Linux ou l’adresse MAC."

http://www.puppetlabs.com/puppet/related-projects/facter/

Par exemple, si nous examinons le fait ec2 (facter-1.6.12 / lib / facter / ec2.rb):

require 'facter/util/ec2'
require 'open-uri'

def metadata(id = "")
  open("http://169.254.169.254/2008-02-01/meta-data/#{id||=''}").read.
    split("\n").each do |o|
    key = "#{id}#{o.gsub(/\=.*$/, '/')}"
    if key[-1..-1] != '/'
      value = open("http://169.254.169.254/2008-02-01/meta-data/#{key}").read.
        split("\n")
      symbol = "ec2_#{key.gsub(/\-|\//, '_')}".to_sym
      Facter.add(symbol) { setcode { value.join(',') } }
    else
      metadata(key)
    end
  end
end

def userdata()
  begin
    value = open("http://169.254.169.254/2008-02-01/user-data/").read.split
    Facter.add(:ec2_userdata) { setcode { value } }
  rescue OpenURI::HTTPError
  end
end

if (Facter::Util::EC2.has_euca_mac? || Facter::Util::EC2.has_openstack_mac? ||
    Facter::Util::EC2.has_ec2_arp?) && Facter::Util::EC2.can_connect?

  metadata
  userdata
else
  Facter.debug "Not an EC2 host"
end
jmprusi
la source
1

Si vous avez installé curl, cette commande retournera 0 si vous utilisez EC2 et une valeur différente de zéro si vous n’êtes pas:

curl --max-time 3 http://169.254.169.254/latest/meta-data/ami-id 2>/dev/null 1>/dev/null`

Il tente d'extraire les métadonnées EC2 déclarant l'identificateur AMI-ID. Si cela ne réussit pas au bout de 3 secondes, cela suppose qu’il ne fonctionne pas dans EC2.

algue
la source
0

Un peu tard pour cette soirée, mais je suis tombé sur ce post et puis j'ai trouvé cette documentation AWS:

Pour une méthode d'identification définitive et vérifiée par cryptographie d'une instance EC2, vérifiez le document d'identité de l'instance, y compris sa signature. Ces documents sont disponibles sur chaque instance EC2 à l'adresse locale non routable http://169.254.169.254/latest/dynamic/instance-identity/

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html

Ceci, bien sûr, nécessite la surcharge du réseau bien que vous puissiez définir le délai d’arrêt de la manière suivante:

curl -s --connect-timeout 5 http://169.254.169.254/latest/dynamic/instance-identity/

Cela définit le délai d'attente à 5 secondes.

Brooks
la source