aws_assume_role 0.1.1 → 0.1.2

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +0 -4
  4. data/.ruby-version +1 -0
  5. data/.simplecov +22 -0
  6. data/.travis.yml +10 -1
  7. data/Gemfile +1 -0
  8. data/README.md +9 -4
  9. data/Rakefile +16 -1
  10. data/aws_assume_role.gemspec +4 -2
  11. data/lib/aws_assume_role/cli/actions/abstract_action.rb +7 -3
  12. data/lib/aws_assume_role/cli/actions/includes.rb +1 -9
  13. data/lib/aws_assume_role/cli/actions/run.rb +1 -1
  14. data/lib/aws_assume_role/cli/actions/test.rb +3 -1
  15. data/lib/aws_assume_role/cli/includes.rb +1 -0
  16. data/lib/aws_assume_role/core_ext/aws-sdk/includes.rb +1 -1
  17. data/lib/aws_assume_role/credentials/factories/abstract_factory.rb +1 -1
  18. data/lib/aws_assume_role/credentials/factories/assume_role.rb +13 -14
  19. data/lib/aws_assume_role/credentials/factories/default_chain_provider.rb +56 -47
  20. data/lib/aws_assume_role/credentials/factories/includes.rb +7 -11
  21. data/lib/aws_assume_role/credentials/factories/instance_profile.rb +1 -1
  22. data/lib/aws_assume_role/credentials/factories/repository.rb +2 -2
  23. data/lib/aws_assume_role/credentials/factories/shared.rb +7 -5
  24. data/lib/aws_assume_role/credentials/includes.rb +4 -0
  25. data/lib/aws_assume_role/credentials/providers/includes.rb +3 -5
  26. data/lib/aws_assume_role/credentials/providers/mfa_session_credentials.rb +20 -23
  27. data/lib/aws_assume_role/credentials/providers/shared_keyring_credentials.rb +27 -10
  28. data/lib/aws_assume_role/includes.rb +9 -3
  29. data/lib/aws_assume_role/profile_configuration.rb +24 -25
  30. data/lib/aws_assume_role/runner.rb +9 -10
  31. data/lib/aws_assume_role/store/includes.rb +1 -11
  32. data/lib/aws_assume_role/store/keyring.rb +1 -2
  33. data/lib/aws_assume_role/store/shared_config_with_keyring.rb +86 -28
  34. data/lib/aws_assume_role/types.rb +1 -2
  35. data/lib/aws_assume_role/vendored/aws/assume_role_credentials.rb +0 -1
  36. data/lib/aws_assume_role/vendored/aws/includes.rb +1 -1
  37. data/lib/aws_assume_role/vendored/aws/refreshing_credentials.rb +0 -2
  38. data/lib/aws_assume_role/vendored/aws/shared_config.rb +4 -1
  39. data/lib/aws_assume_role/version.rb +1 -1
  40. metadata +40 -9
  41. data/lib/aws_assume_role/credentials/factories/shared_keyring.rb +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c34fe41cd7fb5cf0bdcbcc06ed9c29b68a2df815
4
- data.tar.gz: 1ce33d2f0ba1ccc59035b5909b3dfdd23daa0ec8
3
+ metadata.gz: 740d4539f3f7bf68b7acedc131890496b67eaef4
4
+ data.tar.gz: a5f739bbb05c1cd1edfc59e156ee2a348c88c9ff
5
5
  SHA512:
6
- metadata.gz: 9189297164904fa24ce99e87d8fa37b8c8025b9bb4ccdc902d0cca489a69a5cafdd101fccac38986c45442fa05ebb4efbb0d5d0bc3a3740996d18be7c689d99f
7
- data.tar.gz: b1e6cd683fc648571d292cfc5c911e6448d8c9c0ab0082d0f2800fc97e5d785aac6a0210e37bad3962d1d9f6107e53d730ba8bf4f4ace501b3297897a13da8d6
6
+ metadata.gz: 0898326d54de021a939f2375466c7376a3e42cca8b7c597d4b03a9b11b4a407b078b4560ec3790418c462a84bbde0836a2f9ea30acf5e1b3cebfab25e2567a55
7
+ data.tar.gz: f161cc86abf84c2e893cc9426bea9861b02b30bd31fccbf2ed8f7ac526252d51f236e530b5a178fffde1db94ef910a7cf87fc22c9645f8685f0eaa49eeb58c24
data/.gitignore CHANGED
@@ -5,3 +5,5 @@ pkg/
5
5
  Gemfile.lock
6
6
  spec/reports/
7
7
  tags
8
+ *.gem
9
+ coverage
data/.rubocop.yml CHANGED
@@ -1,5 +1,4 @@
1
1
  ---
2
- #require: rubocop-rspec
3
2
  AllCops:
4
3
  DisplayCopNames: true
5
4
  Exclude:
@@ -26,9 +25,6 @@ Metrics/PerceivedComplexity:
26
25
  Style/IndentationWidth:
27
26
  Width: 4
28
27
 
29
- RSpec/ExampleLength:
30
- Enabled: false
31
-
32
28
  Style/TrailingCommaInArguments:
33
29
  EnforcedStyleForMultiline: comma
34
30
 
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.10
data/.simplecov ADDED
@@ -0,0 +1,22 @@
1
+ require 'coveralls'
2
+ Coveralls.wear_merged!
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ])
8
+
9
+ SimpleCov.start do
10
+
11
+ project_name 'AWS Assume Role'
12
+
13
+ add_filter '/spec/'
14
+ add_filter 'lib/aws_assume_role/vendored'
15
+
16
+ %w(aws_assume_role).each do |group_name|
17
+ add_group(group_name, "/#{group_name}/lib")
18
+ end
19
+
20
+ merge_timeout 60 * 15 # 15 minutes
21
+
22
+ end
data/.travis.yml CHANGED
@@ -1,11 +1,20 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 2.1
3
4
  - 2.2
5
+ - 2.3.0
6
+ sudo: false
7
+ script: bundle exec rake
4
8
  deploy:
5
9
  provider: rubygems
6
10
  api_key:
