Jak sprawdzić, czy komputer jest instancją EC2

43

Chciałbym uruchomić kilka skryptów na hostach, które są instancjami EC2, ale nie wiem, jak się upewnić, że host jest naprawdę instancją EC2.

Przeprowadziłem kilka testów, ale to nie wystarczy:

  • Sprawdź, czy binarne ec2_userdata jest dostępne (ale nie zawsze będzie to prawdą)
  • Przetestuj dostępność „ http://169.254.169.254/latest/meta-data ” (ale czy to zawsze będzie prawda? I co to za „magiczne IP”?)
Kelindil
źródło
W rzeczywistości jest to adres APIPA, co jest dość dziwne, gdy używa się go jako odniesienia do krytycznej usługi, takiej jak pobieranie metadanych.
Matthieu Cerda
2
Zakresy adresów IP EC2 są publiczne (choć zmieniają się od czasu do czasu). Jeśli nadążasz za bieżącą listą, możesz sprawdzić IP instancji w odniesieniu do tych zakresów.
Karma Fusebox
2
Nie polegaj na 169.254.169.254, jeśli chcesz EC2 i obsługuje go tylko system podobny do EC2 - EC2, taki jak Eucalyptus. engage.eucalyptus.com/customer/portal/articles/…
ceejayoz
1
Czy potrzebujesz metody, aby działać przeciwko atakującemu, który ma root na hoście i próbuje oszukać cię, że jest to instancja EC2 dla jego własnych złośliwych celów? Jeśli to zrobisz, będzie znacznie trudniej.
Mike Scott,

Odpowiedzi:

3

Cóż, w rzeczywistości istnieje bardzo prosty sposób na wykrycie, czy host jest instancją EC2: sprawdź wsteczne wyszukiwanie swojego publicznego adresu IP. Odwrotności EC2 trudno przeoczyć.

Ponadto, jeśli go nie zmodyfikowałeś, nazwa hosta powinna być twoją odwrotnością, co dodatkowo ułatwi jego wykrycie.

Możesz także użyć „magicznego adresu IP”, o którym mówiłeś, ponieważ jest to rzeczywiście standardowy sposób uzyskiwania znaczników wystąpienia EC2, jednak jeśli nie jesteś w sieci EC2, musisz poczekać na limit czasu, co zwykle nie jest pożądany...

Jeśli te metody nie są wystarczające, po prostu zrób whois swojego adresu IP i sprawdź, czy jesteś w bloku i blokada IP Amazon EC2.

EDYCJA: Możesz użyć tego małego bitu powłoki:

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

