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,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
|