aws_assume_role 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +31 -11
  4. data/Gemfile +7 -13
  5. data/LICENSE.md +201 -19
  6. data/README.md +176 -145
  7. data/aws_assume_role.gemspec +35 -21
  8. data/bin/aws-assume-role +1 -83
  9. data/i18n/en.yml +106 -0
  10. data/lib/aws_assume_role.rb +2 -3
  11. data/lib/aws_assume_role/cli.rb +15 -0
  12. data/lib/aws_assume_role/cli/actions/abstract_action.rb +53 -0
  13. data/lib/aws_assume_role/cli/actions/configure_profile.rb +21 -0
  14. data/lib/aws_assume_role/cli/actions/configure_role_assumption.rb +19 -0
  15. data/lib/aws_assume_role/cli/actions/console.rb +68 -0
  16. data/lib/aws_assume_role/cli/actions/delete_profile.rb +20 -0
  17. data/lib/aws_assume_role/cli/actions/includes.rb +18 -0
  18. data/lib/aws_assume_role/cli/actions/list_profiles.rb +10 -0
  19. data/lib/aws_assume_role/cli/actions/migrate_profile.rb +18 -0
  20. data/lib/aws_assume_role/cli/actions/reset_environment.rb +48 -0
  21. data/lib/aws_assume_role/cli/actions/run.rb +34 -0
  22. data/lib/aws_assume_role/cli/actions/set_environment.rb +60 -0
  23. data/lib/aws_assume_role/cli/actions/test.rb +31 -0
  24. data/lib/aws_assume_role/cli/commands/configure.rb +29 -0
  25. data/lib/aws_assume_role/cli/commands/console.rb +17 -0
  26. data/lib/aws_assume_role/cli/commands/delete.rb +11 -0
  27. data/lib/aws_assume_role/cli/commands/environment.rb +32 -0
  28. data/lib/aws_assume_role/cli/commands/list.rb +10 -0
  29. data/lib/aws_assume_role/cli/commands/migrate.rb +11 -0
  30. data/lib/aws_assume_role/cli/commands/run.rb +17 -0
  31. data/lib/aws_assume_role/cli/commands/test.rb +18 -0
  32. data/lib/aws_assume_role/configuration.rb +19 -0
  33. data/lib/aws_assume_role/core_ext/aws-sdk/credential_provider_chain.rb +2 -0
  34. data/lib/aws_assume_role/core_ext/aws-sdk/includes.rb +7 -0
  35. data/lib/aws_assume_role/credentials/factories.rb +9 -0
  36. data/lib/aws_assume_role/credentials/factories/abstract_factory.rb +31 -0
  37. data/lib/aws_assume_role/credentials/factories/assume_role.rb +38 -0
  38. data/lib/aws_assume_role/credentials/factories/default_chain_provider.rb +101 -0
  39. data/lib/aws_assume_role/credentials/factories/environment.rb +24 -0
  40. data/lib/aws_assume_role/credentials/factories/includes.rb +17 -0
  41. data/lib/aws_assume_role/credentials/factories/instance_profile.rb +17 -0
  42. data/lib/aws_assume_role/credentials/factories/repository.rb +35 -0
  43. data/lib/aws_assume_role/credentials/factories/shared.rb +15 -0
  44. data/lib/aws_assume_role/credentials/factories/shared_keyring.rb +16 -0
  45. data/lib/aws_assume_role/credentials/factories/static.rb +16 -0
  46. data/lib/aws_assume_role/credentials/providers/assume_role_credentials.rb +58 -0
  47. data/lib/aws_assume_role/credentials/providers/includes.rb +9 -0
  48. data/lib/aws_assume_role/credentials/providers/mfa_session_credentials.rb +102 -0
  49. data/lib/aws_assume_role/credentials/providers/shared_keyring_credentials.rb +22 -0
  50. data/lib/aws_assume_role/includes.rb +30 -0
  51. data/lib/aws_assume_role/logging.rb +16 -28
  52. data/lib/aws_assume_role/profile_configuration.rb +71 -0
  53. data/lib/aws_assume_role/runner.rb +39 -0
  54. data/lib/aws_assume_role/store/includes.rb +16 -0
  55. data/lib/aws_assume_role/store/keyring.rb +59 -0
  56. data/lib/aws_assume_role/store/serialization.rb +18 -0
  57. data/lib/aws_assume_role/store/shared_config_with_keyring.rb +175 -0
  58. data/lib/aws_assume_role/types.rb +30 -0
  59. data/lib/aws_assume_role/ui.rb +55 -0
  60. data/lib/aws_assume_role/vendored/aws.rb +4 -0
  61. data/lib/aws_assume_role/vendored/aws/README.md +2 -0
  62. data/lib/aws_assume_role/vendored/aws/assume_role_credentials.rb +68 -0
  63. data/lib/aws_assume_role/vendored/aws/includes.rb +9 -0
  64. data/lib/aws_assume_role/vendored/aws/refreshing_credentials.rb +60 -0
  65. data/lib/aws_assume_role/vendored/aws/shared_config.rb +220 -0
  66. data/lib/aws_assume_role/version.rb +3 -0
  67. metadata +264 -20
  68. data/.rspec +0 -2
  69. data/Rakefile +0 -2
  70. data/bin/test.rb +0 -39
  71. data/lib/aws_assume_role/credentials.rb +0 -92
  72. data/lib/aws_assume_role/profile.rb +0 -203
  73. data/lib/aws_assume_role/profile/assume_role.rb +0 -127
  74. data/lib/aws_assume_role/profile/basic.rb +0 -152
  75. 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
- # Mixin to provide global logging object
2
- module AWSAssumeRole
3
-
4
- module Logging
5
-
6
- require 'logger'
7
-
8
- class << self
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
- Logging.logger
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