Cómo saber si una máquina es una instancia EC2

43

Me gustaría ejecutar algunos scripts en hosts que son instancias de EC2, pero no sé cómo asegurarme de que el host sea realmente una instancia de EC2.

He hecho algunas pruebas, pero esto no es suficiente:

  • Pruebe que el binario ec2_userdata esté disponible (pero esto no siempre será cierto)
  • Pruebe la disponibilidad de " http://169.254.169.254/latest/meta-data " (pero ¿será esto siempre cierto? ¿Y qué es esta "IP mágica"?)
Kelindil
fuente
En realidad, es una dirección APIPA, que es bastante extraña de usar como referencia para un servicio crítico como la recuperación de metadatos.
Matthieu Cerda
2
Los rangos de IP de EC2 son públicos (aunque varían de vez en cuando). Si se mantiene al día con una lista actual, puede verificar la IP de las instancias en esos rangos.
Karma Fusebox
2
No confíe en 169.254.169.254 si desea EC2 y solo EC2: los sistemas similares a EC2 como Eucalyptus también lo admiten. engagement.eucalyptus.com/customer/portal/articles/…
ceejayoz
1
¿Necesita el método para trabajar contra un atacante que tiene root en el host y está tratando de engañarlo para que piense que es una instancia de EC2 para sus propios fines maliciosos? Si lo haces, será mucho más difícil.
Mike Scott

Respuestas:

3

Bueno, en realidad, hay una forma muy simple de detectar si el host es una instancia EC2: verifique la búsqueda inversa de su IP pública. Los reveses de EC2 son bastante difíciles de perder.

Además, si no lo modificó, el nombre de host debe ser el inverso, lo que facilitará aún más su detección.

También puede usar la "IP mágica" de la que habló, ya que de hecho es la forma estándar de obtener etiquetas de instancia EC2, sin embargo, si no está en una red EC2, tendrá que esperar un tiempo de espera, que generalmente no es deseable...

Si estos métodos no son suficientes, solo haga un whois de su IP y verifique si está dentro y un bloqueo de IP de Amazon EC2.

EDITAR: puede usar este pequeño bit de 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

Pero cuidado, [[es un bashismo. También puede usar Python o Perl uniline, YMMV.

Matthieu Cerda
fuente
13
esto no funciona en una VPC o en un entorno donde ha cambiado el nombre de host; p.ej. si sus máquinas están en domain.local
Preflightsiren
2
el bit del nombre de host está destinado a fallar.
Dan Pritts
3
hostname -dvuelveeu-west-1.compute.internal
Bulletmagnet
42

Se cambió la respuesta de Hannes para evitar mensajes de error e incluir ejemplos de uso en el script:

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

Esto no funciona en instancias de Windows. La ventaja sobre el rizo es que es casi instantánea tanto en EC2 como no EC2.

qwertzguy
fuente
44
AWS también parece recomendar hacerlo de esta manera docs.aws.amazon.com/AWSEC2/latest/UserGuide/…
Mike
3
Me gusta este metodo Solo tenga en cuenta que un sistema no EC2 que se ejecuta bajo un hipervisor podría generar un UUID que comienza con ec2un falso positivo. Es poco probable (una probabilidad de 1 en 256) y solo si está utilizando un hipervisor que llena ese archivo. Es por eso que la documentación vinculada anteriormente dice " probablemente estés viendo una instancia de EC2".
Nate
1
@Nate, buen punto, pero ¿no debería ser una probabilidad de 1 en 4096? (16 x 16 x 16)
Comodín el
2
@Wildcard: No puedo editar mi comentario, pero es correcto.
Nate
77
¡PELIGRO! Este método ha funcionado de manera confiable para nosotros durante años ... hasta hace poco, con los últimos tipos de c5 y m5 que no tienen este archivo presente . Así que tengo que agregar una verificación de respaldo de 169.254.169.254 para manejar esas instancias.
Josh Kupershmidt
20

Primero, sentí la necesidad de publicar una nueva respuesta debido a los siguientes problemas sutiles con las respuestas existentes, y después de recibir una pregunta sobre mi comentario sobre la respuesta de @ qwertzguy . Aquí están los problemas con las respuestas actuales:

  1. La respuesta aceptada de @MatthieuCerda definitivamente no funciona correctamente, al menos no en cualquier instancia de VPC he comprobado en contra. (En mis casos, obtengo un nombre de VPC para hostname -d, que se utiliza para DNS interno, no nada con "amazonaws.com").
  2. La respuesta más votada de @qwertzguy no funciona en las nuevas instancias m5 o c5 , que no tienen este archivo. Amazon no documenta este cambio de comportamiento AFAIK, aunque la página del documento sobre este tema dice "... Si / sys / hypervisor / uuid existe ...". Le pregunté al soporte de AWS si este cambio fue intencional, ver más abajo †.
  3. La respuesta de @Jer no necesariamente funciona en todas partes porque la instance-data.ec2.internalbúsqueda de DNS puede no funcionar. En una instancia de Ubuntu EC2 VPC que acabo de probar, veo: ¡ $ curl http://instance-data.ec2.internal curl: (6) Could not resolve host: instance-data.ec2.internal lo que causaría que el código que se basa en este método concluya falsamente que no está en EC2!
  4. La respuesta para usardmidecode de @tamale puede funcionar, pero depende de usted a.) Tener dmidecodedisponible en su instancia, y b.) Tener sudocapacidad de root o sin contraseña desde su código.
  5. ¡La respuesta a check / sys / devices / virtual / dmi / id / bios_version de @spkane es peligrosamente engañosa! Verifiqué una instancia de Ubuntu 14.04 m5 y obtuve una bios_versionde 1.0. Este archivo no está documentado en absoluto en el documento de Amazon , por lo que realmente no confiaría en él.
  6. La primera parte de la respuesta de @ Chris-Montanaro para verificar una URL de terceros no confiable y usarla whoisen el resultado es problemática en varios niveles. Tenga en cuenta que la URL sugerida en esa respuesta es una página 404 en este momento. Incluso si lo hizo encontrar un servicio de tercera partes que se hizo el trabajo, sería comparativamente muy lenta (en comparación con la comprobación de un archivo de forma local) y posiblemente tenga problemas que limitan la velocidad o problemas de red, o, posiblemente, la instancia EC2 no tiene ni siquiera acceso a la red externa.
  7. La segunda sugerencia en la respuesta de @ Chris-Montanaro para verificar http://169.254.169.254/ es un poco mejor, pero otro comentarista señala que otros proveedores de la nube hacen que esta URL de metadatos de instancia esté disponible, por lo que debe tener cuidado para evitar falsas Positivos Además, seguirá siendo mucho más lento que un archivo local, he visto que esta comprobación es especialmente lenta (varios segundos para volver) en instancias con mucha carga. Además, debe recordar pasar un argumento -mo --max-timerizo para evitar que se cuelgue durante mucho tiempo, especialmente en una instancia que no sea EC2, donde esta dirección puede llevar a ninguna parte y colgarse (como en la respuesta de @ algal ).

