boto3 icon indicating copy to clipboard operation
boto3 copied to clipboard

Implement equivalent to boto.utils.get_instance_metadata()

Open jgehrcke opened this issue 10 years ago • 41 comments

This request seems to come up often: Should there be a utility function in boto to retrieve the instance metadata? See: http://stackoverflow.com/questions/31630822/boto3-equivalent-to-boto-utils-get-instance-metadata

jgehrcke avatar Oct 21 '15 15:10 jgehrcke

There is not currently support for this. I'll mark this as a feature request and we can track it here.

mtdowling avatar Oct 21 '15 23:10 mtdowling

This feature would be awesome! We've been postponing using boto3 for a lot of our stuff because this functionality is not available :+1:

When this is implemented, it would also be great if there was builtin way of recursively grabbing all the metadata as a dictionary, instead of only support for lazy loads (like boto2). Somewhat similarly to what we do for collections in boto3, but dict instead of list:

metadata = dict(instance.metadata.all())

Thanks! :)

tiadobatima avatar Nov 10 '15 22:11 tiadobatima

I can not believe this is not in boto3 already. Because AWS' next generation of compute services like Lambda include boto3 natively, having to revert back to boto2 for things like this is a PITA.

rorysavage77 avatar Dec 08 '15 13:12 rorysavage77

Hi, any news on this? Does anyone plan to implement it?

marco-hoyer avatar Jul 08 '16 18:07 marco-hoyer

This is a disappointing regression from boto.

copumpkin avatar Jan 25 '17 14:01 copumpkin

@mtdowling What is the recommended way to replace this method? Do we have to roll our own thing or should we include outdated boto?

Bartvds avatar Jun 14 '17 11:06 Bartvds

Update (as below): I've made a library ec2-metadata that provides an easy interface to query the EC2 metadata API, with caching.


On the instance, do e.g.:

In [5]: requests.get('http://169.254.169.254/latest/meta-data/ami-id').text
Out[5]: 'ami-f0928696'

I think the reason this hasn't been copied is because multiple HTTP requests are needed to get all the metadata as a dict, whereas often you only need one item like so.

adamchainz avatar Jun 14 '17 12:06 adamchainz

I would also love it if we could implement this one. I'll see what I can do internally!

ranman avatar Jun 15 '17 06:06 ranman

Maybe it doesn't have to be this full dict, but an object with some lazy loading properties, and an option to materialize the whole dict if some must have it (for logging/monitoring).

Bartvds avatar Jun 15 '17 07:06 Bartvds

I made a separate mini library for this, with @Bartvds 's suggestion for lazy loading, check it out at https://github.com/adamchainz/ec2-metadata

adamchainz avatar Jun 16 '17 17:06 adamchainz

Any updates on this feature request?

vitchyr avatar Dec 27 '17 17:12 vitchyr

Additionally, it would be great to see boto3 automatically pickup the current region when run on an EC2 instance.

jpiccari avatar Jan 12 '18 18:01 jpiccari

+1 need this

rendicott avatar Jun 27 '18 12:06 rendicott

@rendicott does ec2-metadata not fit your use case? I'd like to make it do everything we need.

adamchainz avatar Jun 27 '18 13:06 adamchainz

@adamchainz I'm sure ec2-metadata will work fine, I plan on using it until it's built into boto

rendicott avatar Jun 27 '18 14:06 rendicott

+1 It would be very nice to have this included in the native boto3 lib.

Adding the ec2-metadata lib listed above seems like a very heavy handed approach, if I wanted to add another pip, I would just use requests.

Having this in boto3 or botocore would mean I could run the code natively on Amazon Linux or a Lambda function w/o having to add dependencies. It would also prevent me from needing to use six to be able to use a python native http get method.

zepplen avatar May 30 '19 18:05 zepplen

Recently noticed /run/cloud-init/instance-data.json on systems with cloud-init.

https://cloudinit.readthedocs.io/en/latest/topics/instancedata.html

jweede avatar May 30 '19 18:05 jweede

@zepplen ec2-metadata is a single 286 line file that builds all the requests calls for you :) Python packaging is better now than it used to be, pip install is not so heavy :)

adamchainz avatar May 30 '19 21:05 adamchainz

@adamchainz ec2-metadata looks great, but we're working with a software package (CKAN) that hasn't yet migrated to Python 3.

ThrawnCA avatar Jan 24 '20 00:01 ThrawnCA

ec2-metadata 1.8.0 is still installable and supports Python 2.

adamchainz avatar Jan 24 '20 08:01 adamchainz

With the changes in IMDSv2, it seems like this is an even more useful feature.

Announcement: https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/

The local metadata service now has a v2 endpoint, which is differentiated from v1 by the existance of a x-aws-ec2-metadata-token header being passed to the local metadata service.

This token is retrieved by sending a PUT request to a new token API in the local metadata service, which will remain active for up to 6 hours (ttl is set as a header in the put request).

It is possible to disable the v1 endpoint, however to do so, ALL metadata queries must use the token, not only IAM Role Credential request calls.

Given the extra complexity of requesting the token, and keeping track of the token TTL for future requests, this undifferentiated heavy lifting, seems like something that should be solved via the AWS provided SDK.

The ec2-metadata library mentioned by @adamchainz does not implement this solution, and I would argue is not a replacement for a solution provided by AWS. (As some development environments have restrictions on what libraries you can import and use).

zepplen avatar Mar 02 '20 16:03 zepplen

ec2-metadata does have an open issue: https://github.com/adamchainz/ec2-metadata/issues/150

adamchainz avatar Mar 02 '20 16:03 adamchainz

@zepplen Incidentally, for those needing a workaround, it's very easy with requests. Eg to retrieve the equivalent of get_instance_metadata()['document']:

token = requests.put('http://169.254.169.254/latest/api/token', headers={'X-aws-ec2-metadata-token-ttl-seconds': '60'}).text
document = requests.get('http://169.254.169.254/latest/dynamic/instance-identity/document', headers={'X-aws-ec2-metadata-token': token}).json()

ThrawnCA avatar Mar 06 '20 04:03 ThrawnCA

ec2-metadata 2.2.0 now supports v2, thanks to @ThrawnCA . #ossFasterThanAWS

adamchainz avatar Mar 12 '20 19:03 adamchainz

yes please +1

tomaskutaj avatar May 15 '20 10:05 tomaskutaj

In [5]: requests.get('http://169.254.169.254/latest/meta-data/ami-id').text
Out[5]: 'ami-f0928696'

I think the reason this hasn't been copied is because multiple HTTP requests are needed to get all the metadata as a dict, whereas often you only need one item like so.

MMhh.. I've tried with requests and I have to agree with @adamchainz it's quite pointless to spend time on this

nnsense avatar Jun 02 '20 18:06 nnsense

@nnsense please try out ec2-metadata, it's a bit more work than one request to use the metadata api v2 ..

adamchainz avatar Jun 02 '20 22:06 adamchainz

At least, it's a bit more work than one request if you want it to be efficient. If you just retrieve a new token every time, you're doubling up all your requests. The implementation in ec2-metadata caches tokens for up to 10 hours and refreshes them when expired, all transparently.

ThrawnCA avatar Jun 03 '20 12:06 ThrawnCA

This is crazy that access to instance metadata is not part of boto. Come on guys!

fshields avatar Jun 05 '20 15:06 fshields

You can access specific metadata easily from botocore if you do not mind calling a private function:

from botocore.utils import IMDSFetcher

IMDSFetcher()._get_request("/latest/meta-data/instance-type", None).text

steven-aerts avatar Feb 17 '22 08:02 steven-aerts