Skip to content

Make "no refresh time" configurable in Aws::InstanceProfileCredentials #3308

@ybiquitous

Description

@ybiquitous

Describe the feature

I'd suggest that the Aws::InstanceProfileCredentials class would provide a configurable option to shorten "no refresh time" (currently implemented with the @no_refresh_until instance variable).

def refresh
if @no_refresh_until && @no_refresh_until > Time.now
warn_expired_credentials
return
end

Use Case

I'm using a single instance of Aws::InstanceProfileCredentials to communicate S3 in a Rails app, e.g.,

# config/initializers/aws.rb
Rails.configuration.x.aws.credentials = Aws::InstanceProfileCredentials.new
Rails.configuration.x.aws.s3_client = Aws::S3::Client.new(
  credentials: Rails.configuration.x.aws.credentials
)

In my deployment environment, an IMDS service (i.e., http://169.254.169.254) sometimes returns 503 Service Unavailable for some reason.

Once the error is raised, requests to S3 fail with 401 Unauthorized error within about 5 minutes (as Aws::InstanceProfileCredentials implements), since stale credentials are used for the S3 API. These 5-minute failures with S3 downgrade my service quality.

# credentials are already set, but there was an error getting new credentials
# so don't update the credentials and use stale ones (static stability)
@no_refresh_until = Time.now + rand(300..360)

To help understand my issue, let me share a few screenshots of APM that I'm using for the app:

  • Image
  • Image

Proposed Solution

Although there might be some approaches, I currently have the following idea to provide a new option, such as a :refresh_back Proc object:

class Aws::InstanceProfileCredentials
  def initialize(options = {})
    # ...
    @refresh_backoff = options[:refresh_backoff] || (-> { Time.now + rand(300..360) })
    @no_refresh_until = nil
    # ...
  end

  def set_refresh_interval
    @no_refresh_until = @refresh_backoff.call
  end
end

Additionally, we would need to change the message in the #warn_expired_credentials method to fit the new option:

def warn_expired_credentials
warn('Attempting credential expiration extension due to a credential service availability issue. '\
'A refresh of these credentials will be attempted again in 5 minutes.')
end

Furthermore, it might be more helpful if this warn (i.e., Kernel#warn) were used with any specific logger object (it'd be optional, though). Since Kernel#warn outputs messages to STDOUT, they're often hard to find. For example:

def warn_expired_credentials
  logger.warn("...")
end

Other Information

This issue might be related to:

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

SDK version used

aws-sdk-core 3.233.0

Environment details (OS name and version, etc.)

  • OS: Linux
  • Ruby: 3.4.6 (CRuby)

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature-requestA feature should be added or improved.needs-triageThis issue or PR still needs to be triaged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions