Como saber se uma máquina é uma instância do EC2

43

Gostaria de executar alguns scripts em hosts que são instâncias do EC2, mas não sei como ter certeza de que o host é realmente uma instância do EC2.

Eu fiz alguns testes, mas isso não é suficiente:

  • Teste se ec2_userdata binário está disponível (mas isso nem sempre será verdadeiro)
  • Teste a disponibilidade de " http://169.254.169.254/latest/meta-data " (mas isso sempre será verdade? E o que é esse "IP mágico"?)
Kelindil
fonte
Na verdade, é um endereço APIPA, bastante estranho de usar como referência para um serviço crítico, como recuperação de metadados.
Matthieu Cerda
2
Os intervalos de IP dos EC2s são públicos (embora variem de tempos em tempos). Se você acompanhar uma lista atual, poderá verificar o IP das instâncias em relação a esses intervalos.
Karma Fusebox
2
Não confie no 169.254.169.254 se desejar o EC2 e somente sistemas compatíveis com o EC2 - EC2 como o Eucalyptus também o suportam. engajamento.eucalyptus.com/customer/portal/articles/…
ceejayoz
1
Você precisa do método para trabalhar contra um invasor que tenha root no host e está tentando fazer com que você pense que é uma instância do EC2 para seus próprios propósitos maliciosos? Se você o fizer, será muito mais difícil.
Mike Scott

Respostas:

3

Bem, na verdade, existe uma maneira muito simples de detectar se o host é uma instância do EC2: verifique a pesquisa inversa do seu IP público. Os reversos do EC2 são bastante difíceis de perder.

Além disso, se você não o modificou, o nome do host deve ser o contrário, facilitando ainda mais a identificação.

Você também pode usar o "IP mágico" de que falou, já que é realmente a maneira padrão de obter tags de Instância EC2; no entanto, se você não estiver em uma rede EC2, precisará aguardar um tempo limite, o que geralmente não é desejável...

Se esses métodos não forem suficientes, faça um whois do seu IP e verifique se você está dentro do bloco de IP do Amazon EC2.

EDIT: você pode usar este pequeno pedaço 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

Cuidado, porém, [[é um basismo. Você também pode usar um Python ou Perl uniline, YMMV.

Matthieu Cerda
fonte
13
isso não funciona em uma VPC ou em um ambiente em que você alterou o nome do host; por exemplo. se suas máquinas estiverem em domain.local
Preflightsiren
2
o bit do nome do host está fadado a falhar.
Dan Pritts
3
hostname -dretornaeu-west-1.compute.internal
Bulletmagnet 22/02
42

Alteração da resposta de Hannes para evitar mensagens de erro e incluir exemplo de uso no script:

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

Isso não funciona nas instâncias do Windows. A vantagem sobre o enrolamento é que é quase instantâneo no EC2 e no não EC2.

qwertzguy
fonte
4
A AWS também parece recomendar fazê-lo dessa maneira docs.aws.amazon.com/AWSEC2/latest/UserGuide/…
Mike
3
Eu gosto deste método Lembre-se de que um sistema não-EC2 em execução em um hipervisor pode gerar um UUID que começa com ec2- um falso positivo. É improvável (uma chance de 1 em 256) e apenas se você estiver usando um hipervisor que preenche esse arquivo. É por isso que a documentação vinculada acima diz "você provavelmente está procurando uma instância do EC2".
Nate
1
@ Nate, bom ponto, mas isso não deveria ser uma chance de 1 em 4096? (16 x 16 x 16)
Caractere curinga
2
@Wildcard: Não consigo editar meu comentário, mas está certo.
Nate
7
PERIGO! Esse método funcionou para nós de maneira confiável por anos ... até recentemente, com os tipos mais recentes de c5 e m5 que não possuem esse arquivo presente . Então, eu tenho que adicionar uma verificação de fallback de 169.254.169.254 para lidar com essas instâncias.
Josh Kupershmidt
20

Primeiro, senti a necessidade de postar uma nova resposta por causa dos seguintes problemas sutis com as respostas existentes e depois de receber uma pergunta sobre meu comentário na resposta do @ qwertzguy . Aqui estão os problemas com as respostas atuais:

  1. A resposta aceita pelo @MatthieuCerda definitivamente não funciona de maneira confiável, pelo menos não nas instâncias de VPC que verifiquei. (Nas minhas instâncias, recebo um nome de VPC para hostname -d, que é usado para DNS interno, e não qualquer coisa com "amazonaws.com" nele.)
  2. A resposta mais votada de @qwertzguy não funciona em novas instâncias m5 ou c5 , que não possuem esse arquivo. A Amazon não documenta esse comportamento, altere o AFAIK, embora a página de documento sobre este assunto diga "... Se / sys / hypervisor / uuid existir ...". Perguntei ao suporte da AWS se essa alteração foi intencional, veja abaixo †.
  3. A resposta do @Jer não funciona necessariamente em todos os lugares porque a instance-data.ec2.internalpesquisa de DNS pode não funcionar. Em uma instância VPC do Ubuntu EC2 em que acabei de testar, vejo: o $ curl http://instance-data.ec2.internal curl: (6) Could not resolve host: instance-data.ec2.internal que faria com que o código que confia nesse método conclua falsamente que não está no EC2!
  4. A resposta a ser usadadmidecode no @tamale pode funcionar, mas depende de você a.) Ter dmidecodedisponível em sua instância eb) ter capacidade de root ou sem sudosenha a partir do seu código.
  5. A resposta para verificar / sys / devices / virtual / dmi / id / bios_version do @spkane é perigosamente enganosa! Eu verifiquei uma instância do Ubuntu 14.04 m5 e obtive uma bios_versiondas 1.0. Esse arquivo não está documentado no documento da Amazon , então eu realmente não confiaria nele.
  6. A primeira parte da resposta de @ Chris-Montanaro para verificar um URL de terceiros não confiável e usar whoisno resultado é problemática em vários níveis. Observe que o URL sugerido nessa resposta é uma página 404 agora! Mesmo se você encontrasse um serviço de terceiros que funcionasse, seria comparativamente muito lento (comparado à verificação de um arquivo localmente) e possivelmente teria problemas de limitação de taxa ou problemas de rede, ou talvez sua instância do EC2 nem sequer tenha acesso à rede externa.
  7. A segunda sugestão na resposta de @ Chris-Montanaro para verificar http://169.254.169.254/ é um pouco melhor, mas outro comentarista observa que outros provedores de nuvem disponibilizam o URL de metadados dessa instância, portanto, você deve ter cuidado para evitar falsos positivos. Além disso, ainda será muito mais lento que um arquivo local. Vi essa verificação ser especialmente lenta (alguns segundos para retornar) em instâncias muito carregadas. Além disso, lembre-se de passar um argumento -mou --max-timecurl para evitar que ele fique paralisado por muito tempo, especialmente em uma instância não-EC2 em que esse endereço possa levar a lugar nenhum e travar (como na resposta de @ algal ).

