Current section
Files
Jump to
Current section
Files
src/aws_credentials_ec2.erl
%% @doc This provider looks up credential information from EC2 metadata.
%% @end
-module(aws_credentials_ec2).
-behaviour(aws_credentials_provider).
-define(SESSION_TOKEN_URL,
"http://169.254.169.254/latest/api/token/").
-define(SESSION_TOKEN_TTL_HEADER,
"x-aws-ec2-metadata-token-ttl-seconds").
-define(SESSION_TOKEN_TTL_SECONDS,
"21600").
-define(SESSION_TOKEN_HEADER,
"X-aws-ec2-metadata-token").
-define(CREDENTIAL_URL,
"http://169.254.169.254/latest/meta-data/iam/security-credentials/").
-define(DOCUMENT_URL,
"http://169.254.169.254/latest/dynamic/instance-identity/document").
-type role() :: binary().
-type session_token() :: binary().
-type field() :: string().
-type value() :: string().
-type request_header() :: {field(), value()}.
-type request_headers() :: [request_header()].
-export([fetch/1]).
-spec fetch(aws_credentials_provider:options()) ->
{ok, aws_credentials_provider:credentials(), aws_credentials_provider:expiration()} |
{error, any()}.
fetch(_Options) ->
% Fetch the IMDS session token and convert it to the request headers.
% Then pass the request headers to subsequent IMDS requests.
{ok, SessionToken} = fetch_session_token(),
{ok, RequestHeaders} = request_headers(SessionToken),
{ok, Role} = fetch_role(RequestHeaders),
{ok, AccessKeyID, SecretAccessKey, ExpirationTime, Token} =
fetch_metadata(Role, RequestHeaders),
{ok, Region} = fetch_document(RequestHeaders),
Credentials = aws_credentials:make_map(?MODULE, AccessKeyID, SecretAccessKey, Token, Region),
{ok, Credentials, ExpirationTime}.
-spec fetch_session_token() -> {ok, session_token()}.
fetch_session_token() ->
RequestHeaders = [{?SESSION_TOKEN_TTL_HEADER, ?SESSION_TOKEN_TTL_SECONDS}],
{ok, 200, Body, _Headers} =
aws_credentials_httpc:request(put, ?SESSION_TOKEN_URL, RequestHeaders),
{ok, Body}.
-spec request_headers(session_token()) -> {ok, request_headers()}.
request_headers(SessionToken) ->
SessionTokenString = binary:bin_to_list(SessionToken),
RequestHeaders = [{?SESSION_TOKEN_HEADER, SessionTokenString}],
{ok, RequestHeaders}.
-spec fetch_role(request_headers()) -> {ok, role()}.
fetch_role(RequestHeaders) ->
{ok, 200, Body, _Headers} =
aws_credentials_httpc:request(get, ?CREDENTIAL_URL, RequestHeaders),
{ok, Body}.
-spec fetch_metadata(role(), request_headers()) -> {'ok', binary(), binary(), binary(), binary()}.
fetch_metadata(Role, RequestHeaders) ->
Url = lists:flatten(io_lib:format("~s~s", [?CREDENTIAL_URL, Role])),
{ok, 200, Body, _Headers} = aws_credentials_httpc:request(get, Url, RequestHeaders),
Map = jsx:decode(Body),
{ok, maps:get(<<"AccessKeyId">>, Map),
maps:get(<<"SecretAccessKey">>, Map),
maps:get(<<"Expiration">>, Map),
maps:get(<<"Token">>, Map)}.
-spec fetch_document(request_headers()) -> {ok, binary()}.
fetch_document(RequestHeaders) ->
{ok, 200, Body, _Headers} = aws_credentials_httpc:request(get, ?DOCUMENT_URL, RequestHeaders),
Map = jsx:decode(Body),
{ok, maps:get(<<"region">>, Map)}.