Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set token create time before the request #2650

Merged
merged 5 commits into from
Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions gems/aws-sdk-core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Unreleased Changes
------------------

* Issue - Set `create_time` on IMDS tokens before fetch to reduce chance of using expired tokens and retry failures due to using expired tokens.

3.126.0 (2022-02-03)
------------------

Expand Down
5 changes: 3 additions & 2 deletions gems/aws-sdk-core/lib/aws-sdk-core/ec2_metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ def resolve_endpoint(endpoint, endpoint_mode)

def fetch_token
open_connection do |conn|
created_time = Time.now
token_value, token_ttl = http_put(conn, @token_ttl)
@token = Token.new(value: token_value, ttl: token_ttl)
@token = Token.new(value: token_value, ttl: token_ttl, created_time: created_time)
end
end

Expand Down Expand Up @@ -222,7 +223,7 @@ class Token
def initialize(options = {})
@ttl = options[:ttl]
@value = options[:value]
@created_time = Time.now
@created_time = options[:created_time] || Time.now
end

# [String] Returns the token value.
Expand Down
31 changes: 23 additions & 8 deletions gems/aws-sdk-core/lib/aws-sdk-core/instance_profile_credentials.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,11 @@ def get_credentials
begin
retry_errors(NETWORK_ERRORS, max_retries: @retries) do
unless token_set?
created_time = Time.now
token_value, ttl = http_put(
conn, METADATA_TOKEN_PATH, @token_ttl
)
@token = Token.new(token_value, ttl) if token_value && ttl
@token = Token.new(token_value, ttl, created_time) if token_value && ttl
end
end
rescue *NETWORK_ERRORS
Expand All @@ -166,9 +167,17 @@ def get_credentials
end

token = @token.value if token_set?
metadata = http_get(conn, METADATA_PATH_BASE, token)
profile_name = metadata.lines.first.strip
http_get(conn, METADATA_PATH_BASE + profile_name, token)

begin
metadata = http_get(conn, METADATA_PATH_BASE, token)
profile_name = metadata.lines.first.strip
http_get(conn, METADATA_PATH_BASE + profile_name, token)
rescue TokenExpiredError
# Token has expired, reset it
# The next retry should fetch it
@token = nil
raise Non200Response
end
end
end
rescue
Expand Down Expand Up @@ -200,9 +209,15 @@ def http_get(connection, path, token = nil)
headers = { 'User-Agent' => "aws-sdk-ruby3/#{CORE_GEM_VERSION}" }
headers['x-aws-ec2-metadata-token'] = token if token
response = connection.request(Net::HTTP::Get.new(path, headers))
raise Non200Response unless response.code.to_i == 200

response.body
case response.code.to_i
when 200
response.body
when 401
raise TokenExpiredError
else
raise Non200Response
end
end

# PUT request fetch token with ttl
Expand Down Expand Up @@ -244,10 +259,10 @@ def retry_errors(error_classes, options = {}, &_block)
# @api private
# Token used to fetch IMDS profile and credentials
class Token
def initialize(value, ttl)
def initialize(value, ttl, created_time = Time.now)
@ttl = ttl
@value = value
@created_time = Time.now
@created_time = created_time
end

# [String] token value
Expand Down