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

43

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

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

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

qwertzguy
источник
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

spkane
источник
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
jmprusi
источник
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 с.

Brooks
источник