7
- secure: ndWQ3WVAkQRcKO1MhKz4OY7shjLpGNtOw6vUR62Eza9nc1i32pyLXs3N8gfXpSQff9SvJP/3UL1GaDDFbA539bMAlLqLaXtsLlu6rUr+QTpa3a9Y1iQfuLixJ/lzJU/7KmWJkUG9iKs/7p+83X9uUQK10BA1eHuClNOmTkLrw4s5WgDaKKG7Sy9ihZ4gIQtONQHZbCQy21UOeuObGXAuPi3mLunoe/ygmCIrNt8T3BmuBmDoB9q6Z1YChEDnyWi5ALnHckZO0IQ5U5BP5WLTaqSKDXtcUifs9uPJ2YHubqghpbIf+5MOfrG92zFoSR4NIuFjhkQ4yT9rRZ8g1bOhBFLe5Xa/GJbX5XNWq/IStEOiWnXPaR6kpTpmjskR1NbonfPB1or++wh7zRT9AQE+loZKWrUTGLRa1vGTlIMVQzzF5jskbIogA8Rmzg0K4vGJ8W0xftWTez/1WWl+yJEwd8JIU9fHp+P1dsLf3bZ8vFgkH0jMm6neaibK7O64RbPdAERQ5s+9zXGjYug5H6xPnWYP7c/tAJn4g020aUGhdftTwpMpf8d3dLa3J4PYQ8XBeEPqjUU2DGscyL9cIbUwCfY5USwulom5tG0yeA/4nS/T36zx/QwOcw60SS2i7QGhN4CeHS6lIFbhb9lFvsRY31JDaR3TgysnX1hGASw22vs=
11
+ secure: H6MYP5cWFC0BtqrxW6ahc1RFxywtyKRFjGlSpyoBM+AH2y8U194toWQdGyO/QMRQVr7vAZf+MdxYTutDvnBEkwQbof6QBJ1+4GFWSqFgYAVEV5Ddva0ea5dVE8xC3rMRvd+i5KTzwuVNX/+Cux49v2wGRWZLKOmBSWbujsL8SbpdKaPi+qsClkdz3YTrHpGEEWTPNBNTwDMlg+qAX3UkqoAxD5ebrUaFPdJR83yMSGUPfTm/urlKvkx85MONuj7lPL1CyoYJCvy31bE6CWGq2L/+2Fnk8RvNMCaDffY+8YjKhWduBLrGuUYWf+ZcERxW6AxDy6BFIkekpFwpeaDmrdfSTK0aELSZogGqs9VHs9O1pTApdS/NRYDzxC9hmlvub80xC2uI1Vnhn04Z95Gh9KYh0H20UnlBJJ7ewvFPHzQ3zK8Z2O3kJOeZo0rX2d3yGOydyHlf1dX/auGnn8QVcr7w1jERQDLi5ZEAR+EGnYROvfGKjfP9rgaLoouTbEGXx7KV9QQjLUsmQ0q2yu+HoVlQaDtv7VEQTtFnvdmiVGYbWj+DhaquvTmHyiizO7hFOfvVYYFyOM2iFoRCY+dT3kapqc0DM94BUjxV3tMZX6MYNYfwnNwhNNpTXLVvVXP9cShL+ogwY/E0C2Fg2CYdY5/Ioe6hUbAiPx79dwzVfic=
8
12
  gem: aws_assume_role
9
13
  on:
10
14
  tags: true
11
15
  repo: scalefactory/aws-assume-role
16
+ notifications:
17
+ slack:
18
+ secure: RmJmJSSDI8qdIpM2KKYoXX2mpcL85YZ9r9gF4rauZH9TuqnYOPP3kQ5iYJsE0VUTuZpuvQ8Axoux5IQr+IDK7kMrmrI0iaZp1dAR9tGK+aLF73sprOmQEou6HIoDs97UQhOWlsAUR8max/7WYdJYJ1o78dqavfFtOy0VcHCkUMRf+WxcKzz+8MunsocIYi0HXuz5vC3RAZCOaK2h8epXzmnWq0ke8YeTmddpDWC85wzeDNjA9T1j5WD+y6gC9F0vyaqVqDCsCXlbRKZl7a1TU9QGDVyBzowoGsWmTpFR80v4CKofAn6nnMRqblwATOS1jMT+HC+Yku29qFzXPugYa2KAUSQaYQiOe+TE5IDa2Exe/57ZQCOq4ve8gKSE9aQXh4Riq3u8qccM+UeoQdcwgXQIciTeWjqi4LQro6Dbyrv8XrUbxdG0VPsWmf49jbWgq6PPAJqdcbXr9eGb+81uJ2REa1vhDYZu4T3JHv4erd5QlyYWzeBJ/LMQav/C5mnMF43jg8DzZ2g0BZBao/reO9xcZre/ka8eOus9Ll1i+8PCxmFZMx2KDPC9i5R7bXL/CwPBjzFInmvHM0cgKjxrRSY6xMWSPyBbgdsKJl2qag74K5xG+2VPlMcVx0ikTKVjsja5iPlOYKhflGAfCKvpzPcd2QoEWg8jZYqZtO9Nj+M=
19
+ on_success: change
20
+ on_failure: change
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  group :test do
7
+ gem "coveralls", require: false
7
8
  gem "rake"
8
9
  end
9
10
 
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  aws-assume-role
2
2
  ---------------
3
+ [![Build Status](https://travis-ci.org/scalefactory/aws-assume-role.svg?branch=master)](https://travis-ci.org/scalefactory/aws-assume-role)
4
+ [![Coverage Status](https://coveralls.io/repos/github/scalefactory/aws-assume-role/badge.svg?branch=master)](https://coveralls.io/github/scalefactory/aws-assume-role?branch=master)
5
+ [![Code Climate](https://codeclimate.com/github/scalefactory/aws-assume-role/badges/gpa.svg)](https://codeclimate.com/github/scalefactory/aws-assume-role)
6
+ [![Dependencies](https://img.shields.io/librariesio/github/scalefactory/aws-assume-role.svg)](https://libraries.io/rubygems/aws_assume_role)
7
+ [![Gem Version](https://badge.fury.io/rb/aws_assume_role.svg)](https://badge.fury.io/rb/aws_assume_role)
3
8
 
4
9
  aws-assume-role is a utility intended for developer and operator environments
5
10
  who need to use 2FA and role assumption to access AWS services.
@@ -17,11 +22,11 @@ disk as unencrypted files.
17
22
 
18
23
  It allows easy credential management and role assumption with a 2FA/MFA device.
19
24
 
20
- For more information on role assumption, see the AWS documentation.
25
+ For more information on role assumption, see the [AWS documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html).
21
26
 
22
27
  Requirements
23
28
  ------------
24
- * Ruby ≥ 2.2
29
+ * Ruby ≥ 2.1
25
30
  * OS X KeyChain or GNOME Keyring
26
31
 
27
32
  Install
@@ -179,14 +184,14 @@ where options is a hash with the following symbol keys:
179
184
  `aws_assume_role` resolves credentials in almost the same way as the AWS SDK, i.e.:
180
185
 
181
186
  ```no-highlight
182
- static credentials ⟶ environment variables ⟶ configured profiles
187
+ static credentials ⟶ environment variables ⟶ configured profiles role ⟶ assumption (look up source profile and check for 2FA)
183
188
  ```
184
189
 
185
190
  Any of the above may get chained to do MFA or role assumption, or both,
186
191
  in the following order:
187
192
 
188
193
  ```no-highlight
189
- second factor ⟶ role assumption (look up source profile and check for 2FA) ⟶ ecs/instance profile
194
+ second factor ⟶ ecs/instance profile
190
195
  ```
191
196
 
192
197
  These are the same as the AWS SDK equivalents whereever possible. The command line help will give an explanation of the rest.
data/Rakefile CHANGED
@@ -1,8 +1,23 @@
1
1
  require "bundler/gem_tasks"
2
- task default: :spec
2
+ task default: :test
3
3
 
4
4
  begin
5
5
  require "rspec/core/rake_task"
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
  rescue LoadError # rubocop:disable Lint/HandleExceptions
8
8
  end
9
+
10
+ begin
11
+ require "rubocop/rake_task"
12
+ RuboCop::RakeTask.new(:rubocop)
13
+ rescue LoadError # rubocop:disable Lint/HandleExceptions
14
+ end
15
+
16
+ task :test => [:no_pry, :rubocop, :spec] # rubocop:disable Style/HashSyntax
17
+
18
+ task :no_pry do
19
+ files = Dir.glob("**/**").reject { |x| x.match(/^spec|Gemfile|coverage|\.gemspec$|Rakefile/) || File.directory?(x) }
20
+ files.each do |file|
21
+ raise "Use of pry found in #{file}." if File.read(file) =~ /"pry"/
22
+ end
23
+ end
@@ -22,10 +22,10 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^bin/aws}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_runtime_dependency "activesupport", "~> 4.0"
25
+ spec.add_runtime_dependency "activesupport", "~> 4.2"
26
26
  spec.add_runtime_dependency "aws-sdk", "~> 2.7"
27
27
  spec.add_runtime_dependency "dry-configurable", "~> 0.5"
28
- spec.add_runtime_dependency "dry-initializer", "~> 1.1"
28
+ spec.add_runtime_dependency "dry-struct", "~> 0.1"
29
29
  spec.add_runtime_dependency "dry-types", "~> 0.9"
30
30
  spec.add_runtime_dependency "dry-validation", "~> 0.10"
31
31
  spec.add_runtime_dependency "gli", "~> 2.15"
@@ -38,6 +38,8 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency "rspec", "~> 3.5"
39
39
  spec.add_development_dependency "rubocop", "~> 0.46"
40
40
  spec.add_development_dependency "yard", "~> 0.9"
41
+ spec.add_development_dependency "simplecov", "~> 0.13"
42
+ spec.add_development_dependency "webmock", "~> 2.3"
41
43
 
42
44
  case Gem::Platform.local.os
43
45
  when "linux"
@@ -4,12 +4,15 @@ require_relative "../../profile_configuration"
4
4
  class AwsAssumeRole::Cli::Actions::AbstractAction
5
5
  include AwsAssumeRole
6
6
  include AwsAssumeRole::Types
7
- include Ui
7
+ include AwsAssumeRole::Ui
8
+ include AwsAssumeRole::Logging
8
9
  CommandSchema = proc { raise "CommandSchema Not implemented" }
9
10
 
10
11
  def initialize(global_options, options, args)
11
12
  config = ProfileConfiguration.new_from_cli(global_options, options, args)
12
- result = validate_options(config.to_h.deep_symbolize_keys)
13
+ logger.debug "Config initialized with #{config.to_hash}"
14
+ result = validate_options(config.to_hash)
15
+ logger.debug "Config validated as #{result.to_hash}"
13
16
  return act_on(config) if result.success?
14
17
  Ui.show_validation_errors result
15
18
  end
@@ -17,8 +20,9 @@ class AwsAssumeRole::Cli::Actions::AbstractAction
17
20
  private
18
21
 
19
22
  def try_for_credentials(config)
20
- @provider ||= AwsAssumeRole::Credentials::Factories::DefaultChainProvider.new(config.to_h)
23
+ @provider ||= AwsAssumeRole::Credentials::Factories::DefaultChainProvider.new(config.to_hash)
21
24
  creds = @provider.resolve(nil_with_role_not_set: true)
25
+ logger.debug "Got credentials #{creds}"
22
26
  return creds unless creds.nil?
23
27
  rescue NoMethodError
24
28
  error "Cannot find any credentials"
@@ -1,13 +1,5 @@
1
- require "i18n"
2
- require "aws-sdk"
3
- require "dry-types"
1
+ require_relative "../includes"
4
2
  require_relative "../../types"
5
- require "dry-validation"
6
- require "active_support/core_ext/hash/compact"
7
- require "active_support/core_ext/hash/keys"
8
- require "launchy"
9
- require "open-uri"
10
- require "json"
11
3
  require_relative "../../../aws_assume_role"
12
4
 
13
5
  module AwsAssumeRole
@@ -20,7 +20,7 @@ class AwsAssumeRole::Cli::Actions::Run < AwsAssumeRole::Cli::Actions::AbstractAc
20
20
  def act_on(config)
21
21
  credentials = try_for_credentials config.to_h
22
22
  unless config.args.empty?
23
- Runner.new(config.args,
23
+ Runner.new(command: config.args,
24
24
  environment: { "AWS_DEFAULT_REGION" => resolved_region },
25
25
  credentials: credentials)
26
26
  end
@@ -17,7 +17,9 @@ class AwsAssumeRole::Cli::Actions::Test < AwsAssumeRole::Cli::Actions::AbstractA
17
17
  end
18
18
 
19
19
  def act_on(config)
20
- credentials = try_for_credentials config.to_h
20
+ logger.debug "Will try for credentials"
21
+ credentials = try_for_credentials config
22
+ logger.debug "Got credentials #{credentials}"
21
23
  client = Aws::STS::Client.new(credentials: credentials, region: resolved_region)
22
24
  identity = client.get_caller_identity
23
25
  out format(t("commands.test.output"), identity.account, identity.arn, identity.user_id)
@@ -0,0 +1 @@
1
+ require_relative "../includes"
@@ -1,4 +1,4 @@
1
- require "aws-sdk"
1
+ require_relative "../../includes"
2
2
  module AwsAssumeRole
3
3
  module CoreExt
4
4
  module Aws
@@ -15,7 +15,7 @@ class AwsAssumeRole::Credentials::Factories::AbstractFactory
15
15
  end
16
16
 
17
17
  def self.type(str)
18
- @type = Types::Strict::Symbol.enum(:credential_provider, :second_factor_provider, :role_assumption_provider)[str]
18
+ @type = Types::Strict::Symbol.enum(:credential_provider, :second_factor_provider, :instance_role_provider)[str]
19
19
  register_if_complete
20
20
  end
21
21
 
@@ -4,11 +4,14 @@ require_relative "../providers/mfa_session_credentials"
4
4
 
5
5
  class AwsAssumeRole::Credentials::Factories::AssumeRole < AwsAssumeRole::Credentials::Factories::AbstractFactory
6
6
  include AwsAssumeRole::Credentials::Factories
7
- type :role_assumption_provider
8
- priority 30
7
+ type :credential_provider
8
+ priority 20
9
9
 
10
10
  def initialize(options)
11
+ logger.debug "AwsAssumeRole::Credentials::Factories::AssumeRole initiated with #{options}"
12
+ return unless options[:profile] || options[:role_arn]
11
13
  if options[:profile]
14
+ logger.debug "AwsAssumeRole: #{options[:profile]} found. Trying with profile"
12
15
  try_with_profile(options)
13
16
  else
14
17
  if options[:use_mfa]
@@ -19,20 +22,16 @@ class AwsAssumeRole::Credentials::Factories::AssumeRole < AwsAssumeRole::Credent
19
22
  end
20
23
 
21
24
  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)
25
+ return unless AwsAssumeRole.shared_config.config_enabled?
26
+ logger.debug "AwsAssumeRole: Shared Config enabled"
27
+ @profile = options[:profile]
28
+ @region = options[:region]
29
+ @credentials = assume_role_with_profile(options)
30
+ @region ||= AwsAssumeRole.shared_config.profile_region(@profile)
29
31
  @role_arn ||= AwsAssumeRole.shared_config.profile_role(@profile)
30
32
  end
31
33
 
32
- def assume_role_with_profile(prof, region)
33
- AwsAssumeRole.shared_config.assume_role_credentials_from_config(
34
- profile: prof,
35
- region: region,
36
- )
34
+ def assume_role_with_profile(options)
35
+ AwsAssumeRole.shared_config.assume_role_credentials_from_config(options)
37
36
  end
38
37
  end
@@ -6,77 +6,83 @@ require_relative "environment"
6
6
  require_relative "repository"
7
7
  require_relative "instance_profile"
8
8
  require_relative "assume_role"
9
- require_relative "shared_keyring"
10
9
  require_relative "shared"
11
10
  require_relative "static"
12
11
 
13
- class AwsAssumeRole::Credentials::Factories::DefaultChainProvider
14
- extend Dry::Initializer::Mixin
12
+ class AwsAssumeRole::Credentials::Factories::DefaultChainProvider < Dry::Struct
13
+ constructor_type :schema
15
14
  include AwsAssumeRole::Credentials::Factories
15
+ include AwsAssumeRole::Logging
16
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 }
17
+ attribute :access_key_id, Dry::Types["strict.string"].optional
18
+ attribute :credentials, Dry::Types["object"].optional
19
+ attribute :secret_access_key, Dry::Types["strict.string"].optional
20
+ attribute :session_token, Dry::Types["strict.string"].optional
21
+ attribute :duration_seconds, Dry::Types["coercible.int"].optional
22
+ attribute :external_id, Dry::Types["strict.string"].optional
23
+ attribute :persist_session, Dry::Types["strict.bool"].default(true)
24
+ attribute :path, Dry::Types["strict.string"].optional
25
+ attribute :profile, Dry::Types["strict.string"].optional
26
+ attribute :profile_name, Dry::Types["strict.string"].optional
27
+ attribute :region, Dry::Types["strict.string"].optional
28
+ attribute :role_arn, Dry::Types["strict.string"].optional
29
+ attribute :role_session_name, Dry::Types["strict.string"].optional
30
+ attribute :serial_number, Dry::Types["strict.string"].optional
31
+ attribute :mfa_serial, Dry::Types["strict.string"].optional
32
+ attribute :use_mfa, Dry::Types["strict.bool"].default(false)
33
+ attribute :no_profile, Dry::Types["strict.bool"].default(false)
34
+ attribute :source_profile, Dry::Types["strict.string"].optional
35
+ attribute :instance_profile_credentials_retries, Dry::Types["strict.int"].default(0)
36
+ attribute :instance_profile_credentials_timeout, Dry::Types["coercible.float"].default(1.0)
35
37
 
36
- def initialize(*options)
37
- if options[0].is_a? Seahorse::Client::Configuration::DefaultResolver
38
- initialize_with_seahorse(options[0])
38
+ def self.new(options)
39
+ if options.respond_to? :resolve
40
+ finalize_instance new_with_seahorse(options)
39
41
  else
40
- super(*options)
42
+ finalize_instance(options)
41
43
  end
42
- @profile_name ||= @profile
43
- @original_profile = @profile
44
+ end
45
+
46
+ def self.finalize_instance(options)
47
+ new_opts = options.to_h
48
+ new_opts[:profile_name] ||= new_opts[:profile]
49
+ new_opts[:original_profile] = new_opts[:profile_name]
50
+ instance = allocate
51
+ instance.send(:initialize, new_opts)
52
+ instance
53
+ end
54
+
55
+ def self.new_with_seahorse(resolver)
56
+ keys = resolver.resolve
57
+ options = keys.map do |k|
58
+ [k, resolver.send(k)]
59
+ end
60
+ finalize_instance(options.to_h)
44
61
  end
45
62
 
46
63
  def resolve(nil_with_role_not_set: false, explicit_default_profile: false)
47
64
  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 &&
65
+ # nil_creds = Aws::Credentials.new(nil, nil, nil)
66
+ return nil if (nil_with_role_not_set &&
50
67
  @role_arn &&
51
68
  @credentials.credentials.session_token.nil?) || @credentials.nil?
52
69
  @credentials
53
70
  end
54
71
 
72
+ def to_h
73
+ to_hash
74
+ end
75
+
55
76
  private
56
77
 
57
78
  def resolve_final_credentials(explicit_default_profile = false)
58
79
  resolve_credentials(:credential_provider, true, explicit_default_profile)
59
80
  return @credentials if @credentials && @credentials.set? && !use_mfa && !role_arn
60
81
  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
82
  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
- )
83
+ resolve_credentials(:instance_role_provider, true, explicit_default_profile)
84
+ return @credentials if @credentials && @credentials.set?
85
+ nil
80
86
  end
81
87
 
82
88
  def resolve_credentials(type, break_if_successful = false, explicit_default_profile = false)
@@ -84,13 +90,16 @@ class AwsAssumeRole::Credentials::Factories::DefaultChainProvider
84
90
  factories_to_try.each do |x|
85
91
  options = to_h
86
92
  options[:credentials] = credentials if credentials && credentials.set?
93
+ logger.debug "About to try credential lookup with #{x}"
87
94
  factory = x.new(options)
88
95
  @region ||= factory.region
89
96
  @profile ||= factory.profile
90
97
  @role_arn ||= factory.role_arn
91
98
  next unless factory.credentials && factory.credentials.set?
99
+ logger.debug "Profile currently #{@profile}"
92
100
  next if explicit_default_profile && (@profile == "default") && (@profile != @original_profile)
93
101
  @credentials ||= factory.credentials
102
+ logger.debug "Got #{@credentials}"
94
103
  break if break_if_successful
95
104
  end
96
105
  end
@@ -1,17 +1,13 @@
1
- require "dry-initializer"
2
- require "dry-types"
3
- require "aws-sdk"
1
+ require_relative "../includes"
4
2
  require_relative "../../logging"
5
3
  require_relative "../../vendored/aws"
6
4
  require_relative "../../../aws_assume_role"
7
5
 
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
6
+ module AwsAssumeRole::Credentials
7
+ module Factories
8
+ Types = Dry::Types.module
9
+ include AwsAssumeRole
10
+ include AwsAssumeRole::Logging
11
+ include AwsAssumeRole::Vendored::Aws
16
12
  end
17
13
  end
@@ -1,7 +1,7 @@
1
1
  require_relative "abstract_factory"
2
2
 
3
3
  class AwsAssumeRole::Credentials::Factories::InstanceProfile < AwsAssumeRole::Credentials::Factories::AbstractFactory
4
- type :role_assumption_provider
4
+ type :instance_role_provider
5
5
  priority 40
6
6
 
7
7
  def initialize(options = {})
@@ -9,7 +9,7 @@ class AwsAssumeRole::Credentials::Factories::Repository
9
9
  FactoryRepositoryType = Types::Hash.schema(
10
10
  credential_provider: SubFactoryRepositoryType,
11
11
  second_factor_provider: SubFactoryRepositoryType,
12
- role_assumption_provider: SubFactoryRepositoryType,
12
+ instance_role_provider: SubFactoryRepositoryType,
13
13
  )
14
14
 
15
15
  def self.factories
@@ -20,7 +20,7 @@ class AwsAssumeRole::Credentials::Factories::Repository
20
20
  @repository ||= FactoryRepositoryType[
21
21
  credential_provider: {},
22
22
  second_factor_provider: {},
23
- role_assumption_provider: {},
23
+ instance_role_provider: {},
24
24
  ]
25
25
  end
26
26
 
@@ -1,14 +1,16 @@
1
1
  require_relative "abstract_factory"
2
+ require_relative "../providers/shared_keyring_credentials"
2
3
 
3
4
  class AwsAssumeRole::Credentials::Factories::Shared < AwsAssumeRole::Credentials::Factories::AbstractFactory
4
5
  type :credential_provider
5
- priority 20
6
+ priority 30
6
7
 
7
8
  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)
9
+ logger.debug "Shared Factory initiated with #{options}"
10
+ @profile = options[:profile]
11
+ @credentials = AwsAssumeRole::Credentials::Providers::SharedKeyringCredentials.new(options)
12
+ @region = @credentials.region
13
+ @role_arn = @credentials.role_arn
12
14
  rescue Aws::Errors::NoSuchProfileError
13
15
  nil
14
16
  end
@@ -0,0 +1,4 @@
1
+ require_relative "../includes"
2
+ module AwsAssumeRole
3
+ module Credentials end
4
+ end
@@ -1,9 +1,7 @@
1
+ require_relative "../includes"
1
2
  require_relative "../../vendored/aws"
2
3
  require_relative "../../ui"
3
4
  require_relative "../../logging"
4
- module AwsAssumeRole
5
- module Credentials
6
- module Providers
7
- end
8
- end
5
+ module AwsAssumeRole::Credentials
6
+ module Providers end
9
7
  end
@@ -1,32 +1,29 @@
1
1
  require_relative "includes"
2
2
  require_relative "../../types"
3
+ require_relative "../../configuration"
3
4
 
4
- class AwsAssumeRole::Credentials::Providers::MfaSessionCredentials
5
+ class AwsAssumeRole::Credentials::Providers::MfaSessionCredentials < Dry::Struct
6
+ constructor_type :schema
5
7
  include AwsAssumeRole::Vendored::Aws::CredentialProvider
6
8
  include AwsAssumeRole::Vendored::Aws::RefreshingCredentials
7
9
  include AwsAssumeRole::Ui
8
10
  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)
11
+
12
+ attribute :permanent_credentials, Dry::Types["object"].optional
13
+ attribute :credentials, Dry::Types["object"].optional
14
+ attribute :expiration, Dry::Types["strict.time"].default(Time.now)
15
+ attribute :first_time, Dry::Types["strict.bool"].default(true)
16
+ attribute :persist_session, Dry::Types["strict.bool"].default(true)
17
+ attribute :duration_seconds, Dry::Types["coercible.int"].default(3600)
18
+ attribute :region, AwsAssumeRole::Types::Region.optional
19
+ attribute :serial_number, AwsAssumeRole::Types::MfaSerial.optional.default("automatic")
20
+
21
+ def initialize(options)
22
+ options.each { |key, value| instance_variable_set("@#{key}", value) }
26
23
  @permanent_credentials ||= credentials
27
24
  @credentials = nil
28
25
  @serial_number = resolve_serial_number(serial_number)
29
- AwsAssumeRole::Vendored::Aws::RefreshingCredentials.instance_method(:initialize).bind(self).call(*options)
26
+ AwsAssumeRole::Vendored::Aws::RefreshingCredentials.instance_method(:initialize).bind(self).call(options)
30
27
  end
31
28
 
32
29
  private
@@ -67,14 +64,15 @@ class AwsAssumeRole::Credentials::Providers::MfaSessionCredentials
67
64
  end
68
65
 
69
66
  def credentials_from_keyring
70
- @credentials_from_keyring ||= AwsAssumeRole::Store::Keyring.fetch @keyring_username
67
+ @credentials_from_keyring ||= AwsAssumeRole::Store::Keyring.fetch keyring_username
71
68
  rescue Aws::Errors::NoSuchProfileError
72
69
  logger.debug "Key not found"
73
70
  @credentials_from_keyring = nil
71
+ return nil
74
72
  end
75
73
 
76
74
  def persist_credentials
77
- AwsAssumeRole::Store::Keyring.save_credentials @keyring_username, @credentials, expiration: @expiration
75
+ AwsAssumeRole::Store::Keyring.save_credentials keyring_username, @credentials, expiration: @expiration
78
76
  end
79
77
 
80
78
  def instance_credentials(credentials)
@@ -84,7 +82,7 @@ class AwsAssumeRole::Credentials::Providers::MfaSessionCredentials
84
82
  end
85
83
 
86
84
  def set_credentials_from_keyring
87
- instance_credentials credentials_from_keyring
85
+ instance_credentials credentials_from_keyring if credentials_from_keyring
88
86
  initialized
89
87
  refresh_using_mfa unless @credentials && !near_expiration?
90
88
  end
@@ -98,5 +96,4 @@ class AwsAssumeRole::Credentials::Providers::MfaSessionCredentials
98
96
  user_name = identity.arn.split("/")[1]
99
97
  "arn:aws:iam::#{identity.account}:mfa/#{user_name}"
100
98
  end
101
- Dry::Types.register_class(self)
102
99
  end
@@ -2,21 +2,38 @@ require_relative "includes"
2
2
  require_relative "../../types"
3
3
 
4
4
  class AwsAssumeRole::Credentials::Providers::SharedKeyringCredentials < ::Aws::SharedCredentials
5
+ include AwsAssumeRole::Logging
6
+ attr_reader :region, :role_arn
7
+
5
8
  def initialize(options = {})
6
- shared_config = AwsAssumeRole.shared_config
9
+ logger.debug "SharedKeyringCredentials initiated with #{options}"
7
10
  @path = options[:path]
8
- @path ||= shared_config.credentials_path
9
- @profile_name = options[:profile_name]
11
+ @path ||= AwsAssumeRole.shared_config.credentials_path
12
+ @profile_name = options[:profile_name] ||= options[:profile]
10
13
  @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
+ @profile_name ||= AwsAssumeRole.shared_config.profile_name
15
+ logger.debug "SharedKeyringCredentials resolved profile name #{@profile_name}"
16
+ config = determine_config(@path, @profile_name)
17
+ @role_arn = config.profile_hash(@profile_name)
18
+ @region = config.profile_region(@profile_name)
19
+ @role_arn = config.profile_role(@profile_name)
20
+ attempted_credential = config.credentials(options)
21
+ return unless attempted_credential && attempted_credential.set?
22
+ @credentials = attempted_credential
23
+ end
24
+
25
+ private
26
+
27
+ def determine_config(path, profile_name)
28
+ if path && path == AwsAssumeRole.shared_config.credentials_path
29
+ logger.debug "SharedKeyringCredentials found shared credential path"
30
+ AwsAssumeRole.shared_config
14
31
  else
15
- config = AwsAssumeRole::Store::SharedConfig.new(
16
- credentials_path: @path,
17
- profile_name: @profile_name,
32
+ logger.debug "SharedKeyringCredentials found custom credential path"
33
+ AwsAssumeRole::Store::SharedConfigWithKeyring.new(
34
+ credentials_path: path,
35
+ profile_name: profile_name,
18
36
  )
19
- @credentials = config.credentials(profile: @profile_name)
20
37
  end
21
38
  end
22
39
  end
@@ -1,13 +1,14 @@
1
1
  require "i18n"
2
- require "keyring"
2
+ require "active_support/json"
3
3
  require "active_support/core_ext/object/blank"
4
4
  require "active_support/core_ext/string/inflections"
5
+ require "active_support/core_ext/hash/compact"
5
6
  require "active_support/core_ext/hash/keys"
6
- require "active_support/core_ext/object/json"
7
+ require "active_support/core_ext/hash/slice"
7
8
  require "aws-sdk"
8
9
  require "aws-sdk-core/ini_parser"
9
10
  require "dry-configurable"
10
- require "dry-initializer"
11
+ require "dry-struct"
11
12
  require "dry-validation"
12
13
  require "dry-types"
13
14
  require "English"
@@ -15,8 +16,13 @@ require "gli"
15
16
  require "highline"
16
17
  require "inifile"
17
18
  require "json"
19
+ require "keyring"
20
+ require "launchy"
18
21
  require "logger"
22
+ require "open-uri"
19
23
  require "pastel"
24
+ require "securerandom"
25
+ require "set"
20
26
  require "thread"
21
27
  require "time"
22
28
 
@@ -1,29 +1,30 @@
1
1
  require_relative "includes"
2
2
  require_relative "logging"
3
3
 
4
- class AwsAssumeRole::ProfileConfiguration
5
- extend Dry::Initializer
4
+ class AwsAssumeRole::ProfileConfiguration < Dry::Struct
5
+ constructor_type :schema
6
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 }
7
+ attribute :access_key_id, Dry::Types["strict.string"].optional
8
+ attribute :credentials, Dry::Types["object"].optional
9
+ attribute :secret_access_key, Dry::Types["strict.string"].optional
10
+ attribute :session_token, Dry::Types["strict.string"].optional
11
+ attribute :duration_seconds, Dry::Types["coercible.int"].optional
12
+ attribute :external_id, Dry::Types["strict.string"].optional
13
+ attribute :path, Dry::Types["strict.string"].optional
14
+ attribute :persist_session, Dry::Types["strict.bool"].optional.default(true)
15
+ attribute :profile, Dry::Types["strict.string"].optional
16
+ attribute :region, Dry::Types["strict.string"].optional
17
+ attribute :role_arn, Dry::Types["strict.string"].optional
18
+ attribute :role_session_name, Dry::Types["strict.string"].optional
19
+ attribute :serial_number, Dry::Types["strict.string"].optional
20
+ attribute :mfa_serial, Dry::Types["strict.string"].optional
21
+ attribute :use_mfa, Dry::Types["strict.bool"].optional.default(false)
22
+ attribute :no_profile, Dry::Types["strict.bool"].optional.default(false)
23
+ attribute :shell_type, Dry::Types["strict.string"].optional
24
+ attribute :source_profile, Dry::Types["strict.string"].optional
25
+ attribute :args, Dry::Types["strict.array"].optional.default([])
26
+ attribute :instance_profile_credentials_retries, Dry::Types["strict.int"].default(0)
27
+ attribute :instance_profile_credentials_timeout, Dry::Types["coercible.float"].default(1.0)
27
28
 
28
29
  attr_writer :credentials
29
30
 
@@ -64,8 +65,6 @@ class AwsAssumeRole::ProfileConfiguration
64
65
  end
65
66
 
66
67
  def to_h
67
- instance_values.delete("__options__").symbolize_keys
68
+ to_hash
68
69
  end
69
-
70
- Dry::Types.register_class(self)
71
70
  end
@@ -1,18 +1,17 @@
1
1
  require_relative "includes"
2
2
  require_relative "logging"
3
3
 
4
- class AwsAssumeRole::Runner
4
+ class AwsAssumeRole::Runner < Dry::Struct
5
5
  include AwsAssumeRole::Logging
6
- extend Dry::Initializer
6
+ constructor_type :schema
7
+ attribute :command, Dry::Types["coercible.array"].member(Dry::Types["strict.string"]).default([])
8
+ attribute :exit_on_error, Dry::Types["strict.bool"].default(true)
9
+ attribute :expected_exit_code, Dry::Types["strict.int"].default(0)
10
+ attribute :environment, Dry::Types["strict.hash"].default({})
11
+ attribute :credentials, Dry::Types["object"].optional
7
12
 
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)
13
+ def initialize(options)
14
+ super(options)
16
15
  command_to_exec = command.join(" ")
17
16
  process_credentials unless credentials.blank?
18
17
  system environment, command_to_exec
@@ -1,14 +1,4 @@
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"
1
+ require_relative "../includes"
12
2
 
13
3
  module AwsAssumeRole
14
4
  module Store
@@ -38,8 +38,7 @@ module AwsAssumeRole::Store::Keyring
38
38
  def fetch(id, backend: nil)
39
39
  logger.debug "Fetching #{id} from keyring"
40
40
  fetched = keyring(backend).get_password(KEYRING_KEY, id)
41
- return nil if fetched == "null" || fetched.nil?
42
- raise Aws::Errors::NoSuchProfileError unless fetched
41
+ raise Aws::Errors::NoSuchProfileError if fetched == "null" || fetched.nil? || !fetched
43
42
  JSON.parse(fetched, symbolize_names: true)
44
43
  end
45
44
 
@@ -10,14 +10,51 @@ class AwsAssumeRole::Store::SharedConfigWithKeyring < AwsAssumeRole::Vendored::A
10
10
 
11
11
  attr_reader :parsed_config
12
12
 
13
+ # @param [Hash] options
14
+ # @option options [String] :credentials_path Path to the shared credentials
15
+ # file. Defaults to "#{Dir.home}/.aws/credentials".
16
+ # @option options [String] :config_path Path to the shared config file.
17
+ # Defaults to "#{Dir.home}/.aws/config".
18
+ # @option options [String] :profile_name The credential/config profile name
19
+ # to use. If not specified, will check `ENV['AWS_PROFILE']` before using
20
+ # the fixed default value of 'default'.
21
+ # @option options [Boolean] :config_enabled If true, loads the shared config
22
+ # file and enables new config values outside of the old shared credential
23
+ # spec.
13
24
  def initialize(options = {})
14
- super(options)
15
- @config_enabled = true
16
- @config_path = determine_config_path
17
- load_config_file
25
+ @profile_name = determine_profile(options)
26
+ @config_enabled = options[:config_enabled]
27
+ @credentials_path = options[:credentials_path] ||
28
+ determine_credentials_path
29
+ @parsed_credentials = {}
30
+ load_credentials_file if loadable?(@credentials_path)
31
+ return unless @config_enabled
32
+ @config_path = options[:config_path] || determine_config_path
33
+ load_config_file if loadable?(@config_path)
34
+ end
35
+
36
+ # @api private
37
+ def fresh(options = {})
38
+ @configuration = nil
39
+ @semaphore = nil
40
+ @assume_role_shared_config = nil
41
+ @profile_name = nil
42
+ @credentials_path = nil
43
+ @config_path = nil
44
+ @parsed_credentials = {}
45
+ @parsed_config = nil
46
+ @config_enabled = options[:config_enabled] ? true : false
47
+ @profile_name = determine_profile(options)
48
+ @credentials_path = options[:credentials_path] ||
49
+ determine_credentials_path
50
+ load_credentials_file if loadable?(@credentials_path)
51
+ return unless @config_enabled
52
+ @config_path = options[:config_path] || determine_config_path
53
+ load_config_file if loadable?(@config_path)
18
54
  end
19
55
 
20
56
  def credentials(opts = {})
57
+ logger.debug "SharedConfigWithKeyring asked for credentials with opts #{opts}"
21
58
  p = opts[:profile] || @profile_name
22
59
  validate_profile_exists(p) if credentials_present?
23
60
  credentials_from_keyring(p, opts) || credentials_from_shared(p, opts) || credentials_from_config(p, opts)
@@ -59,20 +96,15 @@ class AwsAssumeRole::Store::SharedConfigWithKeyring < AwsAssumeRole::Vendored::A
59
96
  end
60
97
 
61
98
  def profile_region(profile_name)
62
- prof_cfg = @parsed_config[profile_key(profile_name)]
63
- resolve_region(@parsed_config, prof_cfg)
99
+ resolve_profile_parameter(profile_name, "region")
64
100
  end
65
101
 
66
102
  def profile_role(profile_name)
67
- prof_cfg = @parsed_config[profile_key(profile_name)]
68
- resolve_arn(@parsed_config, prof_cfg)
103
+ resolve_profile_parameter(profile_name, "role_arn")
69
104
  end
70
105
 
71
- def determine_profile(options)
72
- ret = options[:profile_name]
73
- ret ||= ENV["AWS_PROFILE"]
74
- ret ||= "default"
75
- ret
106
+ def profile_hash(profile_name)
107
+ {} || @parsed_config[profile_key(profile_name)]
76
108
  end
77
109
 
78
110
  private
@@ -86,21 +118,32 @@ class AwsAssumeRole::Store::SharedConfigWithKeyring < AwsAssumeRole::Vendored::A
86
118
  end
87
119
  end
88
120
 
89
- def resolve_region(cfg, prof_cfg)
121
+ def resolve_profile_parameter(profile_name, param)
122
+ return unless @parsed_config
123
+ prof_cfg = @parsed_config[profile_key(profile_name)]
124
+ resolve_parameter(param, @parsed_config, prof_cfg)
125
+ end
126
+
127
+ def resolve_parameter(param, cfg, prof_cfg)
90
128
  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")
129
+ return prof_cfg[param] if prof_cfg.key? param
130
+ source_profile = prof_cfg["source_profile"]
131
+ return unless source_profile
132
+ source_cfg = cfg[source_profile]
133
+ return unless source_cfg
134
+ cfg[prof_cfg["source_profile"]][param] if source_cfg.key?(param)
135
+ end
136
+
137
+ def resolve_region(cfg, prof_cfg)
138
+ resolve_parameter("region", cfg, prof_cfg)
94
139
  end
95
140
 
96
141
  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")
142
+ resolve_parameter("role_arn", cfg, prof_cfg)
101
143
  end
102
144
 
103
145
  def assume_role_from_profile(cfg, profile, opts)
146
+ logger.debug "Entering assume_role_from_profile with #{cfg}, #{profile}, #{opts}"
104
147
  prof_cfg = cfg[profile]
105
148
  return unless cfg && prof_cfg
106
149
  opts[:source_profile] ||= prof_cfg["source_profile"]
@@ -133,7 +176,7 @@ class AwsAssumeRole::Store::SharedConfigWithKeyring < AwsAssumeRole::Vendored::A
133
176
  def mfa_session(cfg, profile, opts)
134
177
  prof_cfg = cfg[profile]
135
178
  return unless cfg && prof_cfg
136
- opts[:serial_number] ||= prof_cfg["mfa_serial"]
179
+ opts[:serial_number] ||= opts[:mfa_serial] || prof_cfg["mfa_serial"]
137
180
  opts[:source_profile] ||= prof_cfg["source_profile"]
138
181
  opts[:region] ||= profile_region(profile)
139
182
  return unless opts[:serial_number]
@@ -141,11 +184,26 @@ class AwsAssumeRole::Store::SharedConfigWithKeyring < AwsAssumeRole::Vendored::A
141
184
  AwsAssumeRole::Credentials::Providers::MfaSessionCredentials.new(opts)
142
185
  end
143
186
 
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)
187
+ def credentials_from_keyring(profile, opts)
188
+ logger.debug "Entering credentials_from_keyring"
189
+ return unless @parsed_config
190
+ logger.debug "credentials_from_keyring: @parsed_config found"
191
+ prof_cfg = @parsed_config[profile]
192
+ return unless prof_cfg
193
+ logger.debug "credentials_from_keyring: prof_cfg found"
194
+ opts[:serial_number] ||= opts[:mfa_serial] || prof_cfg[:mfa_serial] || prof_cfg[:serial_number]
195
+ if opts[:serial_number]
196
+ logger.debug "credentials_from_keyring detected mfa requirement"
197
+ mfa_session(@parsed_config, profile, opts)
198
+ else
199
+ logger.debug "Attempt to fetch #{profile} from keyring"
200
+ keyring_creds = Keyring.fetch(profile)
201
+ return unless keyring_creds
202
+ creds = Serialization.credentials_from_hash Keyring.fetch(profile)
203
+ creds if credentials_complete(creds)
204
+ end
205
+ rescue Aws::Errors::NoSourceProfileError, Aws::Errors::NoSuchProfileError
206
+ nil
149
207
  end
150
208
 
151
209
  def semaphore
@@ -170,6 +228,6 @@ module AwsAssumeRole
170
228
 
171
229
  def shared_config
172
230
  enabled = ENV["AWS_SDK_CONFIG_OPT_OUT"] ? false : true
173
- @assuome_role_shared_config ||= ::AwsAssumeRole::Store::SharedConfigWithKeyring.new(config_enabled: enabled)
231
+ @assume_role_shared_config ||= ::AwsAssumeRole::Store::SharedConfigWithKeyring.new(config_enabled: enabled)
174
232
  end
175
233
  end
@@ -1,5 +1,4 @@
1
- require "dry-types"
2
-
1
+ require_relative "includes"
3
2
  module AwsAssumeRole
4
3
  module Types
5
4
  Dry = Dry::Types.module
@@ -1,5 +1,4 @@
1
1
  require_relative "includes"
2
- require "set"
3
2
 
4
3
  module AwsAssumeRole::Vendored::Aws
5
4
  # An auto-refreshing credential provider that works by assuming
@@ -1,4 +1,4 @@
1
- require "aws-sdk"
1
+ require_relative "../../includes"
2
2
 
3
3
  module AwsAssumeRole
4
4
  module Vendored
@@ -1,5 +1,3 @@
1
- require "thread"
2
-
3
1
  module AwsAssumeRole::Vendored::Aws
4
2
  # Base class used credential classes that can be refreshed. This
5
3
  # provides basic refresh logic in a thread-safe manor. Classes mixing in
@@ -2,6 +2,7 @@ require_relative "includes"
2
2
  module AwsAssumeRole::Vendored::Aws
3
3
  # @api private
4
4
  class SharedConfig
5
+ include AwsAssumeRole::Logging
5
6
  # @return [String]
6
7
  attr_reader :credentials_path
7
8
 
@@ -102,9 +103,11 @@ module AwsAssumeRole::Vendored::Aws
102
103
  # Will always attempt first to assume a role from the shared credentials
103
104
  # file, if present.
104
105
  def assume_role_credentials_from_config(opts = {})
106
+ logger.debug "Entered assume_role_credentials_from_config with #{opts}"
105
107
  p = opts.delete(:profile) || @profile_name
106
108
  credentials = assume_role_from_profile(@parsed_credentials, p, opts)
107
109
  if @parsed_config
110
+ logger.debug "Parsed config loaded, testing"
108
111
  credentials ||= assume_role_from_profile(@parsed_config, p, opts)
109
112
  end
110
113
  credentials
@@ -140,7 +143,7 @@ module AwsAssumeRole::Vendored::Aws
140
143
  opts[:external_id] ||= prof_cfg["external_id"]
141
144
  opts[:serial_number] ||= prof_cfg["mfa_serial"]
142
145
  opts[:profile] = opts.delete(:source_profile)
143
- AwsAssumeRole::Vendored::Aws::AssumeRoleCredentials.new(opts)
146
+ AssumeRoleCredentials.new(opts)
144
147
  else
145
148
  raise ::Aws::Errors::NoSourceProfileError, "Profile #{profile} has a role_arn, and source_profile, but the"\
146
149
  " source_profile does not have credentials."
@@ -1,3 +1,3 @@
1
1
  module AwsAssumeRole
2
- VERSION = "0.1.1".freeze
2
+ VERSION = "0.1.2".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_assume_role
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Topper
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-02-16 00:00:00.000000000 Z
13
+ date: 2017-02-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: '4.0'
21
+ version: '4.2'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: '4.0'
28
+ version: '4.2'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: aws-sdk
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -55,19 +55,19 @@ dependencies:
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0.5'
57
57
  - !ruby/object:Gem::Dependency
58
- name: dry-initializer
58
+ name: dry-struct
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - "~>"
62
62
  - !ruby/object:Gem::Version
63
- version: '1.1'
63
+ version: '0.1'
64
64
  type: :runtime
65
65
  prerelease: false
66
66
  version_requirements: !ruby/object:Gem::Requirement
67
67
  requirements:
68
68
  - - "~>"
69
69
  - !ruby/object:Gem::Version
70
- version: '1.1'
70
+ version: '0.1'
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: dry-types
73
73
  requirement: !ruby/object:Gem::Requirement
@@ -242,6 +242,34 @@ dependencies:
242
242
  - - "~>"
243
243
  - !ruby/object:Gem::Version
244
244
  version: '0.9'
245
+ - !ruby/object:Gem::Dependency
246
+ name: simplecov
247
+ requirement: !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - "~>"
250
+ - !ruby/object:Gem::Version
251
+ version: '0.13'
252
+ type: :development
253
+ prerelease: false
254
+ version_requirements: !ruby/object:Gem::Requirement
255
+ requirements:
256
+ - - "~>"
257
+ - !ruby/object:Gem::Version
258
+ version: '0.13'
259
+ - !ruby/object:Gem::Dependency
260
+ name: webmock
261
+ requirement: !ruby/object:Gem::Requirement
262
+ requirements:
263
+ - - "~>"
264
+ - !ruby/object:Gem::Version
265
+ version: '2.3'
266
+ type: :development
267
+ prerelease: false
268
+ version_requirements: !ruby/object:Gem::Requirement
269
+ requirements:
270
+ - - "~>"
271
+ - !ruby/object:Gem::Version
272
+ version: '2.3'
245
273
  - !ruby/object:Gem::Dependency
246
274
  name: gir_ffi-gnome_keyring
247
275
  requirement: !ruby/object:Gem::Requirement
@@ -275,6 +303,8 @@ extra_rdoc_files: []
275
303
  files:
276
304
  - ".gitignore"
277
305
  - ".rubocop.yml"
306
+ - ".ruby-version"
307
+ - ".simplecov"
278
308
  - ".travis.yml"
279
309
  - Gemfile
280
310
  - LICENSE.md
@@ -305,6 +335,7 @@ files:
305
335
  - lib/aws_assume_role/cli/commands/migrate.rb
306
336
  - lib/aws_assume_role/cli/commands/run.rb
307
337
  - lib/aws_assume_role/cli/commands/test.rb
338
+ - lib/aws_assume_role/cli/includes.rb
308
339
  - lib/aws_assume_role/configuration.rb
309
340
  - lib/aws_assume_role/core_ext/aws-sdk/credential_provider_chain.rb
310
341
  - lib/aws_assume_role/core_ext/aws-sdk/includes.rb
@@ -317,8 +348,8 @@ files:
317
348
  - lib/aws_assume_role/credentials/factories/instance_profile.rb
318
349
  - lib/aws_assume_role/credentials/factories/repository.rb
319
350
  - lib/aws_assume_role/credentials/factories/shared.rb
320
- - lib/aws_assume_role/credentials/factories/shared_keyring.rb
321
351
  - lib/aws_assume_role/credentials/factories/static.rb
352
+ - lib/aws_assume_role/credentials/includes.rb
322
353
  - lib/aws_assume_role/credentials/providers/assume_role_credentials.rb
323
354
  - lib/aws_assume_role/credentials/providers/includes.rb
324
355
  - lib/aws_assume_role/credentials/providers/mfa_session_credentials.rb
@@ -360,7 +391,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
360
391
  version: '0'
361
392
  requirements: []
362
393
  rubyforge_project:
363
- rubygems_version: 2.5.1
394
+ rubygems_version: 2.4.5
364
395
  signing_key:
365
396
  specification_version: 4
366
397
  summary: Manage AWS STS credentials with MFA
@@ -1,16 +0,0 @@
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