Server Fault is a question and answer site for system and network administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I would like to run some scripts on hosts which are EC2 instances but I don't know how to be sure that the host is really an EC2 instance.

I have made some tests, but this is not sufficient:

  • Test that binary ec2_userdata is available (but this will not always be true)
  • Test availability of "http://169.254.169.254/latest/meta-data" (but will this be always true ? and what is this "magical IP" ?)
share|improve this question
    
    
It's an APIPA address actually, which is quite odd to use as a reference for a critical service like meta data retrieval. – Matthieu Cerda Jan 4 '13 at 9:52
1  
The IP ranges of EC2s are public (though varying from time to time). If you keep up with a current list you can check the instances IP against that ranges. – Karma Fusebox Jan 4 '13 at 10:30
2  
Don't rely on 169.254.169.254 if you want EC2 and only EC2 - EC2-alike systems like Eucalyptus also support it. engage.eucalyptus.com/customer/portal/articles/… – ceejayoz Jul 2 '13 at 14:21
    
Do you need the method to work against an attacker who has root on the host, and is trying to spoof you into thinking that it's an EC2 instance for his own malicious purposes? If you do, then it will be much harder. – Mike Scott Jun 22 '15 at 19:01
up vote 3 down vote accepted

Well actually, there is a very simple way to detect if the host is an EC2 instance: check the reverse lookup of your public IP. The EC2 reverses are quite hard to miss.

Also, if you did not modify it, the hostname should be your reverse, making it further easy to spot it.

You might also use the "magical IP" you talked about, as it is indeed the standard way to get EC2 Instance tags, however, if you are not on a EC2 network, you will have to wait for a timeout, which is generally not desirable...

If these methods are not enough, just do a whois of your IP and check if you are within and Amazon EC2 IP block.

EDIT: You may use this small shell bit:

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

Careful though, [[ is a bashism. You may also use a Python or Perl uniline, YMMV.

share|improve this answer
7  
this doesn't work in a VPC or an environment where you have changed the hostname; eg. if your machines are in domain.local – Preflightsiren Jan 28 '13 at 9:28
    
the hostname bit is just bound to fail. – Dan Pritts Feb 13 '14 at 19:28

Look for the metadata by the EC2 internal domain name instead of IP, which will return a fast DNS failure if you're not on EC2, and avoids IP conflicts or routing issues:

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

On some distros, very basic systems, or very early at installion stages curl is not available. Using wget instead:

wget -q http://instance-data.ec2.internal && echo "EC2 instance!" || echo "Non EC2 instance!"
share|improve this answer
2  
Unfortunately, appears to fail in VPC! – Yuki Izumi Feb 6 '15 at 1:35
    
Also don't use the exclamation mark character inside double quotes -- your echo may blow up with -bash: !": event not found. Use single quotes for those echos instead. – Josh Kupershmidt Nov 10 '15 at 18:19
1  
this probably assumes that the server is still using EC2s DNS servers that know about the ec2.internal zone and that nobody has changed /etc/resolv.conf to 8.8.8.8 or rolled their own DNS infastructure. – lamont Mar 31 at 1:35
    
AWS appears to have broken this. I can no longer resolve instance-data.ec2.internal. instance-data.us-west-2.compute.internal works, though, at least for now. – Bryan Larsen Jun 24 at 18:59

Changed Hannes' answer to avoid error messages and include example usage in script:

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

This doesn't work in Windows instances. Advantage over curl is that it's close to instantaneous on both EC2 and non-EC2.

share|improve this answer
    
I like that this doesn't use the network. Would be nice to get clarification of that file path exists on all distros. I tested on Ubuntu 14 and Ubuntu 12 LTRs and the files exists on both versions. – razzed Feb 19 at 21:20
    
Nice! I also prefer this to anything relying on the network... and this also works on RHEL-based systems, but it's worth noting that that path doesn't exist on other cloud provider VMs like GCE.. I added an answer using dmidecode that works on EC2 and GCE the exact same way and still doesn't use the network. – tamale May 5 at 16:07

Hostnames are likely to change, run a whois against your public 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

or hit the AWS meta-data url

if [[ ! -z $(curl -s http://169.254.169.254/1.0/) ]]; then 
  echo "I'm Amazon"
else 
  echo "I'm not Amazon"
fi
share|improve this answer
2  
Add a --connect-timeout 1 to the second curl statement to fail quickly if you're not running on EC2. – Jonathan Oliver Sep 25 '13 at 12:27
    
FWIW, using the metadata URL can indicate it's running as a cloud instance, but cannot conclusively determine if it is specifically EC2. OpenStack and Eucalyptus also use the same metadata URI. I know this is picking nits, but for my work, which cloud provider matters. – EmmEff Feb 20 '14 at 15:53
test -f /sys/hypervisor/uuid -a `head -c 3 /sys/hypervisor/uuid` == ec2 && echo yes

but I don't know how portable this is across distributions.

share|improve this answer
2  
Well, it's certainly not going to work on Windows EC2 instances. – ceejayoz Jun 4 '15 at 3:24
1  
I prefer this method since it doesn't involve a network interaction which can hang for all kinds of reasons. Using timeouts for an HTTP exchange is not guaranteed to prevent hangs. I don't care about Windows instances. – Hannes Jun 11 '15 at 1:34
    
That is exactly what I needed! Way better than curl'ing something, thanks! – qwertzguy Jun 22 '15 at 18:38
1  
Consider using the full UUID, just in case some other vendor's hypervisor UUID also starts with "ec2". The chance of that happening is 1 in 4096 which is not negligible. – Hannes Jun 23 '15 at 2:07
1  
Actually, comparing the entire UUID does not work since I have seen multiple different hypervisor UUIDs in the wild. They all start with "ec2" though, so this answer works as is. – Hannes Aug 19 '15 at 20:16

Perhaps you can use "facter":

"Facter is a cross-platform library for retrieving simple operating system facts, like operating system, linux distribution, or MAC address."

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

For example, if we take a look to the ec2 fact (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
share|improve this answer

If the goal is to tell if it's an EC2 instance OR another kind of cloud instance, like google, then dmidecode works very nicely and no networking is required. I like this vs some of the other approaches because the metadata url path is different for EC2 and 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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.