Ostrożnie jednak [[to bzdura. Możesz także użyć Python lub Perl uniline, YMMV.

Matthieu Cerda
źródło
13
to nie działa w VPC lub środowisku, w którym zmieniłeś nazwę hosta; na przykład. jeśli twoje maszyny są w domenie.local
Preflightsiren
2
bit nazwy hosta po prostu zawiedzie.
Dan Pritts
3
hostname -dzwrotyeu-west-1.compute.internal
Bulletmagnet
42

Zmieniono odpowiedź Hannesa, aby uniknąć komunikatów o błędach i uwzględnić przykładowe użycie w skrypcie:

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

To nie działa w instancjach Windows. Przewaga nad zwijaniem polega na tym, że jest ona prawie natychmiastowa zarówno w EC2, jak i poza EC2.

qwertzguy
źródło
4
Wydaje się, że AWS zaleca robienie tego w ten sposób docs.aws.amazon.com/AWSEC2/latest/UserGuide/…
Mike
3
Podoba mi się ta metoda. Pamiętaj tylko, że system inny niż EC2 działający pod hiperwizorem może wygenerować UUID, który zaczyna się od ec2- fałszywie dodatni. Jest mało prawdopodobne (szansa 1 na 256) i tylko wtedy, gdy używasz hiperwizora wypełniającego ten plik. Dlatego w powyższej dokumentacji znajduje się informacja „ prawdopodobnie patrzysz na instancję EC2”.
Nate
1
@Nate, dobra uwaga, ale czy nie powinna to być szansa 1 na 4096? (16 x 16 x 16)
Wildcard
2
@Wildcard: Nie mogę edytować mojego komentarza, ale zgadza się.
Nate
7
NIEBEZPIECZEŃSTWO! Ta metoda działała dla nas niezawodnie od lat ... aż do niedawna, z najnowszymi typami c5 i m5, które nie mają tego pliku . Muszę więc dodać kontrolę rezerwową 169.254.169.254, aby obsłużyć te instancje.
Josh Kupershmidt
20

Po pierwsze, czułem potrzebę opublikowania nowej odpowiedzi z powodu następujących subtelnych problemów z istniejącymi odpowiedziami i po otrzymaniu pytania o mój komentarz do odpowiedzi @ qwertzguy . Oto problemy z obecnymi odpowiedziami:

  1. Odpowiedź akceptowaną z @MatthieuCerda zdecydowanie nie działa niezawodnie, a przynajmniej nie na jakichkolwiek przypadkach VPC Sprawdziłem przeciw. (W moich instancjach otrzymuję nazwę VPC hostname -d, która jest używana do wewnętrznego DNS, a nie do niczego z „amazonaws.com”).
  2. Najwyższej głosowało odpowiedź od @qwertzguy nie działa na nowych instancji M5 lub C5 , które nie mają tego pliku. Amazon zaniedbuje dokumentowanie tego zachowania AFAIK, chociaż strona dokumentu na ten temat mówi „... Jeśli / sys / hypervisor / uuid istnieje ...”. Poprosiłem AWS o wsparcie, czy zmiana była zamierzona, patrz poniżej †.
  3. Odpowiedź od @Jer niekoniecznie działają wszędzie, ponieważ instance-data.ec2.internalwyszukiwanie DNS może nie działać. Na instancji Ubuntu EC2 VPC, na której właśnie testowałem, widzę: $ curl http://instance-data.ec2.internal curl: (6) Could not resolve host: instance-data.ec2.internal co spowodowałoby, że kod polegający na tej metodzie błędnie stwierdziłby, że nie ma go na EC2!
  4. Odpowiedź do korzystaniadmidecode z @tamale może działać, ale opiera się na was.) O dmidecodedostępne na przykład, i b.), Mający korzenie lub sudozdolność hasłem mniej z poziomu kodu.
  5. Odpowiedź sprawdzić / sys / devices / virtual / DMI / id / bios_version z @spkane jest niebezpiecznie mylące! Sprawdziłem jeden Ubuntu 14.04 wystąpienie M5 i dostał bios_versionod 1.0. Ten plik w ogóle nie jest udokumentowany w dokumentacji Amazon , więc naprawdę nie polegałbym na nim.
  6. Pierwsza część odpowiedzi @ Chris-Montanaro, aby sprawdzić niewiarygodny adres URL innej firmy i użyć whoiswyniku jest problematyczna na kilku poziomach. Uwaga: adres URL sugerowany w tej odpowiedzi to teraz strona 404! Nawet jeśli znalazłeś usługę innej firmy, która działała, byłaby stosunkowo bardzo wolna (w porównaniu do lokalnego sprawdzania pliku) i prawdopodobnie napotkałaby problemy ograniczające szybkość lub problemy z siecią, a może nawet twoja instancja EC2 nie ma zewnętrzny dostęp do sieci.
  7. Druga sugestia w odpowiedzi @ Chris-Montanaro, aby sprawdzić http://169.254.169.254/, jest nieco lepsza, ale inny komentator zauważa, że ​​inni dostawcy usług w chmurze udostępniają ten adres URL metadanych instancji, dlatego należy uważać, aby uniknąć fałszywego pozytywne. Ponadto nadal będzie znacznie wolniejszy niż plik lokalny. Widziałem, że ta kontrola jest szczególnie wolna (kilka sekund do powrotu) w przypadku mocno załadowanych instancji. Powinieneś również pamiętać o przekazaniu argumentu -mlub --max-timecurl, aby uniknąć zawieszania się przez bardzo długi czas, szczególnie w przypadku instancji innej niż EC2, gdzie ten adres może prowadzić do nikąd i zawiesić się (jak w odpowiedzi @ algal ).

Nie widzę też, aby ktokolwiek wspominał o udokumentowanym wycofaniu się Amazon z sprawdzania (możliwego) pliku /sys/devices/virtual/dmi/id/product_uuid.

Kto wiedział, że ustalenie, czy korzystasz z EC2, może być tak skomplikowane ?! OK, teraz, gdy mamy (większość) problemów z wymienionymi podejściami na liście, oto sugerowany fragment bash, aby sprawdzić, czy korzystasz z EC2. Myślę, że powinno to ogólnie działać na prawie wszystkich instancjach Linuksa, instancje Windows są ćwiczeniem dla czytelnika.

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

