├── .circleci ├── config.yml └── setup-rubygems.sh ├── .gitignore ├── .rspec ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── awssume.gemspec ├── bin ├── console └── setup ├── exe └── awssume ├── lib ├── awssume.rb └── awssume │ ├── adapter │ └── aws_client.rb │ ├── command_decorator.rb │ ├── configuration.rb │ └── version.rb └── spec ├── awssume ├── adapter │ └── aws_client_spec.rb ├── command_decorator_spec.rb └── configuration_spec.rb ├── awssume_spec.rb └── spec_helper.rb /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.0 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/ruby:2.1 6 | steps: 7 | - checkout 8 | - run: 9 | name: Install Dependencies 10 | command: | 11 | gem install bundler --no-rdoc --no-ri -v 1.11.2 12 | bin/setup 13 | - run: 14 | name: Run Tests 15 | command: bundle exec rake spec 16 | -------------------------------------------------------------------------------- /.circleci/setup-rubygems.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | mkdir ~/.gem 4 | echo -e "---\r\n:rubygems_api_key: $RUBYGEMS_API_KEY" > ~/.gem/credentials 5 | chmod 0600 /home/circleci/.gem/credentials 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | /vendor/ 11 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in awssume.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 reppard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Awssume 2 | 3 | [![Circle CI](https://circleci.com/gh/manheim/awssume.svg?style=svg)](https://circleci.com/gh/manheim/awssume) 4 | 5 | Assume a role, do a thing. 6 | 7 | This is a gem for assuming an AWS IAM role and using the returned temporary 8 | credentials to do something such as run a deploy script or execute an aws cli 9 | command. This gem was created because of the need to assume a role using 10 | an instance profile on an EC2 instance and use the resulting credentials to 11 | do some work. This functionality doesn't currently exist in some often used 12 | community tools. 13 | 14 | References: 15 | [AWS Cli Issue](https://github.com/aws/aws-cli/issues/1390) 16 | [Terraform Issue](https://github.com/hashicorp/terraform/issues/1275) 17 | 18 | ## Installation 19 | 20 | Add this line to your application's Gemfile: 21 | 22 | ```ruby 23 | gem 'awssume' 24 | ``` 25 | 26 | And then execute: 27 | 28 | $ bundle 29 | 30 | Or install it yourself as: 31 | 32 | $ gem install awssume 33 | 34 | ## Usage 35 | 36 | This gem has the potential to be used as a library in a project using Ruby. 37 | After a few things are implemented(such as a global configuration block) usage 38 | instructions for using as a library will be added. 39 | 40 | Currently the focus has been to use this gem as a command line tool. 41 | 42 | You can configure env vars to authenticate with AWS: 43 | 44 | ``` 45 | $ export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE 46 | $ export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY 47 | $ export AWS_DEFAULT_REGION=us-west-2 48 | ``` 49 | 50 | If AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY aren't set then other 51 | authentication options are checked (such as instance profiles). This is 52 | functionality provided by the aws-sdk. 53 | 54 | ``` 55 | $ AWS_ROLE_ARN=arn::aws::iam::123456789012:role/RoletoAssume \ 56 | awssume 57 | ``` 58 | ``` 59 | $ AWS_ROLE_ARN=arn::aws::iam::123456789012:role/RoletoAssume \ 60 | awssume bundle exec rake component:deploy 61 | ``` 62 | ``` 63 | $ AWS_ROLE_ARN=arn::aws::iam::123456789012:role/RoletoAssume \ 64 | awssume aws iam list-roles 65 | ``` 66 | 67 | There are scenarios where you might want to [use an external id][aws_ext_id] 68 | in a condition on your assume role policy. For such cases, the gem will look 69 | for the ``AWS_ROLE_EXTERNAL_ID`` variable in your environment. If this variable 70 | is set the value will be sent along in the STS Assume Role request. 71 | 72 | ``` 73 | $ AWS_ROLE_ARN=arn::aws::iam::123456789012:role/RoletoAssume \ 74 | AWS_ROLE_EXTERNAL_ID=12345 \ 75 | awssume aws iam list-roles 76 | ``` 77 | 78 | [aws_ext_id]: http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html 79 | 80 | It's also possible to request credentials that 81 | [last longer than the default of one hour](https://aws.amazon.com/about-aws/whats-new/2018/03/longer-role-sessions/) 82 | if the role you're assuming is configured to support them (``MaxSessionDuration`` 83 | greater than 3600 seconds). Here's an example of assuming 12-hour (43200 second; the maximum) 84 | credentials for a _really_ long-running command: 85 | 86 | ``` 87 | $ AWS_ROLE_ARN=arn::aws::iam::123456789012:role/RoletoAssume \ 88 | AWS_ROLE_DURATION_SECONDS=43200 \ 89 | awssume really-long-running-command 90 | ``` 91 | 92 | ## Development 93 | 94 | After checking out the repo, run `bin/setup` to install dependencies. Then, run 95 | `rake spec` to run the tests. You can also run `bin/console` for an interactive 96 | prompt that will allow you to experiment. 97 | 98 | To install this gem onto your local machine, run `bundle exec rake install`. 99 | To release a new version, update the version number in `version.rb`, and then 100 | run `bundle exec rake release`, which will create a git tag for the version, 101 | push git commits and tags, and push the `.gem` file to 102 | [rubygems.org](https://rubygems.org). 103 | 104 | ## Contributing 105 | 106 | Bug reports and pull requests are welcome on 107 | GitHub at https://github.com/Manheim/awssume. 108 | 109 | 110 | ## License 111 | 112 | The gem is available as open source under the terms of the 113 | [MIT License](http://opensource.org/licenses/MIT). 114 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => [:help] 7 | 8 | desc "Display the list of available rake tasks" 9 | task :help do 10 | system("rake -T") 11 | end 12 | -------------------------------------------------------------------------------- /awssume.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'awssume/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'awssume' 8 | spec.version = Awssume::VERSION 9 | spec.authors = ['reppard'] 10 | spec.email = ['reppardwalker@gmail.com'] 11 | 12 | spec.summary = 'Assume a role, do a thing.' 13 | spec.description = [ 14 | 'This is a gem for assuming an AWS IAM role and using the returned', 15 | 'temporary credentials to do something such as run a deploy script', 16 | 'or execute an aws cli command.' 17 | ].join(' ') 18 | spec.homepage = 'https://github.com/Manheim/awssume' 19 | spec.license = 'MIT' 20 | 21 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 22 | spec.bindir = 'exe' 23 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 24 | spec.require_paths = ['lib'] 25 | 26 | spec.add_development_dependency 'rake', '~> 10.0' 27 | spec.add_development_dependency 'rspec' 28 | 29 | spec.add_runtime_dependency 'aws-sdk-core' 30 | end 31 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "awssume" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | 5 | bundle install 6 | 7 | # Do any other automated setup that you need to do here 8 | -------------------------------------------------------------------------------- /exe/awssume: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 4 | require 'awssume' 5 | Awssume.run 6 | -------------------------------------------------------------------------------- /lib/awssume.rb: -------------------------------------------------------------------------------- 1 | require 'aws-sdk-core' 2 | require 'awssume/version' 3 | require 'awssume/command_decorator' 4 | require 'awssume/configuration' 5 | require 'awssume/adapter/aws_client' 6 | 7 | module Awssume 8 | def self.run 9 | config = Awssume::Configuration.new 10 | adapter = Awssume::Adapter::AwsClient.new( 11 | region: config.region, 12 | role_arn: config.role_arn, 13 | role_session_name: config.role_session_name, 14 | external_id: config.external_id, 15 | duration_seconds: config.duration_seconds, 16 | ) 17 | aws_env = { 18 | 'AWS_REGION' => config.region, 19 | 'AWS_DEFAULT_REGION' => config.region 20 | } 21 | creds_hash = adapter.assume 22 | fmt_cmd = Awssume::CommandDecorator.format_cmd(ARGV[0..-1], creds_hash) 23 | 24 | handle_exit { system(aws_env, fmt_cmd) } 25 | end 26 | 27 | def self.handle_exit(&block) 28 | block.call ? true : exit(1) 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/awssume/adapter/aws_client.rb: -------------------------------------------------------------------------------- 1 | require 'aws-sdk-core' 2 | 3 | module Awssume 4 | module Adapter 5 | # This is aws sts client wrapper class 6 | class AwsClient 7 | attr_reader :config 8 | 9 | def initialize(config) 10 | @config = config 11 | end 12 | 13 | def assume 14 | sts_client.assume_role(assume_role_params).credentials.to_h 15 | end 16 | 17 | def role_session_name 18 | config[:role_session_name] 19 | end 20 | 21 | private 22 | 23 | def assume_role_params 24 | p = { 25 | role_arn: config[:role_arn], 26 | role_session_name: role_session_name, 27 | external_id: config[:external_id], 28 | duration_seconds: config[:duration_seconds], 29 | } 30 | 31 | p.delete(:external_id) unless p[:external_id] 32 | p.delete(:duration_seconds) \ 33 | if p[:duration_seconds].nil? || p[:duration_seconds] == 0 34 | 35 | p 36 | end 37 | 38 | def sts_client 39 | Aws::STS::Client.new(region: config[:region]) 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/awssume/command_decorator.rb: -------------------------------------------------------------------------------- 1 | module Awssume 2 | class CommandDecorator 3 | class << self 4 | def generate_var_string(var_hash) 5 | var_hash.collect { |k,v| "AWS_#{k.upcase}='#{v}'" }.sort.join(' ') 6 | end 7 | 8 | def format_cmd(cmd, var_hash) 9 | cmd = cmd.join(' ') if cmd.kind_of?(Array) 10 | 11 | "#{generate_var_string(var_hash)} #{cmd}" 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/awssume/configuration.rb: -------------------------------------------------------------------------------- 1 | module Awssume 2 | # A class for managing the properties needed for assuming a role 3 | class Configuration 4 | def self.default_session_name 5 | "AwssumedSession#{Time.new.to_i}" 6 | end 7 | 8 | # Defaults must have a value: a value passed in or a hardcoded default 9 | # The utility will exit with an error if a value is missing for a default 10 | def self.defaults 11 | { 12 | region: ENV['AWS_REGION'] || ENV['AWS_DEFAULT_REGION'], 13 | role_arn: ENV['AWS_ROLE_ARN'], 14 | role_session_name: ENV['AWS_ROLE_SESSION_NAME'] || default_session_name, 15 | } 16 | end 17 | 18 | # Options are not required to have a value 19 | # The utility will function without issue if an optional value is missing 20 | def self.options 21 | { 22 | external_id: ENV['AWS_ROLE_EXTERNAL_ID'], 23 | duration_seconds: ENV['AWS_ROLE_DURATION_SECONDS'].to_i 24 | } 25 | end 26 | 27 | def self.attrs 28 | self.defaults.merge(self.options) 29 | end 30 | 31 | attr_accessor(*attrs.keys) 32 | 33 | def initialize(opts = {}) 34 | attrs.each do |k, _| 35 | attr_val = validate_attrs(attrs.merge(opts), k) 36 | instance_variable_set("@#{k}", attr_val) 37 | end 38 | end 39 | 40 | private 41 | 42 | def is_optional(attr_key) 43 | self.class.options.keys.include?(attr_key) 44 | end 45 | 46 | def validate_attrs(attrs, attr_key) 47 | throwout_nils(attrs).fetch(attr_key) do 48 | unless is_optional(attr_key) 49 | raise ArgumentError, missing_attr_error_msg(attr_key) 50 | end 51 | end 52 | end 53 | 54 | def missing_attr_error_msg(key) 55 | [ 56 | "Missing '#{key}'", 57 | 'Args should be passed in or set in the env:', 58 | "AWS_#{key.upcase}=value awssume" 59 | ].join("\n") 60 | end 61 | 62 | def throwout_nils(attrs) 63 | attrs.reject { |_, v| v.nil? } 64 | end 65 | 66 | def attrs 67 | self.class.attrs 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/awssume/version.rb: -------------------------------------------------------------------------------- 1 | module Awssume 2 | VERSION = "1.0.1" 3 | end 4 | -------------------------------------------------------------------------------- /spec/awssume/adapter/aws_client_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Awssume::Adapter::AwsClient do 4 | let(:assume_role_response) do 5 | OpenStruct.new( 6 | :credentials => OpenStruct.new( 7 | :access_key_id => 'ABCDEFGHIJKLMNOPQRST', 8 | :secret_access_key => 'XXXXXXXXXXXXXXXXXXXX', 9 | :session_token => 'SUUUUUUUUPERLONGTOKEN', 10 | :expiration => Time.new('2016-03-28 21:27:29 UTC') 11 | ), 12 | :assumed_role_user => OpenStruct.new( 13 | :assumed_role_id => 'AXXXXXXXXXXXXXXXXXXXX:test', 14 | :arn => 'arn:aws:sts::123456789012:assumed-role/aRole/test' 15 | ) 16 | ) 17 | end 18 | 19 | let(:sts_stub) do 20 | sts = Aws::STS::Client.new(stub_responses: true) 21 | sts.stub_responses(:assume_role, assume_role_response) 22 | sts 23 | end 24 | 25 | let(:config_hash) do 26 | { 27 | region: 'us-east-1', 28 | role_arn: 'arn:aws:iam::123456789012:role/aRole', 29 | role_session_name: 'test-deploy' 30 | } 31 | end 32 | 33 | let(:adapter) { Awssume::Adapter::AwsClient.new(config_hash) } 34 | 35 | before(stub_sts: true) do 36 | allow(adapter).to receive(:sts_client).and_return(sts_stub) 37 | allow(sts_stub).to receive(:assume_role).and_return(assume_role_response) 38 | end 39 | 40 | describe '#assume', stub_sts: true do 41 | it 'should call assume_role with proper params' do 42 | expect(sts_stub).to receive(:assume_role).with( 43 | role_arn: 'arn:aws:iam::123456789012:role/aRole', 44 | role_session_name: 'test-deploy' 45 | ) 46 | 47 | adapter.assume 48 | end 49 | 50 | context 'with external id set' do 51 | let(:adapter) do 52 | c = config_hash.merge({external_id: '12345abc'}) 53 | Awssume::Adapter::AwsClient.new(c) 54 | end 55 | 56 | it 'should call assume_role with external id included' do 57 | expect(sts_stub).to receive(:assume_role).with( 58 | role_arn: 'arn:aws:iam::123456789012:role/aRole', 59 | role_session_name: 'test-deploy', 60 | external_id: '12345abc' 61 | ) 62 | 63 | adapter.assume 64 | end 65 | end 66 | 67 | context 'with duration_seconds set' do 68 | let(:adapter) do 69 | c = config_hash.merge({duration_seconds: 43200}) 70 | Awssume::Adapter::AwsClient.new(c) 71 | end 72 | 73 | it 'should call assume_role with duration_seconds included' do 74 | expect(sts_stub).to receive(:assume_role).with( 75 | role_arn: 'arn:aws:iam::123456789012:role/aRole', 76 | role_session_name: 'test-deploy', 77 | duration_seconds: 43200 78 | ) 79 | 80 | adapter.assume 81 | end 82 | end 83 | 84 | context 'with duration_seconds unset' do 85 | let(:adapter) do 86 | c = config_hash.merge({duration_seconds: 0}) 87 | Awssume::Adapter::AwsClient.new(c) 88 | end 89 | 90 | it 'should call assume_role with duration_seconds included' do 91 | expect(sts_stub).to receive(:assume_role).with( 92 | role_arn: 'arn:aws:iam::123456789012:role/aRole', 93 | role_session_name: 'test-deploy' 94 | ) 95 | 96 | adapter.assume 97 | end 98 | end 99 | 100 | context 'successful response' do 101 | subject(:response) { adapter.assume } 102 | 103 | it 'should have access_key_id' do 104 | expect(response[:access_key_id]).to eq('ABCDEFGHIJKLMNOPQRST') 105 | end 106 | 107 | it 'should have secret_access_key' do 108 | expect(response[:secret_access_key]).to eq('XXXXXXXXXXXXXXXXXXXX') 109 | end 110 | 111 | it 'should have session_token' do 112 | expect(response[:session_token]).to eq('SUUUUUUUUPERLONGTOKEN') 113 | end 114 | end 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /spec/awssume/command_decorator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Awssume::CommandDecorator do 4 | let(:var_hash) { { secret_key: '2', access_id: '1', token: '3' } } 5 | 6 | describe '#format_cmd' do 7 | it 'should concatenate a formatted command string' do 8 | cmd = 'command_to_execute' 9 | expected = [ 10 | "AWS_ACCESS_ID='1'", "AWS_SECRET_KEY='2'", "AWS_TOKEN='3'", cmd 11 | ].join(' ') 12 | command_string = Awssume::CommandDecorator.format_cmd(cmd, var_hash) 13 | 14 | expect(command_string).to eq(expected) 15 | end 16 | 17 | context 'command as an array' do 18 | it 'should concatenate a formatted command string' do 19 | cmd = ['command', 'to', 'execute'] 20 | expected = [ 21 | "AWS_ACCESS_ID='1'", "AWS_SECRET_KEY='2'", 22 | "AWS_TOKEN='3'", 'command to execute' 23 | ].join(' ') 24 | command_string = Awssume::CommandDecorator.format_cmd(cmd, var_hash) 25 | 26 | expect(command_string).to eq(expected) 27 | end 28 | end 29 | end 30 | 31 | describe '#generate_var_string' do 32 | it 'should create a string of env vars from a hash' do 33 | var_string = Awssume::CommandDecorator.generate_var_string(var_hash) 34 | 35 | expect(var_string).to eq( 36 | "AWS_ACCESS_ID='1' AWS_SECRET_KEY='2' AWS_TOKEN='3'" 37 | ) 38 | end 39 | 40 | it 'should return a sorted list of vars' do 41 | var_hash = { z: 'z', a: 'a', b: 'b' } 42 | var_string = Awssume::CommandDecorator.generate_var_string(var_hash) 43 | 44 | expect(var_string).to eq("AWS_A='a' AWS_B='b' AWS_Z='z'") 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /spec/awssume/configuration_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Awssume::Configuration do 4 | context '#initialize' do 5 | describe 'missing attributes' do 6 | let(:invalid_args) do 7 | { 8 | role_arn: 'arn:aws:iam::123456789012:user/David', 9 | role_session_name: 'testDeploy' 10 | } 11 | end 12 | 13 | let(:missing_arg) { 'region' } 14 | 15 | it 'raises ArgumentError when attributes are missing' do 16 | expect { Awssume::Configuration.new(invalid_args) } 17 | .to raise_error(ArgumentError) 18 | end 19 | 20 | it 'raises Argument error with missing attribute in message' do 21 | expected_msg = "Missing '#{missing_arg}'\n" 22 | expected_msg += "Args should be passed in or set in the env:\n" 23 | expected_msg += "AWS_#{missing_arg.upcase}=value awssume" 24 | 25 | expect { Awssume::Configuration.new(invalid_args) } 26 | .to raise_error(/#{expected_msg}/) 27 | end 28 | end 29 | 30 | describe 'missing optional attributes' do 31 | let(:valid_args) do 32 | { 33 | region: 'us-east-1', 34 | role_arn: 'arn:aws:iam::123456789012:user/David', 35 | role_session_name: 'testDeploy' 36 | } 37 | end 38 | 39 | it 'does not raise error when optional attributes are missing' do 40 | expect { Awssume::Configuration.new(valid_args) } 41 | .not_to raise_error 42 | end 43 | end 44 | 45 | it 'should provide default session name if none is provided' do 46 | config = Awssume::Configuration.new( 47 | role_arn: 'arn:aws:iam::123456789012:user/David', 48 | region: 'us-east-1' 49 | ) 50 | 51 | expect(config.role_session_name).to match(/AwssumedSession/) 52 | end 53 | 54 | it 'can receive custom attributes' do 55 | config = Awssume::Configuration.new( 56 | region: 'us-east-1', 57 | role_arn: 'arn:aws:iam::123456789012:user/David', 58 | role_session_name: 'testDeploy' 59 | ) 60 | 61 | expect(config.region).to eq('us-east-1') 62 | expect(config.role_arn).to eq('arn:aws:iam::123456789012:user/David') 63 | expect(config.role_session_name).to eq('testDeploy') 64 | end 65 | 66 | it 'can set attributes with env vars' do 67 | stub_const( 68 | 'ENV', 69 | 'AWS_REGION' => 'us-east-1', 70 | 'AWS_ROLE_ARN' => 'arn:aws:iam::123456789012:user/Gary', 71 | 'AWS_ROLE_SESSION_NAME' => 'testSessionName', 72 | 'AWS_ROLE_EXTERNAL_ID' => '12345abc', 73 | 'AWS_ROLE_DURATION_SECONDS' => '43200', 74 | ) 75 | config = Awssume::Configuration.new 76 | 77 | expect(config.region).to eq('us-east-1') 78 | expect(config.role_arn).to eq('arn:aws:iam::123456789012:user/Gary') 79 | expect(config.role_session_name).to eq('testSessionName') 80 | expect(config.external_id).to eq('12345abc') 81 | expect(config.duration_seconds).to eq(43200) 82 | end 83 | 84 | it 'handles an unset AWS_ROLE_DURATION_SECONDS' do 85 | stub_const( 86 | 'ENV', 87 | 'AWS_REGION' => 'us-east-1', 88 | 'AWS_ROLE_ARN' => 'arn:aws:iam::123456789012:user/Gary', 89 | 'AWS_ROLE_SESSION_NAME' => 'testSessionName', 90 | 'AWS_ROLE_EXTERNAL_ID' => '12345abc', 91 | ) 92 | config = Awssume::Configuration.new 93 | 94 | expect(config.region).to eq('us-east-1') 95 | expect(config.role_arn).to eq('arn:aws:iam::123456789012:user/Gary') 96 | expect(config.role_session_name).to eq('testSessionName') 97 | expect(config.external_id).to eq('12345abc') 98 | expect(config.duration_seconds).to eq(0) 99 | end 100 | 101 | it 'can use AWS_DEFAULT_REGION for region' do 102 | stub_const( 103 | 'ENV', 104 | 'AWS_DEFAULT_REGION' => 'us-east-1', 105 | 'AWS_ROLE_ARN' => 'arn:aws:iam::123456789012:user/Gary', 106 | 'AWS_ROLE_SESSION_NAME' => 'testSessionName' 107 | ) 108 | config = Awssume::Configuration.new 109 | 110 | expect(config.region).to eq('us-east-1') 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /spec/awssume_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Awssume do 4 | it 'has a version number' do 5 | expect(Awssume::VERSION).not_to be nil 6 | end 7 | 8 | describe '.run' do 9 | before do 10 | fake_config = double('fake_config') 11 | [ 12 | :region, :role_arn, :role_session_name, :external_id, :duration_seconds 13 | ].each do |method| 14 | allow(fake_config).to receive(method) 15 | end 16 | 17 | fake_client = double('fake_client') 18 | allow(fake_client).to receive(:assume).and_return({}) 19 | 20 | allow(Awssume::Configuration).to receive(:new) 21 | .and_return(fake_config) 22 | 23 | allow(Awssume::Adapter::AwsClient).to receive(:new) 24 | .and_return(fake_client) 25 | 26 | allow(Awssume).to receive(:system).and_return(status) 27 | end 28 | 29 | subject { -> { Awssume.run } } 30 | 31 | context 'when the command returns a failing status' do 32 | let(:status) { false } 33 | it { is_expected.to raise_error(SystemExit) } 34 | end 35 | 36 | context 'when the command returns a passing status' do 37 | let(:status) { true } 38 | it { is_expected.to_not raise_error } 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 2 | require 'awssume' 3 | --------------------------------------------------------------------------------