aws_assume_role 1.1.0-universal-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rubocop.yml +57 -0
  4. data/.ruby-version +1 -0
  5. data/.simplecov +22 -0
  6. data/.travis.yml +24 -0
  7. data/CHANGELOG.md +61 -0
  8. data/Gemfile +18 -0
  9. data/LICENSE.md +201 -0
  10. data/README.md +303 -0
  11. data/Rakefile +63 -0
  12. data/aws_assume_role.gemspec +56 -0
  13. data/bin/aws-assume-role +4 -0
  14. data/i18n/en.yml +109 -0
  15. data/lib/aws_assume_role.rb +4 -0
  16. data/lib/aws_assume_role/cli.rb +20 -0
  17. data/lib/aws_assume_role/cli/actions/abstract_action.rb +61 -0
  18. data/lib/aws_assume_role/cli/actions/configure_profile.rb +24 -0
  19. data/lib/aws_assume_role/cli/actions/configure_role_assumption.rb +22 -0
  20. data/lib/aws_assume_role/cli/actions/console.rb +70 -0
  21. data/lib/aws_assume_role/cli/actions/delete_profile.rb +22 -0
  22. data/lib/aws_assume_role/cli/actions/includes.rb +12 -0
  23. data/lib/aws_assume_role/cli/actions/list_profiles.rb +12 -0
  24. data/lib/aws_assume_role/cli/actions/migrate_profile.rb +20 -0
  25. data/lib/aws_assume_role/cli/actions/reset_environment.rb +50 -0
  26. data/lib/aws_assume_role/cli/actions/run.rb +36 -0
  27. data/lib/aws_assume_role/cli/actions/set_environment.rb +62 -0
  28. data/lib/aws_assume_role/cli/actions/test.rb +35 -0
  29. data/lib/aws_assume_role/cli/commands/configure.rb +32 -0
  30. data/lib/aws_assume_role/cli/commands/console.rb +19 -0
  31. data/lib/aws_assume_role/cli/commands/delete.rb +13 -0
  32. data/lib/aws_assume_role/cli/commands/environment.rb +34 -0
  33. data/lib/aws_assume_role/cli/commands/list.rb +12 -0
  34. data/lib/aws_assume_role/cli/commands/migrate.rb +13 -0
  35. data/lib/aws_assume_role/cli/commands/run.rb +19 -0
  36. data/lib/aws_assume_role/cli/commands/test.rb +20 -0
  37. data/lib/aws_assume_role/cli/includes.rb +3 -0
  38. data/lib/aws_assume_role/configuration.rb +30 -0
  39. data/lib/aws_assume_role/core_ext/aws-sdk/credential_provider_chain.rb +4 -0
  40. data/lib/aws_assume_role/core_ext/aws-sdk/includes.rb +9 -0
  41. data/lib/aws_assume_role/credentials/factories.rb +11 -0
  42. data/lib/aws_assume_role/credentials/factories/abstract_factory.rb +33 -0
  43. data/lib/aws_assume_role/credentials/factories/assume_role.rb +39 -0
  44. data/lib/aws_assume_role/credentials/factories/default_chain_provider.rb +113 -0
  45. data/lib/aws_assume_role/credentials/factories/environment.rb +26 -0
  46. data/lib/aws_assume_role/credentials/factories/includes.rb +15 -0
  47. data/lib/aws_assume_role/credentials/factories/instance_profile.rb +19 -0
  48. data/lib/aws_assume_role/credentials/factories/repository.rb +37 -0
  49. data/lib/aws_assume_role/credentials/factories/shared.rb +19 -0
  50. data/lib/aws_assume_role/credentials/factories/static.rb +18 -0
  51. data/lib/aws_assume_role/credentials/includes.rb +6 -0
  52. data/lib/aws_assume_role/credentials/providers/assume_role_credentials.rb +60 -0
  53. data/lib/aws_assume_role/credentials/providers/includes.rb +9 -0
  54. data/lib/aws_assume_role/credentials/providers/mfa_session_credentials.rb +119 -0
  55. data/lib/aws_assume_role/credentials/providers/shared_keyring_credentials.rb +41 -0
  56. data/lib/aws_assume_role/includes.rb +38 -0
  57. data/lib/aws_assume_role/logging.rb +27 -0
  58. data/lib/aws_assume_role/profile_configuration.rb +73 -0
  59. data/lib/aws_assume_role/runner.rb +40 -0
  60. data/lib/aws_assume_role/store/includes.rb +8 -0
  61. data/lib/aws_assume_role/store/keyring.rb +61 -0
  62. data/lib/aws_assume_role/store/serialization.rb +20 -0
  63. data/lib/aws_assume_role/store/shared_config_with_keyring.rb +250 -0
  64. data/lib/aws_assume_role/types.rb +31 -0
  65. data/lib/aws_assume_role/ui.rb +57 -0
  66. data/lib/aws_assume_role/vendored/aws.rb +4 -0
  67. data/lib/aws_assume_role/vendored/aws/README.md +2 -0
  68. data/lib/aws_assume_role/vendored/aws/assume_role_credentials.rb +67 -0
  69. data/lib/aws_assume_role/vendored/aws/includes.rb +9 -0
  70. data/lib/aws_assume_role/vendored/aws/refreshing_credentials.rb +58 -0
  71. data/lib/aws_assume_role/vendored/aws/shared_config.rb +223 -0
  72. data/lib/aws_assume_role/version.rb +5 -0
  73. metadata +438 -0
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "includes"
4
+
5
+ module AwsAssumeRole
6
+ class Configuration
7
+ extend Dry::Configurable
8
+ Types = Dry::Types.module
9
+
10
+ setting(:backend_plugin, ENV.fetch("AWS_ASSUME_ROLE_KEYRING_PLUGIN", nil)) do |value|
11
+ Types::Coercible::String[value]
12
+ end
13
+
14
+ setting(:backend, ENV.fetch("AWS_ASSUME_ROLE_KEYRING_BACKEND", "automatic")) do |value|
15
+ value == "automatic" ? nil : Types::Coercible::String[value]
16
+ end
17
+
18
+ setting(:log_level, ENV.fetch("AWS_ASSUME_ROLE_LOG_LEVEL", "WARN")) do |value|
19
+ {
20
+ DEBUG: 0,
21
+ INFO: 1,
22
+ WARN: 2,
23
+ ERROR: 3,
24
+ FATAL: 4,
25
+ UNKNOWN: 5,
26
+ }[value.to_sym] || 2
27
+ end
28
+ end
29
+ Config = Configuration.config
30
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../credentials/factories/default_chain_provider"
4
+ Aws.const_set :CredentialProviderChain, AwsAssumeRole::Credentials::Factories::DefaultChainProvider
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../includes"
4
+ module AwsAssumeRole
5
+ module CoreExt
6
+ module Aws
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "factories/repository"
4
+ require_relative "factories/abstract_factory"
5
+ require_relative "factories/default_chain_provider"
6
+ require_relative "factories/assume_role"
7
+ require_relative "factories/environment"
8
+ require_relative "factories/instance_profile"
9
+ require_relative "factories/shared_keyring"
10
+ require_relative "factories/shared"
11
+ require_relative "factories/static"
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "includes"
4
+ require_relative "repository"
5
+ require_relative "../../profile_configuration"
6
+
7
+ class AwsAssumeRole::Credentials::Factories::AbstractFactory
8
+ include AwsAssumeRole
9
+ include AwsAssumeRole::Credentials::Factories
10
+ include AwsAssumeRole::Logging
11
+
12
+ Dry::Types.register_class(Aws::SharedCredentials)
13
+ attr_reader :credentials, :region, :profile, :role_arn
14
+
15
+ def initialize(_options)
16
+ raise "Not implemented"
17
+ end
18
+
19
+ def self.type(str)
20
+ @type = Types::Strict::Symbol.enum(:credential_provider, :second_factor_provider, :instance_role_provider)[str]
21
+ register_if_complete
22
+ end
23
+
24
+ def self.priority(i)
25
+ @priority = Types::Strict::Int[i]
26
+ register_if_complete
27
+ end
28
+
29
+ def self.register_if_complete
30
+ return unless @type && @priority
31
+ Repository.register_factory(self, @type, @priority)
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "abstract_factory"
4
+ require_relative "../providers/assume_role_credentials"
5
+ require_relative "../providers/mfa_session_credentials"
6
+
7
+ class AwsAssumeRole::Credentials::Factories::AssumeRole < AwsAssumeRole::Credentials::Factories::AbstractFactory
8
+ include AwsAssumeRole::Credentials::Factories
9
+ type :credential_provider
10
+ priority 20
11
+
12
+ def initialize(options)
13
+ logger.debug "AwsAssumeRole::Credentials::Factories::AssumeRole initiated with #{options}"
14
+ return unless options[:profile] || options[:role_arn]
15
+ if options[:profile]
16
+ logger.debug "AwsAssumeRole: #{options[:profile]} found. Trying with profile"
17
+ try_with_profile(options)
18
+ else
19
+ if options[:use_mfa]
20
+ options[:credentials] = AwsAssumeRole::Credentials::Providers::MfaSessionCredentials.new(options).credentials
21
+ end
22
+ @credentials = AwsAssumeRole::Credentials::Providers::AssumeRoleCredentials.new(options)
23
+ end
24
+ end
25
+
26
+ def try_with_profile(options)
27
+ return unless AwsAssumeRole.shared_config.config_enabled?
28
+ logger.debug "AwsAssumeRole: Shared Config enabled"
29
+ @profile = options[:profile]
30
+ @region = options[:region]
31
+ @credentials = assume_role_with_profile(options)
32
+ @region ||= AwsAssumeRole.shared_config.profile_region(@profile)
33
+ @role_arn ||= AwsAssumeRole.shared_config.profile_role(@profile)
34
+ end
35
+
36
+ def assume_role_with_profile(options)
37
+ AwsAssumeRole.shared_config.assume_role_credentials_from_config(options)
38
+ end
39
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "includes"
4
+ require_relative "../../logging"
5
+ require_relative "../../profile_configuration"
6
+ require_relative "abstract_factory"
7
+ require_relative "environment"
8
+ require_relative "repository"
9
+ require_relative "instance_profile"
10
+ require_relative "assume_role"
11
+ require_relative "shared"
12
+ require_relative "static"
13
+
14
+ class AwsAssumeRole::Credentials::Factories::DefaultChainProvider < Dry::Struct
15
+ constructor_type :schema
16
+ include AwsAssumeRole::Credentials::Factories
17
+ include AwsAssumeRole::Logging
18
+
19
+ attribute :access_key_id, Dry::Types["strict.string"].optional
20
+ attribute :credentials, Dry::Types["object"].optional
21
+ attribute :duration_seconds, Dry::Types["coercible.int"].optional
22
+ attribute :external_id, Dry::Types["strict.string"].optional
23
+ attribute :instance_profile_credentials_retries, Dry::Types["strict.int"].default(0)
24
+ attribute :instance_profile_credentials_timeout, Dry::Types["coercible.float"].default(1.0)
25
+ attribute :mfa_serial, Dry::Types["strict.string"].optional
26
+ attribute :no_profile, Dry::Types["strict.bool"].default(false)
27
+ attribute :path, Dry::Types["strict.string"].optional
28
+ attribute :persist_session, Dry::Types["strict.bool"].default(true)
29
+ attribute :profile_name, Dry::Types["strict.string"].optional
30
+ attribute :profile, Dry::Types["strict.string"].optional
31
+ attribute :region, Dry::Types["strict.string"].optional
32
+ attribute :role_arn, Dry::Types["strict.string"].optional
33
+ attribute :role_session_name, Dry::Types["strict.string"].optional
34
+ attribute :secret_access_key, Dry::Types["strict.string"].optional
35
+ attribute :serial_number, Dry::Types["strict.string"].optional
36
+ attribute :session_token, Dry::Types["strict.string"].optional
37
+ attribute :source_profile, Dry::Types["strict.string"].optional
38
+ attribute :use_mfa, Dry::Types["strict.bool"].default(false)
39
+ attribute :yubikey_oath_name, Dry::Types["strict.string"].optional
40
+
41
+ def self.new(options)
42
+ if options.respond_to? :resolve
43
+ finalize_instance new_with_seahorse(options)
44
+ else
45
+ finalize_instance(options)
46
+ end
47
+ end
48
+
49
+ def self.finalize_instance(options)
50
+ new_opts = options.to_h
51
+ new_opts[:profile_name] ||= new_opts[:profile]
52
+ new_opts[:original_profile] = new_opts[:profile_name]
53
+ instance = allocate
54
+ instance.send(:initialize, new_opts)
55
+ instance
56
+ end
57
+
58
+ def self.new_with_seahorse(resolver)
59
+ keys = resolver.resolve
60
+ options = keys.map do |k|
61
+ [k, resolver.send(k)]
62
+ end
63
+ finalize_instance(options.to_h)
64
+ end
65
+
66
+ def resolve(nil_with_role_not_set: false, explicit_default_profile: false)
67
+ resolve_final_credentials(explicit_default_profile)
68
+ # nil_creds = Aws::Credentials.new(nil, nil, nil)
69
+ return nil if (nil_with_role_not_set &&
70
+ @role_arn &&
71
+ @credentials.credentials.session_token.nil?) || @credentials.nil?
72
+ @credentials
73
+ end
74
+
75
+ def to_h
76
+ to_hash
77
+ end
78
+
79
+ private
80
+
81
+ def resolve_final_credentials(explicit_default_profile = false)
82
+ resolve_credentials(:credential_provider, true, explicit_default_profile)
83
+ return @credentials if @credentials && @credentials.set? && !use_mfa && !role_arn
84
+ resolve_credentials(:second_factor_provider, true, explicit_default_profile)
85
+ return @credentials if @credentials && @credentials.set?
86
+ resolve_credentials(:instance_role_provider, true, explicit_default_profile)
87
+ return @credentials if @credentials && @credentials.set?
88
+ nil
89
+ end
90
+
91
+ def resolve_credentials(type, break_if_successful = false, explicit_default_profile = false)
92
+ factories_to_try = Repository.factories[type]
93
+ factories_to_try.each do |x|
94
+ options = to_h
95
+ options[:credentials] = credentials if credentials && credentials.set?
96
+ logger.debug "About to try credential lookup with #{x}"
97
+ factory = x.new(options)
98
+ @region ||= factory.region
99
+ @profile ||= factory.profile
100
+ @role_arn ||= factory.role_arn
101
+ next unless factory.credentials && factory.credentials.set?
102
+ logger.debug "Profile currently #{@profile}"
103
+ next if explicit_default_profile && (@profile == "default") && (@profile != @original_profile)
104
+ @credentials ||= factory.credentials
105
+ logger.debug "Got #{@credentials}"
106
+ break if break_if_successful
107
+ end
108
+ end
109
+ end
110
+
111
+ module AwsAssumeRole
112
+ DefaultProvider = AwsAssumeRole::Credentials::Factories::DefaultChainProvider
113
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "abstract_factory"
4
+
5
+ class AwsAssumeRole::Credentials::Factories::Environment < AwsAssumeRole::Credentials::Factories::AbstractFactory
6
+ type :credential_provider
7
+ priority 10
8
+
9
+ def initialize(_options, **)
10
+ key = %w[AWS_ACCESS_KEY_ID AMAZON_ACCESS_KEY_ID AWS_ACCESS_KEY]
11
+ secret = %w[AWS_SECRET_ACCESS_KEY AMAZON_SECRET_ACCESS_KEY AWS_SECRET_KEY]
12
+ token = %w[AWS_SESSION_TOKEN AMAZON_SESSION_TOKEN]
13
+ region = %w[AWS_DEFAULT_REGION]
14
+ profile = %w[AWS_PROFILE]
15
+ @credentials = Aws::Credentials.new(envar(key), envar(secret), envar(token))
16
+ @region = envar(region)
17
+ @profile = envar(profile)
18
+ end
19
+
20
+ def envar(keys)
21
+ keys.each do |key|
22
+ return ENV[key] if ENV.key?(key)
23
+ end
24
+ nil
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../includes"
4
+ require_relative "../../logging"
5
+ require_relative "../../vendored/aws"
6
+ require_relative "../../../aws_assume_role"
7
+
8
+ module AwsAssumeRole::Credentials
9
+ module Factories
10
+ Types = Dry::Types.module
11
+ include AwsAssumeRole
12
+ include AwsAssumeRole::Logging
13
+ include AwsAssumeRole::Vendored::Aws
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "abstract_factory"
4
+
5
+ class AwsAssumeRole::Credentials::Factories::InstanceProfile < AwsAssumeRole::Credentials::Factories::AbstractFactory
6
+ type :instance_role_provider
7
+ priority 40
8
+
9
+ def initialize(options = {})
10
+ options[:retries] ||= options[:instance_profile_credentials_retries] || 0
11
+ options[:http_open_timeout] ||= options[:instance_profile_credentials_timeout] || 1
12
+ options[:http_read_timeout] ||= options[:instance_profile_credentials_timeout] || 1
13
+ @credentials = if ENV["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"]
14
+ Aws::ECSCredentials.new(options)
15
+ else
16
+ Aws::InstanceProfileCredentials.new(options)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "includes"
4
+ require_relative "abstract_factory"
5
+
6
+ class AwsAssumeRole::Credentials::Factories::Repository
7
+ include AwsAssumeRole::Credentials::Factories
8
+
9
+ SubFactoryRepositoryType = Types::Hash.schema(Types::Coercible::Int => Types::Strict::Array)
10
+
11
+ FactoryRepositoryType = Types::Hash.schema(
12
+ credential_provider: SubFactoryRepositoryType,
13
+ second_factor_provider: SubFactoryRepositoryType,
14
+ instance_role_provider: SubFactoryRepositoryType,
15
+ )
16
+
17
+ def self.factories
18
+ repository.keys.map { |t| [t, flatten_factory_type_list(t)] }.to_h
19
+ end
20
+
21
+ def self.repository
22
+ @repository ||= FactoryRepositoryType[
23
+ credential_provider: {},
24
+ second_factor_provider: {},
25
+ instance_role_provider: {},
26
+ ]
27
+ end
28
+
29
+ def self.register_factory(klass, type, priority)
30
+ repository[type][priority] ||= []
31
+ repository[type][priority] << klass
32
+ end
33
+
34
+ def self.flatten_factory_type_list(type)
35
+ repository[type].keys.sort.map { |x| @repository[type][x] }.flatten
36
+ end
37
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "abstract_factory"
4
+ require_relative "../providers/shared_keyring_credentials"
5
+
6
+ class AwsAssumeRole::Credentials::Factories::Shared < AwsAssumeRole::Credentials::Factories::AbstractFactory
7
+ type :credential_provider
8
+ priority 30
9
+
10
+ def initialize(options = {})
11
+ logger.debug "Shared Factory initiated with #{options}"
12
+ @profile = options[:profile]
13
+ @credentials = AwsAssumeRole::Credentials::Providers::SharedKeyringCredentials.new(options)
14
+ @region = @credentials.region
15
+ @role_arn = @credentials.role_arn
16
+ rescue Aws::Errors::NoSuchProfileError
17
+ nil
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "abstract_factory"
4
+
5
+ class AwsAssumeRole::Credentials::Factories::Static < AwsAssumeRole::Credentials::Factories::AbstractFactory
6
+ type :credential_provider
7
+ priority 0
8
+
9
+ def initialize(options = {})
10
+ @credentials = Aws::Credentials.new(
11
+ options[:access_key_id],
12
+ options[:secret_access_key],
13
+ options[:session_token],
14
+ )
15
+ @region = options[:region]
16
+ @profile = options[:profile]
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../includes"
4
+ module AwsAssumeRole
5
+ module Credentials end
6
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "includes"
4
+ require "set"
5
+
6
+ class AwsAssumeRole::Credentials::Providers::AssumeRoleCredentials
7
+ include AwsAssumeRole::Vendored::Aws::CredentialProvider
8
+ include AwsAssumeRole::Vendored::Aws::RefreshingCredentials
9
+
10
+ # @option options [required, String] :role_arn
11
+ # @option options [required, String] :role_session_name
12
+ # @option options [String] :policy
13
+ # @option options [Integer] :duration_seconds
14
+ # @option options [String] :external_id
15
+ # @option options [STS::Client] :client
16
+ #
17
+ #
18
+
19
+ STS_KEYS = %i[role_arn role_session_name policy duration_seconds external_id client credentials region].freeze
20
+
21
+ def initialize(options = {})
22
+ client_opts = {}
23
+ @assume_role_params = {}
24
+ options.each_pair do |key, value|
25
+ if self.class.assume_role_options.include?(key)
26
+ @assume_role_params[key] = value
27
+ else
28
+ next unless STS_KEYS.include?(key)
29
+ client_opts[key] = value
30
+ end
31
+ end
32
+ @client = client_opts[:client] || ::Aws::STS::Client.new(client_opts)
33
+ super
34
+ end
35
+
36
+ # @return [STS::Client]
37
+ attr_reader :client
38
+
39
+ private
40
+
41
+ def refresh
42
+ c = @client.assume_role(@assume_role_params).credentials
43
+ @credentials = ::Aws::Credentials.new(
44
+ c.access_key_id,
45
+ c.secret_access_key,
46
+ c.session_token,
47
+ )
48
+ @expiration = c.expiration
49
+ end
50
+
51
+ class << self
52
+ # @api private
53
+ def assume_role_options
54
+ @aro ||= begin
55
+ input = ::Aws::STS::Client.api.operation(:assume_role).input
56
+ Set.new(input.shape.member_names)
57
+ end
58
+ end
59
+ end
60
+ end