Oczywiście można to rozszerzyć o jeszcze więcej kontroli rezerwowych i uwzględnić paranoję dotyczącą radzenia sobie np. Z fałszywym pozytywnym /sys/hypervisor/uuidskutkiem, by zacząć od „ec2” przez przypadek i tak dalej. Ale jest to wystarczająco dobre rozwiązanie do celów ilustracyjnych i prawdopodobnie prawie wszystkich niepatologicznych przypadków użycia.

[†] Otrzymałem to wyjaśnienie od wsparcia AWS dotyczące zmiany dla instancji c5 / m5:

Instancje C5 i M5 używają nowego stosu hiperwizora, a powiązane sterowniki jądra nie tworzą plików w sysfs (który jest montowany w / sys), jak robią to sterowniki Xen używane przez inne / starsze typy instancji . Najlepszym sposobem na wykrycie, czy system operacyjny działa na instancji EC2, jest uwzględnienie różnych możliwości wymienionych w połączonej dokumentacji .

Josh Kupershmidt
źródło
4
Tak, koledze z podróży w 2018 roku ... to odpowiedź, której szukałeś.
russellpierce
czytanie / sys / devices / virtual / dmi / id / product_uuid również wymaga uprawnień roota
Thayne
@Tayne poprawnie - tak mówi komentarz powyżej tego elifbloku, i dlatego eliftest używa -roperatora testowego, który sprawdza, czy plik istnieje i czy masz uprawnienia do odczytu pliku.
Josh Kupershmidt
Dodatkowa uwaga na temat metadanych 169.254.169.254 - nie zawsze jest gotowa w czasie uruchamiania. Jeśli potrzebujesz tych metadanych dla skryptu rozruchowego, będziesz musiał nadal odpytywać, dopóki nie będzie gotowy. Widziałem, że może to potrwać do 30 sekund od momentu uruchomienia przez skrypt inicjujący chmurę.
vacri
15

Poszukaj metadanych według wewnętrznej nazwy domeny EC2 zamiast adresu IP, który zwróci szybką awarię DNS, jeśli nie korzystasz z EC2, i pozwoli uniknąć konfliktów adresów IP lub problemów z routingiem:

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

W niektórych dystrybucjach bardzo podstawowe systemy lub bardzo wcześnie na etapach instalacji curl nie jest dostępny. Korzystanie wget zamiast:

wget -q http://instance-data.ec2.internal && echo "EC2 instance!" || echo "Non EC2 instance!"
Jer
źródło
4
Niestety wydaje się, że zawodzi w VPC!
Ashe
2
Również nie używać znaku wykrzyknik wewnątrz cudzysłów - Twój echo może wysadzić z -bash: !": event not found. echoZamiast tego użyj pojedynczych cudzysłowów .
Josh Kupershmidt
1
prawdopodobnie zakłada to, że serwer nadal korzysta z serwerów DNS EC2, które znają strefę ec2.internal i że nikt nie zmienił /etc/resolv.conf na 8.8.8.8 ani nie wprowadził własnej infrastruktury DNS.
lamont
1
Wygląda na to, że AWS to zepsuło. Nie mogę już rozpoznać instance-data.ec2.internal. instance-data.us-west-2.compute.internal działa, przynajmniej na razie.
Bryan Larsen
14

Jeśli celem jest stwierdzenie, czy jest to instancja EC2 LUB inny rodzaj instancji w chmurze, takiej jak Google, to dmidecodedziała bardzo ładnie i nie wymaga sieci. Podoba mi się to w porównaniu z niektórymi innymi podejściami, ponieważ ścieżka adresu URL metadanych jest inna dla EC2 i 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
źródło
Spodziewałbym się, że zadziała to dobrze w innych środowiskach maszyn wirtualnych, a nawet na prawdziwym sprzęcie - nie oczekuję, że dostawcy sprzętu dostarczą systemy, w których wersja bios mówi „amazon” ...
Guss
W moich instancjach Ubuntu EC2 to zwraca 1.0- bez wzmianki amazon.
Nate
5

Nazwy hostów prawdopodobnie się zmienią, uruchom Whois przeciwko Twojemu publicznemu adresowi 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

