Skip to content

Conversation

@YashoSharma
Copy link

  • Adds process based credential providers into credential resolution chain
  • Adds unit tests for credential provider process declarations in config files

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Copy link
Contributor

@awood45 awood45 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the approach here. It would seem to make more sense for this to actually be its own credential provider. While Shared Config would be a place for the credential_process flag, it should be its own provider in its own class with its own tests.

@awood45
Copy link
Contributor

awood45 commented Jul 3, 2018

There are other benefits to it being a standalone credential provider - for example, it would allow users to invoke it directly, rather than as a shared configuration side effect.

else
ProcessCredentials.new(profile_name: ENV['AWS_PROFILE'].nil? ? 'default' : ENV['AWS_PROFILE'])
end
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd make the "else nil" explicit here.

include CredentialProvider
include RefreshingCredentials

def initialize(options = {})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the way to go about this either - I think when this credential provider is created, you should be able to specify the process identifier directly. You can fetch that value in the credential provider chain approach and pass it in to this constructor.

Essentially, we shouldn't strictly require that a shared config file even exists.


@expiration = creds_json['Expiration'] ? Time.iso8601(creds_json['Expiration']) : nil
return creds if creds.set?
raise ArgumentError.new("Invalid payload for JSON credentials version 1")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use a SDK typed exception here, as above. Similar to https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Errors/MissingCredentialsError.html but not that exception. Perhaps Aws::Errors::ProcessCredentialsError?

end

def refresh
proc = Aws.shared_config.credentials_process(@profile_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, we need to not source from shared config within this class. It's also static, so the place to set this is in the constructor.

proc is also a reserved word, best not to be used as a variable name.

def process_credentials(options)
if Aws.shared_config.config_enabled?
if options[:config]
ProcessCredentials.new(profile_name: options[:config].profile)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make the "is process credentials enabled by shared config" decision fully within this logic section. If so, we create a ProcessCredentials object and expect it to work. If not, we return nil and move on.

include CredentialProvider
include RefreshingCredentials

def initialize(process)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add more documentation for #initialize like what kind of process variable it's expecting?

@credentials = credentials_from_process(@process)
end

# @return [Credentials]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aws::Credentials?


include CredentialProvider
include RefreshingCredentials

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add some doc here like an example of how to use this?
e.g https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/AssumeRoleCredentials.html

@@ -0,0 +1,43 @@
require_relative '../spec_helper'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test suites looks good, just checking does these covered all cli test suits for the process credentials as well?

end
end

# Raised when a credentials provider process returns a JSON
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

surprise! ;) you need to update the region line here: https://github.com/aws/aws-sdk-ruby/blob/master/build_tools/spec/region_spec.rb#L12

That spec is for testing we don't hard code region names, since the error file has been modified, the line number need to be modified as well :D That' why you are seeing the travis error

Copy link
Contributor

@awood45 awood45 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks much better - I'd address Jingyi's comments on documentation in AssumeRoleCredentials (in fact, double bonus for explicitly testing the use case of plugging in a process credential provider there, since that's by far the most common use case for this), and for double-checking against the SEP definition.

private
def credentials_from_process(proc_invocation)
begin
raw_out = `#{proc_invocation}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My last point is for us to take another pass on the process invocation choice. Backticks run this way are going to be unescaped, and while we're taking in the data from the credentials file, we may want to be cautious. Take a look at Open3 and let's see if Open3.capture2 works equally well.

# provided in the credentials payload
#
# credentials = Aws::ProcessCredentials.new(
# 'echo \'{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use a different example, closer to what we would want to do. A hard-coded echo with hard-coded credentials would never be recommended. It's just meant to be an illustration, but some may take it literally.

# @param [String] process Invocation string for process
# credentials provider.
def initialize(process)
@process = process
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're close now, at this point we just need to make sure we're splitting and escaping the string in the same way Python/CLI does: https://github.com/boto/botocore/blob/25a6a4c7c8a8b1797fc78c6a34dc7bca3f0bfba1/botocore/credentials.py#L793-L796

@awood45
Copy link
Contributor

awood45 commented Jul 31, 2018

So the last thing we need before merging is to add credential provider chain tests to cover what should and should not happen (making sure this is the end of the credential stack, ensuring it's a terminal state).

expect(client.config.credentials.access_key_id).to eq("ACCESS_KEY_SC1")
end

it 'prefers process credentials over metadata credentials' do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last bit here, I would also add some tests with this same profile where we ensure that static profile credentials, for example, are pulled in first. It's a bit thorough, but important for regression.

Copy link
Contributor

@awood45 awood45 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do the merge work on this one

@awood45 awood45 merged commit ddd927a into aws:master Aug 2, 2018
@YashoSharma YashoSharma deleted the feature/ProcessCredentialProvider branch August 2, 2018 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants