aws_assume_role 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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