Além disso, não vejo que alguém tenha mencionado o fallback documentado da Amazon de verificar o arquivo (possível) /sys/devices/virtual/dmi/id/product_uuid.

Quem sabia que determinar se você está executando o EC2 pode ser tão complicado ?! OK, agora que temos (a maioria) dos problemas relacionados às abordagens listadas, aqui está um snippet de bash sugerido para verificar se você está executando no EC2. Eu acho que isso deve funcionar geralmente em quase todas as instâncias do Linux, instâncias do Windows são um exercício para o leitor.

#!/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, você pode expandir isso com ainda mais verificações de fallback e incluir paranóia sobre o manuseio, por exemplo, um falso positivo /sys/hypervisor/uuidaconteça para começar com "ec2" por acaso e assim por diante. Mas esta é uma solução suficientemente boa para fins de ilustração e provavelmente quase todos os casos de uso não patológicos.

[†] Recuperei esta explicação do suporte da AWS sobre a alteração para instâncias c5 / m5:

As instâncias C5 e M5 usam uma nova pilha de hipervisor e os drivers do kernel associados não criam arquivos no sysfs (que é montado em / sys) como os drivers Xen usados ​​pelos outros tipos de instância / antigos . A melhor maneira de detectar se o sistema operacional está sendo executado em uma instância do EC2 é considerar as diferentes possibilidades listadas na documentação que você vinculou .

Josh Kupershmidt
fonte
4
Sim, companheiro de viagem em 2018 ... esta é a resposta que você está procurando.
Russellpierce
A leitura / sys / devices / virtual / dmi / id / product_uuid também requer privilégios de root
Thayne
@ Thayne correto - é o que elifdiz o comentário acima desse bloco, e é por isso que o elifteste usa o -roperador de teste, que verifica se o arquivo existe e se você tem permissões de leitura para o arquivo.
Josh Kupershmidt 4/01
Uma observação adicional sobre os metadados 169.254.169.254 - nem sempre ela está pronta no momento da inicialização. Se você precisar desses metadados para um script de inicialização, precisará continuar pesquisando até que esteja pronto. Vi que demoram 30 segundos depois que a instância começou a executar seus scripts de inicialização na nuvem-init.
vacri 26/09
15

Procure os metadados pelo nome de domínio interno do EC2 em vez do IP, que retornará uma falha rápida do DNS se você não estiver no EC2 e evita conflitos de IP ou problemas de roteamento:

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

Em algumas distribuições, sistemas muito básicos, ou muito precoce em estágios installion onda não está disponível. Usando o wget :

wget -q http://instance-data.ec2.internal && echo "EC2 instance!" || echo "Non EC2 instance!"
Jer
fonte
4
Infelizmente, parece falhar na VPC!
Ashe
2
Também não use o caractere ponto de exclamação dentro de aspas - o seu eco pode explodir com -bash: !": event not found. Use aspas simples para esses echos.
Josh Kupershmidt
1
isso provavelmente pressupõe que o servidor ainda esteja usando servidores DNS do EC2s que conhecem a zona ec2.internal e que ninguém alterou o /etc/resolv.conf para 8.8.8.8 ou rolou sua própria infraestrutura de DNS.
lamont 31/03
1
A AWS parece ter quebrado isso. Não consigo mais resolver instance-data.ec2.internal. instance-data.us-west-2.compute.internal funciona, pelo menos por enquanto.
Bryan Larsen
14

Se o objetivo é saber se é uma instância do EC2 OU outro tipo de instância da nuvem, como o google, dmidecodefunciona muito bem e não é necessária rede. Eu gosto disso vs algumas das outras abordagens porque o caminho do URL de metadados é diferente para EC2 e 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
fonte
Eu esperaria isso para funcionar bem em outros ambientes VM e até mesmo em hardware real - Eu não espero quaisquer fornecedores de hardware para sistemas onde a versão bios diz "amazon" enviar ...
Guss
Nas minhas instâncias do Ubuntu EC2, isso retorna 1.0- sem mencionar amazon.
Nate
5

É provável que os nomes de host sejam alterados, execute um whois no seu IP público:

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 acesse o URL de metadados da 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
fonte
2
Adicione um --connect-timeout 1 à segunda instrução curl para falhar rapidamente se você não estiver executando no EC2.
Jonathan Oliver
1
FWIW, o uso da URL de metadados pode indicar que está sendo executado como uma instância da nuvem, mas não é possível determinar conclusivamente se é especificamente o EC2. O OpenStack e o Eucalyptus também usam o mesmo URI de metadados. Eu sei que isso está pegando fogo, mas, para o meu trabalho, qual provedor de nuvem importa.
EmmEff
5

Isso também funciona bem para hosts Linux no ec2 e não requer a rede e nenhum tempo limite relacionado:

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

Isso funciona, porque a Amazon define essa entrada da seguinte maneira:

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

spkane
fonte
01-05-2018; parece ser inválido em instâncias M5 executando o Ubuntu.
Russellpierce
Nas minhas instâncias do Ubuntu EC2, isso retorna 1.0. Nenhuma menção amazon.
Nate
3
test -f /sys/hypervisor/uuid -a `head -c 3 /sys/hypervisor/uuid` == ec2 && echo yes

mas não sei como isso é portátil nas distribuições.

Hannes
fonte
2
Bem, certamente não vai funcionar em instâncias do Windows EC2.
precisa
1
Prefiro esse método, pois não envolve uma interação de rede que pode travar por todos os tipos de razões. O uso de tempos limite para uma troca HTTP não é garantido para evitar travamentos. Eu não me importo com instâncias do Windows.
Hannes
Era exatamente disso que eu precisava! Muito melhor do que enrolar algo, obrigado!
qwertzguy
1
Considere usar o UUID completo, caso o UUID de outro hypervisor de outro fornecedor também comece com "ec2". A chance disso acontecer é de 1 em 4096, o que não é desprezível.
Hannes
1
Na verdade, comparar o UUID inteiro não funciona, pois eu vi vários UUIDs de hypervisor diferentes na natureza. Todos eles começam com "ec2", portanto, essa resposta funciona como está.
Hannes
3

Resposta 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

Eu estava usando uma das respostas postadas aqui há mais de um ano - mas ela não funciona nos novos tipos de instância 'c5' (estou trabalhando na atualização do 'c4' agora).

Eu gosto dessa solução porque parece ser a menos provável de quebrar no futuro.

Nos tipos de instância mais antigos e nos mais novos, esse arquivo está presente e começa com 'EC2'. Eu verifiquei no Ubuntu rodando no VirtualBox (que eu também preciso suportar) e ele contém a string 'VirtualBox'.

Como um pôster anterior observou (mas foi fácil perder) - há documentação da Amazon sobre maneiras de fazer isso - que inclui minha resposta.

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

Zach Anthony
fonte
2

Talvez você possa usar "facter":

"O Facter é uma biblioteca multiplataforma para recuperar fatos simples do sistema operacional, como sistema operacional, distribuição linux ou endereço MAC".

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

Por exemplo, se dermos uma olhada no fato do 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
fonte
1

Se você tiver o curl instalado, esse comando retornará 0 se você estiver executando no EC2 e diferente de zero se não estiver:

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

Ele tenta extrair os metadados do EC2 que declaram o AMI-ID. Se isso não der certo após 3 segundos, ele assumirá que não está sendo executado no EC2.

algal
fonte
0

Um pouco tarde para esta festa, no entanto, me deparei com esta postagem e encontrei esta documentação da AWS:

Para um método definitivo e criptograficamente verificado de identificar uma instância do EC2, verifique o documento de identidade da instância, incluindo sua assinatura. Esses documentos estão disponíveis em todas as instâncias do EC2 no endereço local não roteável http://169.254.169.254/latest/dynamic/instance-identity/

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

Isso, é claro, requer a sobrecarga da rede, embora você possa definir o tempo limite da ondulação da seguinte forma:

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

Isso define o tempo limite para 5s.

Brooks
fonte