1%% ====================================================================
2%% @author Gavin M. Roy <gavinmroy@gmail.com>
3%% @copyright 2016, Gavin M. Roy
4%% @copyright 2016-2020 VMware, Inc. or its affiliates.
5%% @headerfile
6%% @private
7%% @doc rabbitmq_aws client library constants and records
8%% @end
9%% ====================================================================
10
11-define(MIME_AWS_JSON, "application/x-amz-json-1.0").
12-define(SCHEME, https).
13
14-define(DEFAULT_REGION, "us-east-1").
15-define(DEFAULT_PROFILE, "default").
16
17-define(INSTANCE_AZ, "placement/availability-zone").
18-define(INSTANCE_HOST, "169.254.169.254").
19
20% rabbitmq/rabbitmq-peer-discovery-aws#25
21
22% Note: this timeout must not be greater than the default
23% gen_server:call timeout of 5000ms. INSTANCE_HOST is
24% a pseudo-ip that should have good performance, and the
25% data should be returned quickly. Note that `timeout`,
26% when set, is used as the connect and then request timeout
27% by `httpc`
28-define(DEFAULT_HTTP_TIMEOUT, 2250).
29
30-define(INSTANCE_CREDENTIALS, "iam/security-credentials").
31-define(INSTANCE_METADATA_BASE, "latest/meta-data").
32-define(INSTANCE_ID, "instance-id").
33
34-define(TOKEN_URL, "latest/api/token").
35
36-define(METADATA_TOKEN_TTL_HEADER, "X-aws-ec2-metadata-token-ttl-seconds").
37
38% EC2 Instance Metadata service version 2 (IMDSv2) uses session-oriented authentication.
39% Instance metadata service requests are only needed for loading/refreshing credentials.
40% Long-lived EC2 IMDSv2 tokens are unnecessary. The token only needs to be valid long enough
41% to successfully load/refresh the credentials. 60 seconds is more than enough time to accomplish this.
42-define(METADATA_TOKEN_TTL_SECONDS, 60).
43
44-define(METADATA_TOKEN, "X-aws-ec2-metadata-token").
45
46-define(LINEAR_BACK_OFF_MILLIS, 500).
47-define(MAX_RETRIES, 5).
48
49-type access_key() :: nonempty_string().
50-type secret_access_key() :: nonempty_string().
51-type expiration() :: calendar:datetime() | undefined.
52-type security_token() :: nonempty_string() | undefined.
53-type region() :: nonempty_string() | undefined.
54-type path() :: ssl:path().
55
56-type sc_ok() :: {ok, access_key(), secret_access_key(), expiration(), security_token()}.
57-type sc_error() :: {error, Reason :: atom()}.
58-type security_credentials() :: sc_ok() | sc_error().
59
60-record(imdsv2token, { token :: security_token() | undefined,
61                       expiration :: expiration() | undefined}).
62
63-type imdsv2token() :: #imdsv2token{}.
64
65-record(state, {access_key :: access_key() | undefined,
66                secret_access_key :: secret_access_key() | undefined,
67                expiration :: expiration() | undefined,
68                security_token :: security_token() | undefined,
69                region :: region() | undefined,
70                imdsv2_token:: imdsv2token() | undefined,
71                error :: atom() | string() | undefined}).
72-type state() :: #state{}.
73
74-type scheme() :: atom().
75-type username() :: string().
76-type password() :: string().
77-type host() :: string().
78-type tcp_port() :: integer().
79-type query_args() :: [tuple() | string()].
80-type fragment() :: string().
81
82-type userinfo() :: {undefined | username(),
83                     undefined | password()}.
84
85-type authority() :: {undefined | userinfo(),
86                      host(),
87                      undefined | tcp_port()}.
88-record(uri, {scheme :: undefined | scheme(),
89              authority :: authority(),
90              path :: undefined | path(),
91              query :: undefined | query_args(),
92              fragment :: undefined | fragment()}).
93
94-type method() :: head | get | put | post | trace | options | delete | patch.
95-type http_version() :: string().
96-type status_code() :: integer().
97-type reason_phrase() :: string().
98-type status_line() :: {http_version(), status_code(), reason_phrase()}.
99-type field() :: string().
100-type value() :: string().
101-type header() :: {Field :: field(), Value :: value()}.
102-type headers() :: [header()].
103-type body() :: string() | binary().
104
105-type ssl_options() :: [ssl:ssl_option()].
106
107-type http_option() :: {timeout, timeout()} |
108                       {connect_timeout, timeout()} |
109                       {ssl, ssl_options()} |
110                       {essl, ssl_options()} |
111                       {autoredirect, boolean()} |
112                       {proxy_auth, {User :: string(), Password :: string()}} |
113                       {version, http_version()} |
114                       {relaxed, boolean()} |
115                       {url_encode, boolean()}.
116-type http_options() :: [http_option()].
117
118
119-record(request, {access_key :: access_key(),
120                  secret_access_key :: secret_access_key(),
121                  security_token :: security_token(),
122                  service :: string(),
123                  region = "us-east-1" :: string(),
124                  method = get :: method(),
125                  headers = [] :: headers(),
126                  uri :: string(),
127                  body = "" :: body()}).
128-type request() :: #request{}.
129
130-type httpc_result() :: {ok, {status_line(), headers(), body()}} |
131                        {ok, {status_code(), body()}} |
132                        {error, term()}.
133
134-type result_ok() :: {ok, {ResponseHeaders :: headers(), Response :: list()}}.
135-type result_error() :: {error, Message :: reason_phrase(), {ResponseHeaders :: headers(), Response :: list()} | undefined} |
136                        {error, {credentials, Reason :: string()}}.
137-type result() :: result_ok() | result_error().
138