Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions gems/aws-sdk-core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Unreleased Changes
------------------

* Feature - Extensible Credential Providers, allows you to declare an executable
to be run that outputs the credentials as a JSON payload allowing you to develop
custom credential providers and easily add them to the credential resolution chain, [Docs](https://docs.aws.amazon.com/cli/latest/topic/config-vars.html#sourcing-credentials-from-external-processes)

3.22.1 (2018-06-28)
------------------

Expand Down
26 changes: 26 additions & 0 deletions gems/aws-sdk-core/lib/aws-sdk-core/shared_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,37 @@ def credentials_from_profile(prof_config)
)
if credentials_complete(creds)
creds
elsif proc_invocation = prof_config['credential_process']
credentials_from_process(proc_invocation)
else
nil
end
end

def credentials_from_process(proc_invocation)
raw_out = `#{proc_invocation}`
success = $?.success?

if success
creds_json = JSON.parse(raw_out)
payload_version = creds_json['Version']
if payload_version == 1
creds = Credentials.new(
creds_json['AccessKeyId'],
creds_json['SecretAccessKey'],
creds_json['SessionToken']
)

return creds if credentials_complete(creds)
raise ArgumentError.new("Invalid json payload for credentials JSON version #{payload_version}")
else
raise ArgumentError.new("Invalid version #{payload_version} for credentials payload")
end
else
abort('credential_process provider failure, the credential process had non zero exit status')
end
end

def credentials_complete(creds)
creds.set?
end
Expand Down
42 changes: 42 additions & 0 deletions gems/aws-sdk-core/spec/aws/shared_credentials_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,47 @@ module Aws
expect(creds).to eq(nil)
end

it 'will read credentials from a process' do
creds = SharedCredentials.new(
path: mock_config_file,
profile_name: 'creds_from_process_valid').credentials
expect(creds.access_key_id).to eq('AK_PROC1')
expect(creds.secret_access_key).to eq('SECRET_AK_PROC1')
expect(creds.session_token).to eq('TOKEN_PROC1')
end

it 'will throw an error when the process credentials payload version is invalid' do
expect {
creds = SharedCredentials.new(
path: mock_config_file,
profile_name: 'creds_from_process_invalid_version').credentials
}.to raise_error(ArgumentError)
end

it 'will throw an error when the process credentials payload is malformed' do
expect {
creds = SharedCredentials.new(
path: mock_config_file,
profile_name: 'creds_from_process_invalid_format').credentials
}.to raise_error(ArgumentError)
end

it 'will throw an error and expose the stderr output when the credential process has a nonzero exit status' do
expect {
creds = SharedCredentials.new(
path: mock_config_file,
profile_name: 'creds_from_process_invalid_exit').credentials
}.to raise_error(SystemExit)
.and output("Credential Provider Error\ncredential_process provider failure, the credential process had non zero exit status\n").to_stderr_from_any_process
end

it 'will throw an error when the credential process cant be found' do
expect {
creds = SharedCredentials.new(
path: mock_config_file,
profile_name: 'creds_from_process_invalid_process').credentials
}.to raise_error(Errno::ENOENT)
end

end
end
15 changes: 15 additions & 0 deletions gems/aws-sdk-core/spec/fixtures/credentials/mock_shared_config
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,18 @@ role_arn = arn:aws:iam:123456789012:role/bar
aws_access_key_id = ACCESS_KEY_ARPC
aws_secret_access_key = SECRET_KEY_ARPC
aws_session_token = TOKEN_ARPC

[profile creds_from_process_valid]
credential_process = echo '{"Version":1,"AccessKeyId":"AK_PROC1","SecretAccessKey":"SECRET_AK_PROC1","SessionToken":"TOKEN_PROC1"}'

[profile creds_from_process_invalid_version]
credential_process = echo '{"Version":3,"AccessKeyId":"","SecretAccessKey":"","SessionToken":""}'

[profile creds_from_process_invalid_format]
credential_process = echo '{"Version":1}'

[profile creds_from_process_invalid_exit]
credential_process = >&2 echo "Credential Provider Error"; false

[profile creds_from_process_invalid_process]
credential_process = fake_proc