Как узнать, является ли машина экземпляром EC2


43

Я хотел бы запустить некоторые сценарии на хостах, которые являются экземплярами EC2, но я не знаю, как убедиться, что хост действительно является экземпляром EC2.

Я сделал несколько тестов, но этого недостаточно:

  • Проверьте, доступен ли двоичный файл ec2_userdata (но это не всегда будет так)
  • Проверьте наличие " http://169.254.169.254/latest/meta-data " (но будет ли это всегда так? И что это за "магический IP"?)


На самом деле это адрес APIPA, который довольно странно использовать в качестве ссылки для критически важной службы, такой как поиск метаданных.
— Матье Серда

2
Диапазоны IP-адресов EC2 являются общедоступными (хотя время от времени меняются). Если вы следите за текущим списком, вы можете проверить IP экземпляров по этим диапазонам.
— Карма Fusebox

2
Не полагайтесь на 169.254.169.254, если вы хотите EC2, и только EC2 - EC2-подобные системы, такие как Eucalyptus, также поддерживают его. eng.eucalyptus.com/customer/portal/articles/…
— ceejayoz

1
Вам нужен метод для работы против злоумышленника, у которого есть root на хосте, и который пытается обмануть вас, думая, что это экземпляр EC2 для его собственных злонамеренных целей? Если вы это сделаете, то это будет намного сложнее.
— Майк Скотт

Ответы:


3

На самом деле, существует очень простой способ определить, является ли хост экземпляром EC2: проверить обратный поиск вашего публичного IP-адреса. Обороты EC2 довольно трудно пропустить.

Кроме того, если вы не изменили его, имя хоста должно быть вашим обратным, что облегчит его обнаружение.

Вы также можете использовать «магический IP», о котором вы говорили, поскольку это действительно стандартный способ получения тегов экземпляра EC2, однако, если вы не находитесь в сети EC2, вам придется подождать тайм-аут, который обычно не желательно ...

Если этих методов недостаточно, просто сделайте whois своего IP-адреса и проверьте, находитесь ли вы внутри IP-блока Amazon EC2.

РЕДАКТИРОВАТЬ: Вы можете использовать этот маленький бит оболочки:

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

Осторожно, хотя [[это башизм. Вы также можете использовать Python или Perl uniline, YMMV.


13
это не работает в VPC или в среде, где вы изменили имя хоста; например. если ваши машины находятся в domain.local
— Preflightsiren

2
бит имени хоста просто обязан потерпеть неудачу.
— Дэн Притц

3
hostname -dвозвращаетсяeu-west-1.compute.internal
— Bulletmagnet

42

Изменен ответ Ханнеса, чтобы избежать сообщений об ошибках и включить пример использования в скрипт:

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

Это не работает в экземплярах Windows. Преимущество перед скручиванием заключается в том, что он близок к мгновенному как для EC2, так и для не EC2.


4
AWS также, похоже, рекомендует делать это следующим образом. Docs.aws.amazon.com/AWSEC2/latest/UserGuide/…
— Майк,

3
Мне нравится этот метод. Просто имейте в виду, что система не-EC2, работающая под гипервизором, может генерировать UUID, который начинается с ec2- ложное срабатывание. Это маловероятно (шанс 1 на 256) и только в том случае, если вы используете гипервизор, который заполняет этот файл. Вот почему в приведенной выше документации написано «вы, вероятно, смотрите на экземпляр EC2».
— Nate

1
@Nate, хорошая мысль, но разве это не должен быть шанс 1 на 4096? (16 х 16 х 16)
— подстановочный

2
@Wildcard: я не могу редактировать свой комментарий, но это правильно.
— Nate

7
ОПАСНОСТЬ! Этот метод надежно работал для нас в течение многих лет ... до недавнего времени, с последними типами c5 и m5, у которых нет этого файла . Поэтому я должен добавить запасную проверку 169.254.169.254 для обработки этих экземпляров.
— Джош Купершмидт

20

Сначала я почувствовал необходимость опубликовать новый ответ из-за следующих тонких проблем с существующими ответами и после получения вопроса о моем комментарии к ответу @ qwertzguy . Вот проблемы с текущими ответами:

  1. Общепринятый ответ от @MatthieuCerda определенно не работает надежно, по крайней мере не на каких - либо VPC случаях я сверяюсь. (В моих случаях я получаю имя VPC для hostname -d, которое используется для внутреннего DNS, а не что-либо с "amazonaws.com" в нем.)
  2. Высоким проголосовал ответ от @qwertzguy не работает на новых М5 или с5 случаях , которые не имеют этот файл. Amazon пренебрегает документированием этого изменения поведения AFAIK, хотя на странице документа по этому вопросу написано «... Если / sys / hypervisor / uuid существует ...». Я спросил службу поддержки AWS, было ли это изменение преднамеренным, см. Ниже †.
  3. Ответ от @Jer не обязательно будет работать везде , потому что instance-data.ec2.internalDNS поиск не может работать. На экземпляре Ubuntu EC2 VPC, на котором я только что тестировал, я вижу: $ curl http://instance-data.ec2.internal curl: (6) Could not resolve host: instance-data.ec2.internal что может привести к ложному выводу кода, полагающегося на этот метод, что он не на EC2!
  4. Ответ использоватьdmidecode от @tamale может работать, но полагается на вас.) , Имеющий dmidecodeдоступны на вашем экземпляре и б.) , Имеющих корень или sudoбеспарольный способность из вашего кода.
  5. Ответ для проверки / системы / устройства / виртуальный / DMI / ID / bios_version из @spkane угрожающе в заблуждение! Я проверил один экземпляр Ubuntu 14.04 m5 и получил bios_versionоф 1.0. Этот файл вообще не документирован в документации Amazon , поэтому я бы не стал полагаться на него.
  6. Первая часть ответа от @ Chris-Montanaro о проверке ненадежного стороннего URL-адреса и использовании whoisна результат проблематична на нескольких уровнях. Обратите внимание, что URL, предложенный в этом ответе, - это страница 404 прямо сейчас! Даже если вы найдете стороннюю службу, которая работает, она будет сравнительно очень медленной (по сравнению с локальной проверкой файла) и, возможно , столкнется с проблемами ограничения скорости или сетевыми проблемами, или, возможно, ваш экземпляр EC2 даже не имеет внешний доступ к сети.
  7. Второе предложение в ответе @ Chris-Montanaro о проверке http://169.254.169.254/ немного лучше, но другой комментатор отмечает, что другие облачные провайдеры предоставляют этот URL-адрес метаданных экземпляра, поэтому вам следует быть осторожным, чтобы избежать ложных позитивы. Кроме того, он все равно будет намного медленнее, чем локальный файл, я видел, что эта проверка была особенно медленной (несколько секунд до возврата) в сильно загруженных экземплярах. Кроме того, вы должны не забывать передавать аргумент -mили --max-timeв curl, чтобы избежать его зависания в течение очень долгого времени, особенно в случае экземпляра, не относящегося к EC2, где этот адрес может ни к чему не приводить и зависать (как в ответе @ algal ).

Кроме того, я не вижу, чтобы кто-либо упоминал о задокументированном запасном варианте проверки (возможного) файла Amazon/sys/devices/virtual/dmi/id/product_uuid .

Кто знал, что определить, работаете ли вы на EC2, может быть так сложно ?! Хорошо, теперь, когда у нас есть (большинство) проблем с перечисленными подходами, вот предложенный фрагмент кода bash, чтобы проверить, работаете ли вы на EC2. Я думаю, что это должно работать в основном на любых экземплярах Linux, экземпляры Windows - это упражнение для читателя.

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

Очевидно, вы могли бы расширить это с помощью еще большего количества резервных проверок и включить паранойю по поводу обработки, например, ложного срабатывания /sys/hypervisor/uuidпри случайном запуске с «ec2» и так далее. Но это достаточно хорошее решение для иллюстративных целей и, вероятно, почти для всех непатологических вариантов использования.

[†] Получил это объяснение от поддержки AWS по поводу изменений для экземпляров c5 / m5:

Экземпляры C5 и M5 используют новый стек гипервизора, и связанные драйверы ядра не создают файлы в sysfs (который монтируется в / sys), как драйверы Xen, используемые другими / более старыми типами экземпляров . Лучший способ определить, работает ли операционная система на экземпляре EC2, - это учесть различные возможности, перечисленные в документации, которую вы связали .


4
Да, попутчик в 2018 году ... это ответ, который вы искали.
— russellpierce

Чтение / sys / devices / virtual / dmi / id / product_uuid также требует привилегий root
— Thayne

@ Правильно. Так elifговорится в комментарии над этим блоком, и поэтому в elifтесте используется -rоператор теста, который проверяет, существует ли файл и есть ли у вас разрешения на чтение для этого файла.
— Джош Купершмидт

Дополнительное примечание к метаданным 169.254.169.254 - оно не всегда готово во время загрузки. Если вам нужны эти метаданные для загрузочного скрипта, вам нужно будет продолжать опрос, пока он не будет готов. Я видел, что прошло около 30 секунд после того, как экземпляр запустил свои загрузочные скрипты cloud-init.
— Vacri

15

Найдите метаданные по внутреннему доменному имени EC2 вместо IP-адреса, которое вернет быстрый сбой DNS, если вы не используете EC2, и позволит избежать конфликтов IP-адресов или проблем маршрутизации:

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

На некоторых дистрибутивах, очень базовых системах или на ранних стадиях установки, curl недоступен. Вместо этого используйте wget :

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

4
К сожалению, похоже, что он не работает в VPC!
— Эш

2
Также не используйте символ восклицательного знака в двойных кавычках - ваше эхо может взорваться с -bash: !": event not found. echoВместо этого используйте одинарные кавычки .
— Джош Купершмидт

1
это, вероятно, предполагает, что сервер все еще использует DNS-серверы EC2, которые знают о зоне ec2.internal, и что никто не изменил /etc/resolv.conf на 8.8.8.8 или откатил свою собственную DNS-инфраструктуру.
— Ламонт

1
AWS, кажется, сломал это. Я больше не могу разрешить экземпляр-data.ec2.internal. instance-data.us-west-2.compute.internal работает, хотя, по крайней мере, на данный момент.
— Брайан Ларсен

14

Если цель состоит в том, чтобы определить, является ли это экземпляром EC2 ИЛИ другим типом облачного экземпляра, таким как google, то он dmidecodeработает очень хорошо, и не требуется никаких сетей. Мне нравится это против некоторых других подходов, потому что путь метаданных url различен для EC2 и 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

Я ожидал бы, что это будет хорошо работать в других средах виртуальных машин и даже на реальном оборудовании - я не ожидаю, что какие-либо производители оборудования будут поставлять системы, где версия BIOS говорит «амазонка» ...
— Guss

На моих экземплярах Ubuntu EC2 это возвращается 1.0- без упоминания amazon.
— Nate

5

Имена хостов могут измениться, запустите whois против вашего публичного IP:

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

или нажмите URL-адрес метаданных AWS

if [[ ! -z $(curl -s http://169.254.169.254/1.0/) ]]; then 
  echo "I'm Amazon"
else 
  echo "I'm not Amazon"
fi

2
Добавьте параметр --connect-timeout 1 во второй оператор curl, чтобы он быстро завершился неудачей, если вы не работаете в EC2.
— Джонатан Оливер

1
FWIW, используя URL-адрес метаданных, может указывать на то, что он работает как облачный экземпляр, но не может окончательно определить, является ли он конкретно EC2. OpenStack и Eucalyptus также используют один и тот же URI метаданных. Я знаю, что это выбор гнид, но для моей работы, какой облачный провайдер имеет значение.
— EmmEff

5

Это также хорошо работает для хостов Linux в ec2 и не требует сети и каких-либо связанных таймаутов:

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

Это работает, потому что Amazon определяет эту запись следующим образом:

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


2018-05-01; кажется недействительным на экземплярах M5 под управлением Ubuntu.
— russellpierce

На моих экземплярах Ubuntu EC2 это возвращается 1.0. Нет упоминания о amazon.
— Nate

3
test -f /sys/hypervisor/uuid -a `head -c 3 /sys/hypervisor/uuid` == ec2 && echo yes

но я не знаю, насколько это переносимо между дистрибутивами.


2
Ну, это, конечно, не будет работать на экземплярах Windows EC2.
— ceejayoz

1
Я предпочитаю этот метод, поскольку он не предполагает сетевого взаимодействия, которое может зависать по разным причинам. Использование таймаутов для обмена HTTP не гарантирует предотвращения зависаний. Меня не волнуют экземпляры Windows.
— Ханнес

Это именно то, что мне было нужно! Гораздо лучше, чем свернуться, спасибо!
— qwertzguy

1
Подумайте об использовании полного UUID, на случай, если UUID гипервизора другого производителя также начинается с "ec2". Вероятность того, что это произойдет, равна 1 из 4096, что не является незначительным.
— Ханнес

1
На самом деле, сравнение всего UUID не работает, так как я видел несколько различных UUID гипервизора в дикой природе. Все они начинаются с "ec2", поэтому этот ответ работает как есть.
— Ханнес

3

Быстрый ответ:

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

Я использовал один из ответов, опубликованных здесь, более года, но он не работает с новыми типами экземпляров 'c5' (сейчас я работаю над обновлением с 'c4').

Мне нравится это решение, потому что оно вряд ли сломается в будущем.

На старых типах экземпляров и на более новых типах этот файл присутствует и начинается с 'EC2'. Я проверил Ubuntu, работающий на VirtualBox (который мне также нужно поддерживать), и он содержит строку «VirtualBox».

Как отмечал предыдущий автор (но это было легко пропустить) - есть документация Amazon о том, как это сделать, - в том числе и мой ответ.

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


2

Возможно, вы можете использовать «facter»:

«Facter - это кроссплатформенная библиотека для извлечения простых фактов об операционной системе, таких как операционная система, дистрибутив Linux или MAC-адрес».

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

Например, если мы посмотрим на факт 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

1

Если у вас установлен curl, эта команда вернет 0, если вы работаете в EC2, и ненулевое, если вы не:

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

Он пытается получить метаданные EC2, объявляющие AMI-ID. Если это не удалось через 3 секунды, предполагается, что он не работает в EC2.


0

Немного опоздал на эту вечеринку, однако я наткнулся на этот пост и нашел документацию по AWS:

Для окончательного и криптографически проверенного метода идентификации экземпляра EC2 проверьте документ, удостоверяющий личность экземпляра, включая его подпись. Эти документы доступны в каждом экземпляре EC2 по локальному, не маршрутизируемому адресу http://169.254.169.254/latest/dynamic/instance-identity/

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

Это, конечно, требует сетевых издержек, хотя вы можете установить время ожидания curl следующим образом:

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

Это устанавливает время ожидания 5 с.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.