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.
- 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,9 @@
|
|
1
|
+
require_relative "factories/repository"
|
2
|
+
require_relative "factories/abstract_factory"
|
3
|
+
require_relative "factories/default_chain_provider"
|
4
|
+
require_relative "factories/assume_role"
|
5
|
+
require_relative "factories/environment"
|
6
|
+
require_relative "factories/instance_profile"
|
7
|
+
require_relative "factories/shared_keyring"
|
8
|
+
require_relative "factories/shared"
|
9
|
+
require_relative "factories/static"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "repository"
|
3
|
+
require_relative "../../profile_configuration"
|
4
|
+
|
5
|
+
class AwsAssumeRole::Credentials::Factories::AbstractFactory
|
6
|
+
include AwsAssumeRole
|
7
|
+
include AwsAssumeRole::Credentials::Factories
|
8
|
+
include AwsAssumeRole::Logging
|
9
|
+
|
10
|
+
Dry::Types.register_class(Aws::SharedCredentials)
|
11
|
+
attr_reader :credentials, :region, :profile, :role_arn
|
12
|
+
|
13
|
+
def initialize(_options)
|
14
|
+
raise "Not implemented"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.type(str)
|
18
|
+
@type = Types::Strict::Symbol.enum(:credential_provider, :second_factor_provider, :role_assumption_provider)[str]
|
19
|
+
register_if_complete
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.priority(i)
|
23
|
+
@priority = Types::Strict::Int[i]
|
24
|
+
register_if_complete
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.register_if_complete
|
28
|
+
return unless @type && @priority
|
29
|
+
Repository.register_factory(self, @type, @priority)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative "abstract_factory"
|
2
|
+
require_relative "../providers/assume_role_credentials"
|
3
|
+
require_relative "../providers/mfa_session_credentials"
|
4
|
+
|
5
|
+
class AwsAssumeRole::Credentials::Factories::AssumeRole < AwsAssumeRole::Credentials::Factories::AbstractFactory
|
6
|
+
include AwsAssumeRole::Credentials::Factories
|
7
|
+
type :role_assumption_provider
|
8
|
+
priority 30
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
if options[:profile]
|
12
|
+
try_with_profile(options)
|
13
|
+
else
|
14
|
+
if options[:use_mfa]
|
15
|
+
options[:credentials] = AwsAssumeRole::Credentials::Providers::MfaSessionCredentials.new(options).credentials
|
16
|
+
end
|
17
|
+
@credentials = AwsAssumeRole::Credentials::Providers::AssumeRoleCredentials.new(options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def try_with_profile(options)
|
22
|
+
if AwsAssumeRole.shared_config.config_enabled?
|
23
|
+
@profile = options[:profile]
|
24
|
+
@region = options[:region]
|
25
|
+
@credentials = assume_role_with_profile(options[:profle], options[:region])
|
26
|
+
end
|
27
|
+
@credentials = assume_role_with_profile(@profile, @region)
|
28
|
+
@region ||= AwsAssumeRole.shared_config.profile_region(@profiles)
|
29
|
+
@role_arn ||= AwsAssumeRole.shared_config.profile_role(@profile)
|
30
|
+
end
|
31
|
+
|
32
|
+
def assume_role_with_profile(prof, region)
|
33
|
+
AwsAssumeRole.shared_config.assume_role_credentials_from_config(
|
34
|
+
profile: prof,
|
35
|
+
region: region,
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "../../logging"
|
3
|
+
require_relative "../../profile_configuration"
|
4
|
+
require_relative "abstract_factory"
|
5
|
+
require_relative "environment"
|
6
|
+
require_relative "repository"
|
7
|
+
require_relative "instance_profile"
|
8
|
+
require_relative "assume_role"
|
9
|
+
require_relative "shared_keyring"
|
10
|
+
require_relative "shared"
|
11
|
+
require_relative "static"
|
12
|
+
|
13
|
+
class AwsAssumeRole::Credentials::Factories::DefaultChainProvider
|
14
|
+
extend Dry::Initializer::Mixin
|
15
|
+
include AwsAssumeRole::Credentials::Factories
|
16
|
+
|
17
|
+
option :access_key_id, Dry::Types["strict.string"].optional, default: proc { nil }
|
18
|
+
option :credentials, default: proc { nil }
|
19
|
+
option :secret_access_key, Dry::Types["strict.string"].optional, default: proc { nil }
|
20
|
+
option :session_token, Dry::Types["strict.string"].optional, default: proc { nil }
|
21
|
+
option :duration_seconds, Dry::Types["coercible.int"].optional, default: proc { nil }
|
22
|
+
option :external_id, Dry::Types["strict.string"].optional, default: proc { nil }
|
23
|
+
option :persist_session, Dry::Types["strict.bool"], default: proc { true }
|
24
|
+
option :profile, Dry::Types["strict.string"].optional, default: proc { nil }
|
25
|
+
option :profile_name, Dry::Types["strict.string"].optional, default: proc { @profile }
|
26
|
+
option :region, Dry::Types["strict.string"].optional, default: proc { nil }
|
27
|
+
option :role_arn, Dry::Types["strict.string"].optional, default: proc { nil }
|
28
|
+
option :role_session_name, Dry::Types["strict.string"].optional, default: proc { nil }
|
29
|
+
option :serial_number, Dry::Types["strict.string"].optional, default: proc { nil }
|
30
|
+
option :use_mfa, default: proc { false }
|
31
|
+
option :no_profile, default: proc { false }
|
32
|
+
option :source_profile, Dry::Types["strict.string"].optional, default: proc { nil }
|
33
|
+
option :instance_profile_credentials_retries, Dry::Types["strict.int"], default: proc { 0 }
|
34
|
+
option :instance_profile_credentials_timeout, Dry::Types["coercible.float"], default: proc { 1 }
|
35
|
+
|
36
|
+
def initialize(*options)
|
37
|
+
if options[0].is_a? Seahorse::Client::Configuration::DefaultResolver
|
38
|
+
initialize_with_seahorse(options[0])
|
39
|
+
else
|
40
|
+
super(*options)
|
41
|
+
end
|
42
|
+
@profile_name ||= @profile
|
43
|
+
@original_profile = @profile
|
44
|
+
end
|
45
|
+
|
46
|
+
def resolve(nil_with_role_not_set: false, explicit_default_profile: false)
|
47
|
+
resolve_final_credentials(explicit_default_profile)
|
48
|
+
nil_creds = Aws::Credentials.new(nil, nil, nil)
|
49
|
+
return nil_creds if (nil_with_role_not_set &&
|
50
|
+
@role_arn &&
|
51
|
+
@credentials.credentials.session_token.nil?) || @credentials.nil?
|
52
|
+
@credentials
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def resolve_final_credentials(explicit_default_profile = false)
|
58
|
+
resolve_credentials(:credential_provider, true, explicit_default_profile)
|
59
|
+
return @credentials if @credentials && @credentials.set? && !use_mfa && !role_arn
|
60
|
+
resolve_credentials(:second_factor_provider, true, explicit_default_profile)
|
61
|
+
return @credentials if @credentials && @credentials.set? && !role_arn
|
62
|
+
resolve_credentials(:role_assumption_provider, true, explicit_default_profile)
|
63
|
+
return @credentials if @credentials && @credentials.set?
|
64
|
+
Aws::Credentials.new(nil, nil, nil)
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize_with_seahorse(resolver)
|
68
|
+
keys = resolver.resolve
|
69
|
+
options = keys.map do |k|
|
70
|
+
[k, resolver.send(k)]
|
71
|
+
end
|
72
|
+
__initialize__(options.to_h)
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_h
|
76
|
+
instance_values.delete("__options__").symbolize_keys.merge(
|
77
|
+
instance_profile_credentials_retries: instance_profile_credentials_retries,
|
78
|
+
instance_profile_credentials_timeout: instance_profile_credentials_timeout,
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
def resolve_credentials(type, break_if_successful = false, explicit_default_profile = false)
|
83
|
+
factories_to_try = Repository.factories[type]
|
84
|
+
factories_to_try.each do |x|
|
85
|
+
options = to_h
|
86
|
+
options[:credentials] = credentials if credentials && credentials.set?
|
87
|
+
factory = x.new(options)
|
88
|
+
@region ||= factory.region
|
89
|
+
@profile ||= factory.profile
|
90
|
+
@role_arn ||= factory.role_arn
|
91
|
+
next unless factory.credentials && factory.credentials.set?
|
92
|
+
next if explicit_default_profile && (@profile == "default") && (@profile != @original_profile)
|
93
|
+
@credentials ||= factory.credentials
|
94
|
+
break if break_if_successful
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
module AwsAssumeRole
|
100
|
+
DefaultProvider = AwsAssumeRole::Credentials::Factories::DefaultChainProvider
|
101
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative "abstract_factory"
|
2
|
+
|
3
|
+
class AwsAssumeRole::Credentials::Factories::Environment < AwsAssumeRole::Credentials::Factories::AbstractFactory
|
4
|
+
type :credential_provider
|
5
|
+
priority 10
|
6
|
+
|
7
|
+
def initialize(_options, **)
|
8
|
+
key = %w(AWS_ACCESS_KEY_ID AMAZON_ACCESS_KEY_ID AWS_ACCESS_KEY)
|
9
|
+
secret = %w(AWS_SECRET_ACCESS_KEY AMAZON_SECRET_ACCESS_KEY AWS_SECRET_KEY)
|
10
|
+
token = %w(AWS_SESSION_TOKEN AMAZON_SESSION_TOKEN)
|
11
|
+
region = %w(AWS_DEFAULT_REGION)
|
12
|
+
profile = %w(AWS_PROFILE)
|
13
|
+
@credentials = Aws::Credentials.new(envar(key), envar(secret), envar(token))
|
14
|
+
@region = envar(region)
|
15
|
+
@profile = envar(profile)
|
16
|
+
end
|
17
|
+
|
18
|
+
def envar(keys)
|
19
|
+
keys.each do |key|
|
20
|
+
return ENV[key] if ENV.key?(key)
|
21
|
+
end
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "dry-initializer"
|
2
|
+
require "dry-types"
|
3
|
+
require "aws-sdk"
|
4
|
+
require_relative "../../logging"
|
5
|
+
require_relative "../../vendored/aws"
|
6
|
+
require_relative "../../../aws_assume_role"
|
7
|
+
|
8
|
+
module AwsAssumeRole
|
9
|
+
module Credentials
|
10
|
+
module Factories
|
11
|
+
Types = Dry::Types.module
|
12
|
+
include AwsAssumeRole
|
13
|
+
include AwsAssumeRole::Logging
|
14
|
+
include AwsAssumeRole::Vendored::Aws
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative "abstract_factory"
|
2
|
+
|
3
|
+
class AwsAssumeRole::Credentials::Factories::InstanceProfile < AwsAssumeRole::Credentials::Factories::AbstractFactory
|
4
|
+
type :role_assumption_provider
|
5
|
+
priority 40
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
options[:retries] ||= options[:instance_profile_credentials_retries] || 0
|
9
|
+
options[:http_open_timeout] ||= options[:instance_profile_credentials_timeout] || 1
|
10
|
+
options[:http_read_timeout] ||= options[:instance_profile_credentials_timeout] || 1
|
11
|
+
@credentials = if ENV["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"]
|
12
|
+
Aws::ECSCredentials.new(options)
|
13
|
+
else
|
14
|
+
Aws::InstanceProfileCredentials.new(options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "abstract_factory"
|
3
|
+
|
4
|
+
class AwsAssumeRole::Credentials::Factories::Repository
|
5
|
+
include AwsAssumeRole::Credentials::Factories
|
6
|
+
|
7
|
+
SubFactoryRepositoryType = Types::Hash.schema(Types::Coercible::Int => Types::Strict::Array)
|
8
|
+
|
9
|
+
FactoryRepositoryType = Types::Hash.schema(
|
10
|
+
credential_provider: SubFactoryRepositoryType,
|
11
|
+
second_factor_provider: SubFactoryRepositoryType,
|
12
|
+
role_assumption_provider: SubFactoryRepositoryType,
|
13
|
+
)
|
14
|
+
|
15
|
+
def self.factories
|
16
|
+
repository.keys.map { |t| [t, flatten_factory_type_list(t)] }.to_h
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.repository
|
20
|
+
@repository ||= FactoryRepositoryType[
|
21
|
+
credential_provider: {},
|
22
|
+
second_factor_provider: {},
|
23
|
+
role_assumption_provider: {},
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.register_factory(klass, type, priority)
|
28
|
+
repository[type][priority] ||= []
|
29
|
+
repository[type][priority] << klass
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.flatten_factory_type_list(type)
|
33
|
+
repository[type].keys.sort.map { |x| @repository[type][x] }.flatten
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative "abstract_factory"
|
2
|
+
|
3
|
+
class AwsAssumeRole::Credentials::Factories::Shared < AwsAssumeRole::Credentials::Factories::AbstractFactory
|
4
|
+
type :credential_provider
|
5
|
+
priority 20
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@profile = options[:profile] || "default"
|
9
|
+
@credentials = AwsAssumeRole::Vendored::Aws::SharedCredentials.new(profile_name: @profile)
|
10
|
+
@region = AwsAssumeRole.shared_config.profile_region(@profile)
|
11
|
+
@role_arn = AwsAssumeRole.shared_config.profile_role(@profile)
|
12
|
+
rescue Aws::Errors::NoSuchProfileError
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative "abstract_factory"
|
2
|
+
require_relative "../providers/shared_keyring_credentials"
|
3
|
+
|
4
|
+
class AwsAssumeRole::Credentials::Factories::SharedKeyring < AwsAssumeRole::Credentials::Factories::AbstractFactory
|
5
|
+
type :credential_provider
|
6
|
+
priority 19
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@profile = options[:profile] || "default"
|
10
|
+
@credentials = AwsAssumeRole::Credentials::Providers::SharedKeyringCredentials.new(profile_name: @profile)
|
11
|
+
@region = AwsAssumeRole.shared_config.profile_region(@profile)
|
12
|
+
@role_arn = AwsAssumeRole.shared_config.profile_role(@profile)
|
13
|
+
rescue Aws::Errors::NoSuchProfileError
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative "abstract_factory"
|
2
|
+
|
3
|
+
class AwsAssumeRole::Credentials::Factories::Static < AwsAssumeRole::Credentials::Factories::AbstractFactory
|
4
|
+
type :credential_provider
|
5
|
+
priority 0
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@credentials = Aws::Credentials.new(
|
9
|
+
options[:access_key_id],
|
10
|
+
options[:secret_access_key],
|
11
|
+
options[:session_token],
|
12
|
+
)
|
13
|
+
@region = options[:region]
|
14
|
+
@profile = options[:profile]
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require "set"
|
3
|
+
|
4
|
+
class AwsAssumeRole::Credentials::Providers::AssumeRoleCredentials
|
5
|
+
include AwsAssumeRole::Vendored::Aws::CredentialProvider
|
6
|
+
include AwsAssumeRole::Vendored::Aws::RefreshingCredentials
|
7
|
+
|
8
|
+
# @option options [required, String] :role_arn
|
9
|
+
# @option options [required, String] :role_session_name
|
10
|
+
# @option options [String] :policy
|
11
|
+
# @option options [Integer] :duration_seconds
|
12
|
+
# @option options [String] :external_id
|
13
|
+
# @option options [STS::Client] :client
|
14
|
+
#
|
15
|
+
#
|
16
|
+
|
17
|
+
STS_KEYS = [:role_arn, :role_session_name, :policy, :duration_seconds, :external_id, :client, :credentials, :region].freeze
|
18
|
+
|
19
|
+
def initialize(options = {})
|
20
|
+
client_opts = {}
|
21
|
+
@assume_role_params = {}
|
22
|
+
options.each_pair do |key, value|
|
23
|
+
if self.class.assume_role_options.include?(key)
|
24
|
+
@assume_role_params[key] = value
|
25
|
+
else
|
26
|
+
next unless STS_KEYS.include?(key)
|
27
|
+
client_opts[key] = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@client = client_opts[:client] || ::Aws::STS::Client.new(client_opts)
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [STS::Client]
|
35
|
+
attr_reader :client
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def refresh
|
40
|
+
c = @client.assume_role(@assume_role_params).credentials
|
41
|
+
@credentials = ::Aws::Credentials.new(
|
42
|
+
c.access_key_id,
|
43
|
+
c.secret_access_key,
|
44
|
+
c.session_token,
|
45
|
+
)
|
46
|
+
@expiration = c.expiration
|
47
|
+
end
|
48
|
+
|
49
|
+
class << self
|
50
|
+
# @api private
|
51
|
+
def assume_role_options
|
52
|
+
@aro ||= begin
|
53
|
+
input = ::Aws::STS::Client.api.operation(:assume_role).input
|
54
|
+
Set.new(input.shape.member_names)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require_relative "includes"
|
2
|
+
require_relative "../../types"
|
3
|
+
|
4
|
+
class AwsAssumeRole::Credentials::Providers::MfaSessionCredentials
|
5
|
+
include AwsAssumeRole::Vendored::Aws::CredentialProvider
|
6
|
+
include AwsAssumeRole::Vendored::Aws::RefreshingCredentials
|
7
|
+
include AwsAssumeRole::Ui
|
8
|
+
include AwsAssumeRole::Logging
|
9
|
+
include AwsAssumeRole
|
10
|
+
Types = Dry::Types.module
|
11
|
+
extend Dry::Initializer::Mixin
|
12
|
+
|
13
|
+
attr_reader :permanent_credentials
|
14
|
+
|
15
|
+
option :permanent_credentials, default: proc { credentials }
|
16
|
+
option :credentials
|
17
|
+
option :expiration, type: Types::Strict::Time, default: proc { Time.now }
|
18
|
+
option :first_time, type: Types::Strict::Bool, default: proc { true }
|
19
|
+
option :persist_session, type: Types::Strict::Bool, default: proc { true }
|
20
|
+
option :duration_seconds, type: Types::Coercible::Int, default: proc { 3600 }
|
21
|
+
option :region, type: AwsAssumeRole::Types::Region.optional, default: proc { AwsAssumeRole.Config.region }
|
22
|
+
option :serial_number, type: AwsAssumeRole::Types::MfaSerial.optional, default: proc { "automatic" }
|
23
|
+
|
24
|
+
def initialize(*options)
|
25
|
+
super(*options)
|
26
|
+
@permanent_credentials ||= credentials
|
27
|
+
@credentials = nil
|
28
|
+
@serial_number = resolve_serial_number(serial_number)
|
29
|
+
AwsAssumeRole::Vendored::Aws::RefreshingCredentials.instance_method(:initialize).bind(self).call(*options)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def keyring_username
|
35
|
+
@keyring_username ||= "#{@identity.to_json}|#{@serial_number}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def sts_client
|
39
|
+
@sts_client ||= Aws::STS::Client.new(region: @region, credentials: @permanent_credentials)
|
40
|
+
end
|
41
|
+
|
42
|
+
def prompt_for_token(first_time)
|
43
|
+
text = first_time ? t("options.mfa_token.first_time") : t("options.mfa_token.other_times")
|
44
|
+
Ui.input.ask text
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialized
|
48
|
+
@first_time = false
|
49
|
+
end
|
50
|
+
|
51
|
+
def refresh
|
52
|
+
return set_credentials_from_keyring if @persist_session && @first_time
|
53
|
+
refresh_using_mfa if near_expiration?
|
54
|
+
broadcast(:mfa_completed)
|
55
|
+
end
|
56
|
+
|
57
|
+
def refresh_using_mfa
|
58
|
+
token_code = prompt_for_token(@first_time)
|
59
|
+
token = sts_client.get_session_token(
|
60
|
+
duration_seconds: @duration_seconds,
|
61
|
+
serial_number: @serial_number,
|
62
|
+
token_code: token_code,
|
63
|
+
)
|
64
|
+
initialized
|
65
|
+
instance_credentials token.credentials
|
66
|
+
persist_credentials if @persist_session
|
67
|
+
end
|
68
|
+
|
69
|
+
def credentials_from_keyring
|
70
|
+
@credentials_from_keyring ||= AwsAssumeRole::Store::Keyring.fetch @keyring_username
|
71
|
+
rescue Aws::Errors::NoSuchProfileError
|
72
|
+
logger.debug "Key not found"
|
73
|
+
@credentials_from_keyring = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def persist_credentials
|
77
|
+
AwsAssumeRole::Store::Keyring.save_credentials @keyring_username, @credentials, expiration: @expiration
|
78
|
+
end
|
79
|
+
|
80
|
+
def instance_credentials(credentials)
|
81
|
+
return unless credentials
|
82
|
+
@credentials = AwsAssumeRole::Store::Serialization.credentials_from_hash(credentials)
|
83
|
+
@expiration = credentials.respond_to?(:expiration) ? credentials.expiration : Time.parse(credentials[:expiration])
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_credentials_from_keyring
|
87
|
+
instance_credentials credentials_from_keyring
|
88
|
+
initialized
|
89
|
+
refresh_using_mfa unless @credentials && !near_expiration?
|
90
|
+
end
|
91
|
+
|
92
|
+
def identity
|
93
|
+
@identity ||= sts_client.get_caller_identity
|
94
|
+
end
|
95
|
+
|
96
|
+
def resolve_serial_number(serial_number)
|
97
|
+
return serial_number unless serial_number.nil? || serial_number == "automatic"
|
98
|
+
user_name = identity.arn.split("/")[1]
|
99
|
+
"arn:aws:iam::#{identity.account}:mfa/#{user_name}"
|
100
|
+
end
|
101
|
+
Dry::Types.register_class(self)
|
102
|
+
end
|