IMDS
imds reads instance metadata from multiple cloud providers through one Elixir
API using the provider's instance metadata service.
Use
{:ok, identity} = IMDS.identity()
IMDS.identity/1 returns:
%{
provider:
:aws
| :gce
| :azure
| :oracle
| :hetzner
| :scaleway
| :openstack
| :digital_ocean
| :akamai
| :vultr,
instance_id: binary() | nil,
instance_type: binary() | nil,
region: binary() | nil,
zone: binary() | nil,
scope_id: binary() | nil,
raw: map()
}
The raw field holds the provider identity document when available.
AWS reads the instance type and the account ID from the instance identity
Detection requires AWS IMDSv2. On an instance that permits only IMDSv1, pass
provider: :aws or set INSTANCE_METADATA_PROVIDER=aws.
Use a provider name to skip discovery:
{:ok, identity} = IMDS.identity(provider: :gce)
Use IMDS.detect/1 to find the provider without reading its identity:
{:ok, :azure} = IMDS.detect()
Use IMDS.get/2 and IMDS.get_json/2 to read a provider path. For Azure,
IMDS.get/2 adds the api-version query parameter when the path does not hold
one.
{:ok, id} = IMDS.get("/computeMetadata/v1/instance/id")
{:ok, attributes} =
IMDS.get_json("/computeMetadata/v1/instance/attributes/?recursive=true")
Logger metadata
IMDS.set_global_logger_metadata/1 copies the identity to the primary logger
metadata, so every log line holds the provider and the instance:
:ok = IMDS.set_global_logger_metadata()
The function sets the keys :provider, :instance_id, :instance_type,
:region, :zone, and :scope_id. It does not set :raw. It does not set a
field that the provider does not report, so the metadata holds no nil value.
It does not replace a key that the logger metadata already holds.
It accepts the same options as identity/1. It returns {:error, reason} and
changes nothing when detection or the identity read fails.
Call it one time at application start. Without :provider or
INSTANCE_METADATA_PROVIDER, each call probes all providers.
Providers
| Provider | Metadata service | Request requirement |
|---|---|---|
| AWS EC2 | IMDSv2 | Token from PUT /latest/api/token; token header on metadata GETs |
| GCE | VM metadata server | Metadata-Flavor: Google header |
| Azure | Instance Metadata Service (IMDS) | Metadata: true header and API version 2021-02-01 |
| Oracle Cloud Infrastructure | IMDSv2 | Authorization: Bearer Oracle header |
| Hetzner Cloud | Metadata service | No header; plain text values below /hetzner/v1/metadata |
| Scaleway | Instance metadata service | No header; JSON document at /conf?format=json |
| OpenStack (nova) | Metadata service | No header; JSON document at /openstack/latest/meta_data.json |
| DigitalOcean | Droplet metadata service | No header; JSON document at /metadata/v1.json |
| Akamai Cloud Computing | Metadata service | Token from PUT /v1/token; Metadata-Token header and Accept: application/json on /v1/instance |
| Vultr | Instance metadata service | No header; JSON document at /v1.json |
The module keeps no state between calls. Every call of IMDS.detect/1 probes
the providers again. The environment variable INSTANCE_METADATA_PROVIDER can
select provider and omit probing. The :provider option takes precedence over
the environment variable.
Options
| Option | Default | Purpose |
|---|---|---|
:provider |
detection | Select one provider and skip detection |
:base_url |
provider address | Replace the provider base URL, for example in a local test |
:timeout |
5,000 ms | Timeout for one request; discovery uses 1,000 ms unless set |
:req_options |
[] |
Options added to the Req request, for example a test plug |
:aws_imds_v1_fallback |
true |
Permit AWS IMDSv1 after token requests answer 403, 404 or 405 |
:api_version |
2021-02-01 |
Azure IMDS API version |
License
Apache 2.0