aws_assume_role 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +31 -11
- data/Gemfile +7 -13
- data/LICENSE.md +201 -19
- data/README.md +176 -145
- data/aws_assume_role.gemspec +35 -21
- data/bin/aws-assume-role +1 -83
- data/i18n/en.yml +106 -0
- data/lib/aws_assume_role.rb +2 -3
- data/lib/aws_assume_role/cli.rb +15 -0
- data/lib/aws_assume_role/cli/actions/abstract_action.rb +53 -0
- data/lib/aws_assume_role/cli/actions/configure_profile.rb +21 -0
- data/lib/aws_assume_role/cli/actions/configure_role_assumption.rb +19 -0
- data/lib/aws_assume_role/cli/actions/console.rb +68 -0
- data/lib/aws_assume_role/cli/actions/delete_profile.rb +20 -0
- data/lib/aws_assume_role/cli/actions/includes.rb +18 -0
- data/lib/aws_assume_role/cli/actions/list_profiles.rb +10 -0
- data/lib/aws_assume_role/cli/actions/migrate_profile.rb +18 -0
- data/lib/aws_assume_role/cli/actions/reset_environment.rb +48 -0
- data/lib/aws_assume_role/cli/actions/run.rb +34 -0
- data/lib/aws_assume_role/cli/actions/set_environment.rb +60 -0
- data/lib/aws_assume_role/cli/actions/test.rb +31 -0
- data/lib/aws_assume_role/cli/commands/configure.rb +29 -0
- data/lib/aws_assume_role/cli/commands/console.rb +17 -0
- data/lib/aws_assume_role/cli/commands/delete.rb +11 -0
- data/lib/aws_assume_role/cli/commands/environment.rb +32 -0
- data/lib/aws_assume_role/cli/commands/list.rb +10 -0
- data/lib/aws_assume_role/cli/commands/migrate.rb +11 -0
- data/lib/aws_assume_role/cli/commands/run.rb +17 -0
- data/lib/aws_assume_role/cli/commands/test.rb +18 -0
- data/lib/aws_assume_role/configuration.rb +19 -0
- data/lib/aws_assume_role/core_ext/aws-sdk/credential_provider_chain.rb +2 -0
- data/lib/aws_assume_role/core_ext/aws-sdk/includes.rb +7 -0
- data/lib/aws_assume_role/credentials/factories.rb +9 -0
- data/lib/aws_assume_role/credentials/factories/abstract_factory.rb +31 -0
- data/lib/aws_assume_role/credentials/factories/assume_role.rb +38 -0
- data/lib/aws_assume_role/credentials/factories/default_chain_provider.rb +101 -0
- data/lib/aws_assume_role/credentials/factories/environment.rb +24 -0
- data/lib/aws_assume_role/credentials/factories/includes.rb +17 -0
- data/lib/aws_assume_role/credentials/factories/instance_profile.rb +17 -0
- data/lib/aws_assume_role/credentials/factories/repository.rb +35 -0
- data/lib/aws_assume_role/credentials/factories/shared.rb +15 -0
- data/lib/aws_assume_role/credentials/factories/shared_keyring.rb +16 -0
- data/lib/aws_assume_role/credentials/factories/static.rb +16 -0
- data/lib/aws_assume_role/credentials/providers/assume_role_credentials.rb +58 -0
- data/lib/aws_assume_role/credentials/providers/includes.rb +9 -0
- data/lib/aws_assume_role/credentials/providers/mfa_session_credentials.rb +102 -0
- data/lib/aws_assume_role/credentials/providers/shared_keyring_credentials.rb +22 -0
- data/lib/aws_assume_role/includes.rb +30 -0
- data/lib/aws_assume_role/logging.rb +16 -28
- data/lib/aws_assume_role/profile_configuration.rb +71 -0
- data/lib/aws_assume_role/runner.rb +39 -0
- data/lib/aws_assume_role/store/includes.rb +16 -0
- data/lib/aws_assume_role/store/keyring.rb +59 -0
- data/lib/aws_assume_role/store/serialization.rb +18 -0
- data/lib/aws_assume_role/store/shared_config_with_keyring.rb +175 -0
- data/lib/aws_assume_role/types.rb +30 -0
- data/lib/aws_assume_role/ui.rb +55 -0
- data/lib/aws_assume_role/vendored/aws.rb +4 -0
- data/lib/aws_assume_role/vendored/aws/README.md +2 -0
- data/lib/aws_assume_role/vendored/aws/assume_role_credentials.rb +68 -0
- data/lib/aws_assume_role/vendored/aws/includes.rb +9 -0
- data/lib/aws_assume_role/vendored/aws/refreshing_credentials.rb +60 -0
- data/lib/aws_assume_role/vendored/aws/shared_config.rb +220 -0
- data/lib/aws_assume_role/version.rb +3 -0
- metadata +264 -20
- data/.rspec +0 -2
- data/Rakefile +0 -2
- data/bin/test.rb +0 -39
- data/lib/aws_assume_role/credentials.rb +0 -92
- data/lib/aws_assume_role/profile.rb +0 -203
- data/lib/aws_assume_role/profile/assume_role.rb +0 -127
- data/lib/aws_assume_role/profile/basic.rb +0 -152
- data/lib/aws_assume_role/profile/list.rb +0 -57
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "../../types"
|
3
|
+
|
4
|
+
class AwsAssumeRole::Credentials::Providers::SharedKeyringCredentials < ::Aws::SharedCredentials
|
5
|
+
def initialize(options = {})
|
6
|
+
shared_config = AwsAssumeRole.shared_config
|
7
|
+
@path = options[:path]
|
8
|
+
@path ||= shared_config.credentials_path
|
9
|
+
@profile_name = options[:profile_name]
|
10
|
+
@profile_name ||= ENV["AWS_PROFILE"]
|
11
|
+
@profile_name ||= shared_config.profile_name
|
12
|
+
if @path && @path == shared_config.credentials_path
|
13
|
+
@credentials = shared_config.credentials(profile: @profile_name)
|
14
|
+
else
|
15
|
+
config = AwsAssumeRole::Store::SharedConfig.new(
|
16
|
+
credentials_path: @path,
|
17
|
+
profile_name: @profile_name,
|
18
|
+
)
|
19
|
+
@credentials = config.credentials(profile: @profile_name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "i18n"
|
2
|
+
require "keyring"
|
3
|
+
require "active_support/core_ext/object/blank"
|
4
|
+
require "active_support/core_ext/string/inflections"
|
5
|
+
require "active_support/core_ext/hash/keys"
|
6
|
+
require "active_support/core_ext/object/json"
|
7
|
+
require "aws-sdk"
|
8
|
+
require "aws-sdk-core/ini_parser"
|
9
|
+
require "dry-configurable"
|
10
|
+
require "dry-initializer"
|
11
|
+
require "dry-validation"
|
12
|
+
require "dry-types"
|
13
|
+
require "English"
|
14
|
+
require "gli"
|
15
|
+
require "highline"
|
16
|
+
require "inifile"
|
17
|
+
require "json"
|
18
|
+
require "logger"
|
19
|
+
require "pastel"
|
20
|
+
require "thread"
|
21
|
+
require "time"
|
22
|
+
|
23
|
+
module AwsAssumeRole
|
24
|
+
module_function
|
25
|
+
|
26
|
+
def shared_config
|
27
|
+
enabled = ENV["AWS_SDK_CONFIG_OPT_OUT"] ? false : true
|
28
|
+
@shared_config ||= SharedConfigWithKeyring.new(config_enabled: enabled)
|
29
|
+
end
|
30
|
+
end
|
@@ -1,36 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def logger
|
11
|
-
@logger ||= Logger.new($stderr)
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_writer :logger
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.included(base)
|
19
|
-
|
20
|
-
class << base
|
21
|
-
|
22
|
-
def logger # rubocop:disable Lint/NestedMethodDefinition
|
23
|
-
Logging.logger
|
24
|
-
end
|
25
|
-
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "configuration"
|
3
|
+
module AwsAssumeRole::Logging
|
4
|
+
module ClassMethods
|
5
|
+
def logger
|
6
|
+
@logger ||= begin
|
7
|
+
logger = Logger.new($stderr)
|
8
|
+
logger.level = AwsAssumeRole::Config.log_level
|
9
|
+
logger
|
26
10
|
end
|
27
|
-
|
28
11
|
end
|
12
|
+
end
|
29
13
|
|
14
|
+
module InstanceMethods
|
30
15
|
def logger
|
31
|
-
|
16
|
+
self.class.logger
|
32
17
|
end
|
33
|
-
|
34
18
|
end
|
35
19
|
|
20
|
+
def self.included(base)
|
21
|
+
base.extend ClassMethods
|
22
|
+
base.include InstanceMethods
|
23
|
+
end
|
36
24
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "logging"
|
3
|
+
|
4
|
+
class AwsAssumeRole::ProfileConfiguration
|
5
|
+
extend Dry::Initializer
|
6
|
+
include AwsAssumeRole::Logging
|
7
|
+
option :access_key_id, Dry::Types["strict.string"].optional, default: proc { nil }
|
8
|
+
option :credentials, default: proc { nil }
|
9
|
+
option :secret_access_key, Dry::Types["strict.string"].optional, default: proc { nil }
|
10
|
+
option :session_token, Dry::Types["strict.string"].optional, default: proc { nil }
|
11
|
+
option :duration_seconds, Dry::Types["coercible.int"].optional, default: proc { nil }
|
12
|
+
option :external_id, Dry::Types["strict.string"].optional, default: proc { nil }
|
13
|
+
option :persist_session, Dry::Types["strict.bool"], default: proc { true }
|
14
|
+
option :profile, Dry::Types["strict.string"].optional, default: proc { nil }
|
15
|
+
option :region, Dry::Types["strict.string"].optional, default: proc { nil }
|
16
|
+
option :role_arn, Dry::Types["strict.string"].optional, default: proc { nil }
|
17
|
+
option :role_session_name, Dry::Types["strict.string"].optional, default: proc { nil }
|
18
|
+
option :serial_number, Dry::Types["strict.string"].optional, default: proc { nil }
|
19
|
+
option :mfa_serial, Dry::Types["strict.string"].optional, default: proc { nil }
|
20
|
+
option :use_mfa, default: proc { false }
|
21
|
+
option :no_profile, default: proc { false }
|
22
|
+
option :shell_type, Dry::Types["strict.string"].optional, default: proc { nil }
|
23
|
+
option :source_profile, Dry::Types["strict.string"].optional, default: proc { nil }
|
24
|
+
option :args, default: proc { [] }
|
25
|
+
option :instance_profile_credentials_retries, Dry::Types["strict.int"], default: proc { 0 }
|
26
|
+
option :instance_profile_credentials_timeout, Dry::Types["coercible.float"], default: proc { 1 }
|
27
|
+
|
28
|
+
attr_writer :credentials
|
29
|
+
|
30
|
+
def self.merge_mfa_variable(options)
|
31
|
+
new_hash = options.key?(:mfa_serial) ? options.merge(serial_number: options[:mfa_serial]) : options
|
32
|
+
new_hash[:use_mfa] ||= new_hash.fetch(:serial_number, nil) ? true : false
|
33
|
+
if new_hash.key?(:serial_number) && new_hash[:serial_number] == "automatic"
|
34
|
+
new_hash.delete(:serial_number)
|
35
|
+
end
|
36
|
+
new_hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.new_from_cli(global_options, options, args)
|
40
|
+
options = global_options.merge options
|
41
|
+
options = options.map do |k, v|
|
42
|
+
[k.to_s.underscore.to_sym, v]
|
43
|
+
end.to_h
|
44
|
+
options[:args] = args
|
45
|
+
new merge_mfa_variable(options)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.new_from_credential_provider_initialization(options)
|
49
|
+
logger.debug "new_from_credential_provider_initialization with #{options.to_h}"
|
50
|
+
new_from_credential_provider(options, credentials: nil, delete: [])
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.new_from_credential_provider(options = {}, credentials: nil, delete: [])
|
54
|
+
option_hash = options.to_h
|
55
|
+
config = option_hash.fetch(:config, {}).to_h
|
56
|
+
hash_to_merge = option_hash.merge config
|
57
|
+
hash_to_merge.merge(credentials: credentials) if credentials
|
58
|
+
delete.each do |k|
|
59
|
+
hash_to_merge.delete k
|
60
|
+
end
|
61
|
+
hash = merge_mfa_variable(hash_to_merge)
|
62
|
+
logger.debug "new_from_credential_provider with #{hash}"
|
63
|
+
new hash
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_h
|
67
|
+
instance_values.delete("__options__").symbolize_keys
|
68
|
+
end
|
69
|
+
|
70
|
+
Dry::Types.register_class(self)
|
71
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "logging"
|
3
|
+
|
4
|
+
class AwsAssumeRole::Runner
|
5
|
+
include AwsAssumeRole::Logging
|
6
|
+
extend Dry::Initializer
|
7
|
+
|
8
|
+
param :command, Dry::Types["coercible.array"].member(Dry::Types["strict.string"])
|
9
|
+
option :exit_on_error, Dry::Types["strict.bool"], default: proc { true }
|
10
|
+
option :expected_exit_code, Dry::Types["strict.int"], default: proc { 0 }
|
11
|
+
option :environment, Dry::Types["strict.hash"], default: proc { {} }
|
12
|
+
option :credentials, optional: true
|
13
|
+
|
14
|
+
def initialize(params, options = {})
|
15
|
+
super(params, options)
|
16
|
+
command_to_exec = command.join(" ")
|
17
|
+
process_credentials unless credentials.blank?
|
18
|
+
system environment, command_to_exec
|
19
|
+
exit_status = $CHILD_STATUS.exitstatus
|
20
|
+
process_error(exit_status) if exit_status != expected_exit_code
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def process_credentials
|
26
|
+
cred_env = {
|
27
|
+
"AWS_ACCESS_KEY_ID" => credentials.credentials.access_key_id,
|
28
|
+
"AWS_SECRET_ACCESS_KEY" => credentials.credentials.secret_access_key,
|
29
|
+
"AWS_SESSION_TOKEN" => credentials.credentials.session_token,
|
30
|
+
}
|
31
|
+
@environment = environment.merge cred_env
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_error(exit_status)
|
35
|
+
logger.error "#{command} failed with #{exit_status}"
|
36
|
+
exit exit_status if exit_on_error
|
37
|
+
raise "#{command} failed with #{exit_status}"
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "active_support/core_ext/object/blank"
|
2
|
+
require "active_support/core_ext/string/inflections"
|
3
|
+
require "active_support/core_ext/hash/slice"
|
4
|
+
require "active_support/json"
|
5
|
+
require "aws-sdk"
|
6
|
+
require "aws-sdk-core/ini_parser"
|
7
|
+
require "inifile"
|
8
|
+
require "json"
|
9
|
+
require "keyring"
|
10
|
+
require "time"
|
11
|
+
require "securerandom"
|
12
|
+
|
13
|
+
module AwsAssumeRole
|
14
|
+
module Store
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "serialization"
|
3
|
+
require_relative "../configuration"
|
4
|
+
require_relative "../logging"
|
5
|
+
|
6
|
+
module AwsAssumeRole::Store::Keyring
|
7
|
+
include AwsAssumeRole
|
8
|
+
include AwsAssumeRole::Store
|
9
|
+
include AwsAssumeRole::Logging
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
KEYRING_KEY = "AwsAssumeRole".freeze
|
14
|
+
|
15
|
+
def semaphore
|
16
|
+
@semaphore ||= Mutex.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def keyrings
|
20
|
+
@keyrings ||= {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def try_backend_plugin
|
24
|
+
return if AwsAssumeRole::Config.backend_plugin.blank?
|
25
|
+
logger.info "Attempting to load #{AwsAssumeRole::Config.backend_plugin} plugin"
|
26
|
+
require AwsAssumeRole::Config.backend_plugin
|
27
|
+
end
|
28
|
+
|
29
|
+
def keyring(backend = AwsAssumeRole::Config.backend)
|
30
|
+
keyrings[backend] ||= begin
|
31
|
+
try_backend_plugin
|
32
|
+
klass = backend ? "Keyring::Backend::#{backend}".constantize : nil
|
33
|
+
logger.debug "Initializing #{klass} backend"
|
34
|
+
::Keyring.new(klass)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def fetch(id, backend: nil)
|
39
|
+
logger.debug "Fetching #{id} from keyring"
|
40
|
+
fetched = keyring(backend).get_password(KEYRING_KEY, id)
|
41
|
+
return nil if fetched == "null" || fetched.nil?
|
42
|
+
raise Aws::Errors::NoSuchProfileError unless fetched
|
43
|
+
JSON.parse(fetched, symbolize_names: true)
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete_credentials(id, backend: nil)
|
47
|
+
semaphore.synchronize do
|
48
|
+
keyring(backend).delete_password(KEYRING_KEY, id)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def save_credentials(id, credentials, expiration: nil, backend: nil)
|
53
|
+
credentials_to_persist = Serialization.credentials_to_hash(credentials)
|
54
|
+
credentials_to_persist[:expiration] = expiration if expiration
|
55
|
+
semaphore.synchronize do
|
56
|
+
keyring(backend).set_password(KEYRING_KEY, id, credentials_to_persist.to_json)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AwsAssumeRole::Store::Serialization
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def credentials_from_hash(credentials)
|
5
|
+
creds_for_deserialization = credentials.respond_to?("[]") ? credentials : credentials_to_hash(credentials)
|
6
|
+
Aws::Credentials.new(creds_for_deserialization[:access_key_id],
|
7
|
+
creds_for_deserialization[:secret_access_key],
|
8
|
+
creds_for_deserialization[:session_token])
|
9
|
+
end
|
10
|
+
|
11
|
+
def credentials_to_hash(credentials)
|
12
|
+
{
|
13
|
+
access_key_id: credentials.access_key_id,
|
14
|
+
secret_access_key: credentials.secret_access_key,
|
15
|
+
session_token: credentials.session_token,
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "../logging"
|
3
|
+
require_relative "keyring"
|
4
|
+
require_relative "../profile_configuration"
|
5
|
+
require_relative "../credentials/providers/mfa_session_credentials"
|
6
|
+
|
7
|
+
class AwsAssumeRole::Store::SharedConfigWithKeyring < AwsAssumeRole::Vendored::Aws::SharedConfig
|
8
|
+
include AwsAssumeRole::Store
|
9
|
+
include AwsAssumeRole::Logging
|
10
|
+
|
11
|
+
attr_reader :parsed_config
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
super(options)
|
15
|
+
@config_enabled = true
|
16
|
+
@config_path = determine_config_path
|
17
|
+
load_config_file
|
18
|
+
end
|
19
|
+
|
20
|
+
def credentials(opts = {})
|
21
|
+
p = opts[:profile] || @profile_name
|
22
|
+
validate_profile_exists(p) if credentials_present?
|
23
|
+
credentials_from_keyring(p, opts) || credentials_from_shared(p, opts) || credentials_from_config(p, opts)
|
24
|
+
end
|
25
|
+
|
26
|
+
def save_profile(profile_name, hash)
|
27
|
+
ckey = "profile #{profile_name}"
|
28
|
+
merged_config = configuration[ckey].deep_symbolize_keys.merge hash.to_h
|
29
|
+
merged_config[:mfa_serial] = merged_config[:serial_number] if merged_config[:serial_number]
|
30
|
+
credentials = Aws::Credentials.new(merged_config.delete(:aws_access_key_id),
|
31
|
+
merged_config.delete(:aws_secret_access_key))
|
32
|
+
semaphore.synchronize do
|
33
|
+
Keyring.save_credentials profile_name, credentials if credentials.set?
|
34
|
+
merged_config = merged_config.slice :region, :role_arn, :mfa_serial, :source_profile,
|
35
|
+
:role_session_name, :external_id, :duration_seconds
|
36
|
+
configuration.delete_section ckey
|
37
|
+
configuration[ckey] = merged_config.compact
|
38
|
+
save_configuration
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def profiles
|
43
|
+
configuration.sections.map { |c| c.gsub("profile ", "") }
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete_profile(profile_name)
|
47
|
+
# Keyring does not return errors for non-existent things, so always attempt.
|
48
|
+
Keyring.delete_credentials(profile_name)
|
49
|
+
semaphore.synchronize do
|
50
|
+
raise KeyError if configuration["profile #{profile_name}"].blank?
|
51
|
+
configuration.delete_section("profile #{profile_name}")
|
52
|
+
save_configuration
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def migrate_profile(profile_name)
|
57
|
+
validate_profile_exists(profile_name)
|
58
|
+
save_profile(profile_name, configuration["profile #{profile_name}"])
|
59
|
+
end
|
60
|
+
|
61
|
+
def profile_region(profile_name)
|
62
|
+
prof_cfg = @parsed_config[profile_key(profile_name)]
|
63
|
+
resolve_region(@parsed_config, prof_cfg)
|
64
|
+
end
|
65
|
+
|
66
|
+
def profile_role(profile_name)
|
67
|
+
prof_cfg = @parsed_config[profile_key(profile_name)]
|
68
|
+
resolve_arn(@parsed_config, prof_cfg)
|
69
|
+
end
|
70
|
+
|
71
|
+
def determine_profile(options)
|
72
|
+
ret = options[:profile_name]
|
73
|
+
ret ||= ENV["AWS_PROFILE"]
|
74
|
+
ret ||= "default"
|
75
|
+
ret
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def profile_key(profile)
|
81
|
+
logger.debug "About to lookup #{profile}"
|
82
|
+
if profile == "default" || profile.nil? || profile == ""
|
83
|
+
"default"
|
84
|
+
else
|
85
|
+
profile
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def resolve_region(cfg, prof_cfg)
|
90
|
+
return unless prof_cfg && cfg
|
91
|
+
return prof_cfg["region"] if prof_cfg.key? "region"
|
92
|
+
source_cfg = cfg[prof_cfg["source_profile"]]
|
93
|
+
cfg[prof_cfg["source_profile"]]["region"] if source_cfg && source_cfg.key?("region")
|
94
|
+
end
|
95
|
+
|
96
|
+
def resolve_arn(cfg, prof_cfg)
|
97
|
+
return unless prof_cfg && cfg
|
98
|
+
return prof_cfg["role_arn"] if prof_cfg.key? "role_arn"
|
99
|
+
source_cfg = cfg[prof_cfg["source_profile"]]
|
100
|
+
cfg[prof_cfg["source_profile"]]["role_arn"] if source_cfg && source_cfg.key?("role_arn")
|
101
|
+
end
|
102
|
+
|
103
|
+
def assume_role_from_profile(cfg, profile, opts)
|
104
|
+
prof_cfg = cfg[profile]
|
105
|
+
return unless cfg && prof_cfg
|
106
|
+
opts[:source_profile] ||= prof_cfg["source_profile"]
|
107
|
+
if opts[:source_profile]
|
108
|
+
opts[:credentials] = credentials(profile: opts[:source_profile])
|
109
|
+
if opts[:credentials]
|
110
|
+
opts[:role_session_name] ||= prof_cfg["role_session_name"]
|
111
|
+
opts[:role_session_name] ||= "default_session"
|
112
|
+
opts[:role_arn] ||= prof_cfg["role_arn"]
|
113
|
+
opts[:external_id] ||= prof_cfg["external_id"]
|
114
|
+
opts[:serial_number] ||= prof_cfg["mfa_serial"]
|
115
|
+
opts[:region] ||= profile_region(profile)
|
116
|
+
if opts[:serial_number]
|
117
|
+
mfa_opts = { credentials: opts[:credentials], region: opts[:region], serial_number: opts[:serial_number] }
|
118
|
+
mfa_creds = mfa_session(cfg, opts[:source_profile], mfa_opts)
|
119
|
+
opts.delete :serial_number
|
120
|
+
end
|
121
|
+
opts[:credentials] = mfa_creds if mfa_creds
|
122
|
+
opts[:profile] = opts.delete(:source_profile)
|
123
|
+
AwsAssumeRole::Credentials::Providers::AssumeRoleCredentials.new(opts)
|
124
|
+
else
|
125
|
+
raise ::Aws::Errors::NoSourceProfileError, "Profile #{profile} has a role_arn, and source_profile, but the"\
|
126
|
+
" source_profile does not have credentials."
|
127
|
+
end
|
128
|
+
elsif prof_cfg["role_arn"]
|
129
|
+
raise ::Aws::Errors::NoSourceProfileError, "Profile #{profile} has a role_arn, but no source_profile."
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def mfa_session(cfg, profile, opts)
|
134
|
+
prof_cfg = cfg[profile]
|
135
|
+
return unless cfg && prof_cfg
|
136
|
+
opts[:serial_number] ||= prof_cfg["mfa_serial"]
|
137
|
+
opts[:source_profile] ||= prof_cfg["source_profile"]
|
138
|
+
opts[:region] ||= profile_region(profile)
|
139
|
+
return unless opts[:serial_number]
|
140
|
+
opts[:credentials] ||= credentials(profile: opts[:profile])
|
141
|
+
AwsAssumeRole::Credentials::Providers::MfaSessionCredentials.new(opts)
|
142
|
+
end
|
143
|
+
|
144
|
+
def credentials_from_keyring(profile, _options)
|
145
|
+
return unless @parsed_config && @parsed_config[profile_key(profile)]
|
146
|
+
logger.debug "Attempt to fetch #{profile} from keyring"
|
147
|
+
creds = Serialization.credentials_from_hash Keyring.fetch(profile)
|
148
|
+
creds if credentials_complete(creds)
|
149
|
+
end
|
150
|
+
|
151
|
+
def semaphore
|
152
|
+
@semaphore ||= Mutex.new
|
153
|
+
end
|
154
|
+
|
155
|
+
def configuration
|
156
|
+
@configuration ||= IniFile.new(filename: determine_config_path, default: "default")
|
157
|
+
end
|
158
|
+
|
159
|
+
# Please run in a mutex
|
160
|
+
def save_configuration
|
161
|
+
bytes_required = File.size(determine_config_path)
|
162
|
+
random_bytes = SecureRandom.random_bytes(bytes_required)
|
163
|
+
File.write(determine_config_path, random_bytes)
|
164
|
+
configuration.save
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
module AwsAssumeRole
|
169
|
+
module_function
|
170
|
+
|
171
|
+
def shared_config
|
172
|
+
enabled = ENV["AWS_SDK_CONFIG_OPT_OUT"] ? false : true
|
173
|
+
@assuome_role_shared_config ||= ::AwsAssumeRole::Store::SharedConfigWithKeyring.new(config_enabled: enabled)
|
174
|
+
end
|
175
|
+
end
|