@@ -15,6 +15,7 @@ using ..AWSExceptions: IMDSUnavailable
15
15
using HTTP: HTTP
16
16
using HTTP. Exceptions: ConnectError, StatusError
17
17
using Mocking
18
+ using URIs: URI
18
19
19
20
# Local-link address (https://en.wikipedia.org/wiki/Link-local_address)
20
21
const IPv4_ADDRESS = " 169.254.169.254"
@@ -55,8 +56,28 @@ function refresh_token!(session::Session, duration::Integer=session.duration)
55
56
# For IMDSv2, you must use `/latest/api/token` when retrieving the token instead of a
56
57
# version specific path.
57
58
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html#imds-considerations
58
- uri = HTTP. URI (; scheme= " http" , host= IPv4_ADDRESS, path= " /latest/api/token" )
59
- r = _http_request (" PUT" , uri, headers; status_exception= false )
59
+ uri = URI (; scheme= " http" , host= IPv4_ADDRESS, path= " /latest/api/token" )
60
+ r = try
61
+ _http_request (" PUT" , uri, headers; status_exception= false )
62
+ catch e
63
+ # The IMDSv2 uses a default Time To Live (TTL) of 1 (also known as the hop limit) at
64
+ # the IP layer to ensure token requests occur on the instance. When this occurs we
65
+ # need to fall back to using IMDSv1. Users may wish to increase the hop limit to
66
+ # allow for IMDSv2 use in container based environments:
67
+ # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html#imds-considerations
68
+ if is_ttl_expired_exception (e)
69
+ @warn " IMDSv2 token request rejected due to reaching hop limit. Consider " *
70
+ " increasing the hop limit to avoid delays upon initial use:\n " *
71
+ " https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/" *
72
+ " instancedata-data-retrieval.html#imds-considerations"
73
+
74
+ session. duration = 0
75
+ session. expiration = typemax (Int64) # Use IMDSv1 indefinitely
76
+ return session
77
+ else
78
+ rethrow ()
79
+ end
80
+ end
60
81
61
82
# Store the session token when we receive an HTTP 200. If we receive an HTTP 404 assume
62
83
# that the server is only supports IMDSv1. Otherwise "rethrow" the `StatusError`.
@@ -87,7 +108,7 @@ function request(session::Session, method::AbstractString, path::AbstractString;
87
108
# Only using the IPv4 endpoint as the IPv6 endpoint has to be explicitly enabled and
88
109
# does not disable IPv4 support.
89
110
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-IMDS-new-instances.html#configure-IMDS-new-instances-ipv4-ipv6-endpoints
90
- uri = HTTP . URI (; scheme= " http" , host= IPv4_ADDRESS, path)
111
+ uri = URI (; scheme= " http" , host= IPv4_ADDRESS, path)
91
112
return _http_request (method, uri, headers; kwargs... )
92
113
end
93
114
@@ -122,10 +143,12 @@ end
122
143
is_connection_exception (e:: ConnectError ) = true
123
144
is_connection_exception (e:: Exception ) = false
124
145
146
+ # https://github.com/JuliaCloud/AWS.jl/issues/654
125
147
# https://github.com/JuliaCloud/AWS.jl/issues/649
126
- function is_connection_exception (e:: HTTP.Exceptions.RequestError )
148
+ function is_ttl_expired_exception (e:: HTTP.Exceptions.RequestError )
127
149
return e. error == Base. IOError (" read: connection timed out (ETIMEDOUT)" , - 110 )
128
150
end
151
+ is_ttl_expired_exception (e:: Exception ) = false
129
152
130
153
"""
131
154
get([session::Session], path::AbstractString) -> Union{String, Nothing}
0 commit comments