lub naciśnij adres metadanych 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
źródło
2
Dodaj --connect-timeout 1 do drugiej instrukcji curl, aby szybko zawieść, jeśli nie korzystasz z EC2.
Jonathan Oliver
1
FWIW przy użyciu adresu URL metadanych może wskazywać, że działa jako instancja chmury, ale nie może jednoznacznie ustalić, czy jest to konkretnie EC2. OpenStack i Eucalyptus również używają tego samego identyfikatora URI metadanych. Wiem, że to wybiera gnidy, ale dla mojej pracy, który dostawca chmury ma znaczenie.
EmmEff
5

Działa to również dobrze dla hostów Linuksa w ec2 i nie wymaga limitów sieciowych i związanych z nimi:

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

To działa, ponieważ Amazon definiuje ten wpis w następujący sposób:

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

spkane
źródło
2018-05-01; wydaje się być nieprawidłowy w instancjach M5 z systemem Ubuntu.
russellpierce
W moich instancjach Ubuntu EC2 to zwraca 1.0. Brak wzmianki o amazon.
Nate
3
test -f /sys/hypervisor/uuid -a `head -c 3 /sys/hypervisor/uuid` == ec2 && echo yes

ale nie wiem, jak przenośne jest to w różnych dystrybucjach.

Hannes
źródło
2
Cóż, na pewno nie zadziała w instancjach Windows EC2.
ceejayoz
1
Wolę tę metodę, ponieważ nie wymaga interakcji sieci, która może się zawiesić z różnych powodów. Nie można zagwarantować, że użycie limitów czasu dla wymiany HTTP zapobiegnie zawieszaniu się. Nie dbam o instancje Windows.
Hannes,
Właśnie tego potrzebowałem! O wiele lepsze niż zwijanie czegoś, dzięki!
qwertzguy
1
Zastanów się nad użyciem pełnego identyfikatora UUID, na wypadek, gdyby identyfikator UUID innego dostawcy również zaczyna się od „ec2”. Prawdopodobieństwo takiego zdarzenia wynosi 1 na 4096, co nie jest nieistotne.
Hannes
1
W rzeczywistości porównywanie całego UUID nie działa, ponieważ widziałem wiele różnych UUID hiperwizorów na wolności. Wszystkie zaczynają się od „ec2”, więc ta odpowiedź działa bez zmian.
Hannes,
3

Szybka odpowiedź:

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

Korzystałem z jednej z odpowiedzi opublikowanych tutaj od ponad roku - ale nie działa na nowych typach instancji „c5” (teraz pracuję nad aktualizacją z wersji „c4”).

Podoba mi się to rozwiązanie, ponieważ wydaje się, że w przyszłości będzie najmniej prawdopodobne, aby się zepsuło.

W starszych typach instancji i nowszych plik ten jest obecny i zaczyna się od „EC2”. Sprawdziłem Ubuntu działający na VirtualBox (który również muszę obsługiwać) i zawiera ciąg „VirtualBox”.

Jak zauważył poprzedni plakat (ale łatwo go było przegapić) - istnieje dokumentacja Amazon na temat tego, jak to zrobić - która zawiera moją odpowiedź.

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

Zach Anthony
źródło
2

Być może możesz użyć „facter”:

„Facter to wieloplatformowa biblioteka do wyszukiwania prostych informacji o systemie operacyjnym, takich jak system operacyjny, dystrybucja linux lub adres MAC”.

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

Na przykład, jeśli przyjrzymy się faktowi 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
źródło
1

Jeśli masz zainstalowane curl, to polecenie zwróci 0, jeśli działasz w EC2 i niezerowe, jeśli nie jesteś:

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

Próbuje wyciągnąć metadane EC2 deklarujące identyfikator AMI. Jeśli to się nie powiedzie po 3 sekundach, oznacza to, że nie działa w EC2.

glon
źródło
0

Trochę za późno na tę imprezę, ale natknąłem się na ten post i znalazłem dokumentację AWS:

Aby znaleźć ostateczną i zweryfikowaną kryptograficznie metodę identyfikacji instancji EC2, sprawdź dokument tożsamości instancji, w tym jej podpis. Dokumenty te są dostępne w każdej instancji EC2 pod lokalnym, nierutowalnym adresem http://169.254.169.254/latest/dynamic/instance-identity/

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

To oczywiście wymaga narzutu sieciowego, chociaż można ustawić limit czasu zawijania w następujący sposób:

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

To ustawia limit czasu na 5s.

Strumyki
źródło