Además, no veo que nadie haya mencionado el respaldo documentado de Amazon para verificar el (posible) archivo /sys/devices/virtual/dmi/id/product_uuid.

¿Quién sabía que determinar si estás ejecutando EC2 podría ser tan complicado? Bien, ahora que tenemos (la mayoría) de los problemas con los enfoques enumerados, aquí hay un fragmento de bash sugerido para verificar si está ejecutando en EC2. Creo que esto debería funcionar en general en casi cualquier instancia de Linux, las instancias de Windows son un ejercicio para el lector.

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

Obviamente, podría expandir esto con más controles de respaldo e incluir paranoia sobre el manejo, por ejemplo, de un falso positivo que /sys/hypervisor/uuidocurra para comenzar con "ec2" por casualidad, etc. Pero esta es una solución suficientemente buena para fines ilustrativos y probablemente para casi todos los casos de uso no patológicos.

[†] Recibí esta explicación del soporte de AWS sobre el cambio para las instancias de c5 / m5:

Las instancias C5 y M5 usan una nueva pila de hipervisor y los controladores de kernel asociados no crean archivos en sysfs (que está montado en / sys) como lo hacen los controladores Xen utilizados por los otros tipos de instancias anteriores . La mejor manera de detectar si el sistema operativo se ejecuta en una instancia EC2 es tener en cuenta las diferentes posibilidades enumeradas en la documentación que ha vinculado .

Josh Kupershmidt
fuente
44
Sí, compañero de viaje en 2018 ... esta es la respuesta que has estado buscando.
russellpierce
lectura / sys / devices / virtual / dmi / id / product_uuid también requiere privilegios de root
Thayne
@Thayne correcto: eso es lo que elifdice el comentario sobre ese bloque, y es por eso que la elifprueba utiliza el -roperador de prueba, que verifica si el archivo existe y si tiene permisos de lectura para el archivo.
Josh Kupershmidt
Una nota adicional sobre los metadatos 169.254.169.254 : no siempre está lista en el momento del arranque. Si necesita esos metadatos para un bootscript, necesitará seguir encuestando hasta que esté listo. Lo he visto tomar hasta 30 segundos después de que la instancia ha comenzado a ejecutar sus inicios de arranque en la nube.
vacri
15

Busque los metadatos por el nombre de dominio interno EC2 en lugar de IP, lo que devolverá una falla rápida de DNS si no está en EC2, y evita conflictos de IP o problemas de enrutamiento:

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

En algunas distribuciones, sistemas muy básicos, o muy temprano en las etapas Installion rizo no está disponible. Usando wget en su lugar:

wget -q http://instance-data.ec2.internal && echo "EC2 instance!" || echo "Non EC2 instance!"
Jer
fuente
44
¡Desafortunadamente, parece fallar en VPC!
Ashe
2
Asimismo, no utilice el carácter de signo de exclamación dentro de comillas dobles - el eco puede volar con -bash: !": event not found. Use comillas simples para esos echos en su lugar.
Josh Kupershmidt
1
Esto probablemente supone que el servidor todavía está utilizando servidores DNS EC2 que conocen la zona ec2.internal y que nadie ha cambiado /etc/resolv.conf a 8.8.8.8 o ha lanzado su propia infraestructura DNS.
lamont
1
AWS parece haber roto esto. Ya no puedo resolver instance-data.ec2.internal. instance-data.us-west-2.compute.internal funciona, al menos por ahora.
Bryan Larsen
14

Si el objetivo es saber si se trata de una instancia EC2 O de otro tipo de instancia en la nube, como google, dmidecodefunciona muy bien y no se requiere una red. Me gusta esto frente a algunos de los otros enfoques porque la ruta de URL de metadatos es diferente para EC2 y 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
tamal
fuente
Esperaría que esto funcione bien en otros entornos de VM e incluso en hardware real. No espero que ningún proveedor de hardware envíe sistemas donde la versión de BIOS diga "amazon" ...
Guss
En mis instancias Ubuntu EC2, esto regresa 1.0, sin mencionarlo amazon.
Nate
5

Es probable que cambien los nombres de host, ejecute un whois contra su IP pública:

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

o pulse la url de metadatos de 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
fuente
2
Agregue un --connect-timeout 1 a la segunda instrucción curl para que falle rápidamente si no está ejecutando en EC2.
Jonathan Oliver
1
FWIW, el uso de la URL de metadatos puede indicar que se está ejecutando como una instancia de la nube, pero no puede determinar de manera concluyente si es específicamente EC2. OpenStack y Eucalyptus también usan el mismo URI de metadatos. Sé que esto es elegir liendres, pero para mi trabajo, qué proveedor de la nube es importante.
EmmEff
5

Esto también funciona bien para hosts Linux en ec2 y no requiere la red ni los tiempos de espera relacionados:

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

Esto funciona, porque Amazon define esta entrada así:

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

spkane
fuente
2018-05-01; parece no ser válido en instancias M5 que ejecutan Ubuntu.
russellpierce
En mis instancias Ubuntu EC2 esto vuelve 1.0. No hay mención de amazon.
Nate
3
test -f /sys/hypervisor/uuid -a `head -c 3 /sys/hypervisor/uuid` == ec2 && echo yes

pero no sé cuán portátil es esto en todas las distribuciones.

Hannes
fuente
2
Bueno, ciertamente no funcionará en instancias de Windows EC2.
ceejayoz
1
Prefiero este método, ya que no implica una interacción de red que puede bloquearse por todo tipo de razones. No se garantiza el uso de tiempos de espera para un intercambio HTTP para evitar bloqueos. No me importan las instancias de Windows.
Hannes
¡Eso es exactamente lo que necesitaba! Mucho mejor que rizar algo, ¡gracias!
qwertzguy
1
Considere usar el UUID completo, en caso de que el UUID del hipervisor de otro proveedor también comience con "ec2". La posibilidad de que eso ocurra es de 1 en 4096, lo que no es despreciable.
Hannes
1
En realidad, comparar todo el UUID no funciona ya que he visto múltiples UUID hipervisor diferentes en la naturaleza. Sin embargo, todos comienzan con "ec2", por lo que esta respuesta funciona como es.
Hannes
3

Respuesta rápida:

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

Había estado usando una de las respuestas publicadas aquí durante más de un año, pero no funciona en los nuevos tipos de instancia 'c5' (ahora estoy trabajando para actualizar desde 'c4').

Me gusta esta solución porque parece que es menos probable que se rompa en el futuro.

En los tipos de instancia más antiguos y los más nuevos, este archivo está presente y comienza con 'EC2'. Verifiqué Ubuntu que se ejecuta en VirtualBox (que también necesito admitir) y contiene la cadena 'VirtualBox'.

Como señaló un póster anterior (pero fue fácil pasarlo por alto), hay documentación de Amazon sobre formas de hacer esto, que incluye mi respuesta.

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

Zach Anthony
fuente
2

Quizás puedas usar "facter":

"Facter es una biblioteca multiplataforma para recuperar datos simples del sistema operativo, como el sistema operativo, la distribución de Linux o la dirección MAC".

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

Por ejemplo, si echamos un vistazo al hecho 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
fuente
1

Si tiene instalado curl, este comando devolverá 0 si está ejecutando dentro de EC2 y no cero si no:

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

Intenta extraer los metadatos EC2 que declaran la ID AMI. Si esto no tiene éxito después de 3 segundos, se supone que no se está ejecutando en EC2.

alga
fuente
0

Un poco tarde para esta fiesta, sin embargo, me encontré con esta publicación y luego encontré esta documentación de AWS:

Para obtener un método definitivo y verificado criptográficamente para identificar una instancia EC2, verifique el documento de identidad de la instancia, incluida su firma. Estos documentos están disponibles en cada instancia de EC2 en la dirección local no enrutable http://169.254.169.254/latest/dynamic/instance-identity/

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

Esto, por supuesto, requiere la sobrecarga de la red, aunque puede configurar el tiempo de espera de curvatura de la siguiente manera:

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

Eso establece el tiempo de espera en 5s.

Brooks
fuente