diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index e65adc3..082999e 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -6,25 +6,30 @@ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby name: Ruby - on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] - + branches: ["main"] permissions: contents: read - jobs: test: runs-on: macos-latest steps: - - uses: actions/checkout@v3 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6.10 - bundler-cache: true - - name: Run tests - run: bundle exec rake + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.6.10 + bundler-cache: true + - name: Run filemode + run: bundle exec rake filemode + - name: Run Rubocop + run: bundle exec rake rubocop + - name: Run Rspec + run: bundle exec rake spec + - name: Run Ronn Doc + run: bundle exec rake ronn + - name: Run Yard Doc + run: bundle exec rake yard diff --git a/i18n/en.yml b/i18n/en.yml index 19dbf0d..f5fd02f 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -5,6 +5,7 @@ en: add_role_desc: Adds a ROLE to the keyring awskeyring_desc: Autocompletion for bourne shells console_desc: Open the AWS Console for the ACCOUNT + decode_desc: Decode an account id from a KEY default_desc: Run default help or initialise if needed. env_desc: Outputs bourne shell environment exports for an ACCOUNT exec_desc: Execute a COMMAND with the environment set for an ACCOUNT diff --git a/lib/awskeyring.rb b/lib/awskeyring.rb index 87ebe56..634675f 100644 --- a/lib/awskeyring.rb +++ b/lib/awskeyring.rb @@ -4,6 +4,7 @@ require 'json' require 'keychain' require 'awskeyring/validate' +require 'awskeyring/awsapi' # Awskeyring Module, # gives you an interface to access keychains and items. @@ -195,6 +196,19 @@ def self.list_account_names (items + tokens).uniq.sort end + # Return a list account item names plus account ids + def self.list_account_names_plus # rubocop:disable Metrics/AbcSize + list_items.concat(list_tokens).map do |elem| + account_id = Awskeyring::Awsapi.get_account_id(key: elem.attributes[:account]) + account_name = if elem.attributes[:label].start_with?(ACCOUNT_PREFIX) + elem.attributes[:label][(ACCOUNT_PREFIX.length)..] + else + elem.attributes[:label][(SESSION_KEY_PREFIX.length)..] + end + "#{account_name}\t#{account_id}" + end.uniq.sort + end + # Return a list role item names def self.list_role_names list_roles.map { |elem| elem.attributes[:label][(ROLE_PREFIX.length)..] }.sort diff --git a/lib/awskeyring/awsapi.rb b/lib/awskeyring/awsapi.rb index 9031008..c380ddb 100644 --- a/lib/awskeyring/awsapi.rb +++ b/lib/awskeyring/awsapi.rb @@ -25,6 +25,7 @@ module Awsapi # rubocop:disable Metrics/ModuleLength # AWS Env vars AWS_ENV_VARS = %w[ AWS_ACCOUNT_NAME + AWS_ACCOUNT_ID AWS_ACCESS_KEY_ID AWS_ACCESS_KEY AWS_CREDENTIAL_EXPIRATION @@ -123,14 +124,16 @@ def self.get_cred_json(key:, secret:, token:, expiry:) # [String] secret The aws_secret_access_key # [String] token The aws_session_token # @return [Hash] env_var hash - def self.get_env_array(params = {}) + def self.get_env_array(params = {}) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize env_var = {} env_var['AWS_DEFAULT_REGION'] = 'us-east-1' unless region params[:expiration] = Time.at(params[:expiry]).iso8601 unless params[:expiry].nil? + params[:account_name] = params.delete(:account) + params[:account_id] = get_account_id(key: params[:key]) unless params[:key].nil? - params.each_key do |param_name| - AWS_ENV_VARS.each do |var_name| + AWS_ENV_VARS.each do |var_name| + params.each_key do |param_name| if var_name.include?(param_name.to_s.upcase) && !params[param_name].nil? env_var[var_name] = params[param_name] end @@ -229,6 +232,30 @@ def self.region region || Aws.shared_config.region(profile: 'default') end + # Get the account number from an access key + # + # @param [String] key The aws_access_key_id + # @return [String] Account number + def self.get_account_id(key:) + padded_no = key[3..12] + mask = (2 << 39) - 1 + decimal = (decode(padded_no) >> 4) & mask + decimal.to_s.rjust(12, '0') + end + + # base32 decode function + # returns 0 on failure + private_class_method def self.decode(str) + aws_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567' + bytes = str.bytes + bytes.inject do |m, o| + i = aws_table.index(o.chr) + return 0 if i.nil? + + (m << 5) + i + end + end + # Rotates the AWS access keys # # @param [String] key The aws_access_key_id diff --git a/lib/awskeyring_command.rb b/lib/awskeyring_command.rb index 8b149b7..0ea3309 100644 --- a/lib/awskeyring_command.rb +++ b/lib/awskeyring_command.rb @@ -77,13 +77,18 @@ def initialise end desc 'list', I18n.t('list_desc') + method_option :detail, type: :boolean, aliases: '-d', desc: I18n.t('method_option.detail'), default: false # list the accounts def list if Awskeyring.list_account_names.empty? warn I18n.t('message.missing_account', bin: File.basename($PROGRAM_NAME)) exit 1 end - puts Awskeyring.list_account_names.join("\n") + if options[:detail] + puts Awskeyring.list_account_names_plus.join("\n") + else + puts Awskeyring.list_account_names.join("\n") + end end desc 'list-role', I18n.t('list_role_desc') @@ -426,6 +431,16 @@ def console(account = nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLeng end end + desc 'decode KEY', I18n.t('decode_desc'), hide: true + # decode account numbers + def decode(key = nil) + key = ask_check( + existing: key, message: I18n.t('message.key'), validator: Awskeyring::Validate.method(:access_key) + ) + + puts Awskeyring::Awsapi.get_account_id(key: key) + end + desc "#{File.basename($PROGRAM_NAME)} CURR PREV", I18n.t('awskeyring_desc'), hide: true map File.basename($PROGRAM_NAME) => :autocomplete # autocomplete @@ -522,7 +537,7 @@ def fetch_auto_resp(comp_type, sub_cmd) # list command names def list_commands commands = self.class.all_commands.keys.map { |elem| elem.tr('_', '-') } - commands.reject! { |elem| %w[autocomplete default].include?(elem) } + commands.reject! { |elem| %w[autocomplete default decode].include?(elem) } end # list flags for a command diff --git a/man/awskeyring.5 b/man/awskeyring.5 index 77c69d6..b899c08 100644 --- a/man/awskeyring.5 +++ b/man/awskeyring.5 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "AWSKEYRING" "5" "September 2023" "" "" +.TH "AWSKEYRING" "5" "October 2023" "" "" . .SH "NAME" \fBAwskeyring\fR \- is a small tool to manage AWS account keys in the macOS Keychain @@ -159,6 +159,9 @@ list: .IP Prints a list of accounts in the keyring . +.IP +\-d, \-\-detail, \-\-no\-detail: Show more detail\. +. .TP list\-role: . diff --git a/man/awskeyring.5.ronn b/man/awskeyring.5.ronn index 0cfb25e..ffe0208 100644 --- a/man/awskeyring.5.ronn +++ b/man/awskeyring.5.ronn @@ -86,6 +86,8 @@ The commands are as follows: Prints a list of accounts in the keyring + -d, --detail, --no-detail: Show more detail. + * list-role: Prints a list of roles in the keyring
diff --git a/spec/lib/awskeyring/awsapi_spec.rb b/spec/lib/awskeyring/awsapi_spec.rb index f9e0ffc..eafb81a 100644 --- a/spec/lib/awskeyring/awsapi_spec.rb +++ b/spec/lib/awskeyring/awsapi_spec.rb @@ -40,7 +40,7 @@ instance_double( Aws::STS::Types::AssumeRoleResponse, assumed_role_user: { - arn: 'arn:aws:sts::123456789012:assumed-role/demo/Bob', + arn: 'arn:aws:sts::747118721026:assumed-role/demo/Bob', assumed_role_id: 'ARO123EXAMPLE123:Bob' }, credentials: { @@ -62,7 +62,7 @@ instance_double( Aws::STS::Types::AssumeRoleResponse, assumed_role_user: { - arn: 'arn:aws:sts::123456789012:assumed-role/demo/Bob', + arn: 'arn:aws:sts::747118721026:assumed-role/demo/Bob', assumed_role_id: 'ARO123EXAMPLE123:Bob' }, credentials: { @@ -217,7 +217,7 @@ end context 'when credentials are verified' do - let(:key) { 'AKIA1234567890ABCDEF' } + let(:key) { 'AKIA234567ABCDEFGHIJ' } let(:secret) { 'AbCkTEsTAAAi8ni0987ASDFwer23j14FEQW3IUJV' } let(:token) { 'AQoDYXdzEPT//////////wEXAMPLEtc764assume_roleDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMi' } @@ -227,9 +227,9 @@ allow(described_class).to receive(:region).and_return(nil) allow(Aws::STS::Client).to receive(:new).and_return(sts_client) allow(sts_client).to receive(:get_caller_identity).and_return( - account: '123456789012', - arn: 'arn:aws:iam::123456789012:user/Alice', - user_id: 'AKIAI44QH8DHBEXAMPLE' + account: '747118721026', + arn: 'arn:aws:iam::747118721026:user/Alice', + user_id: 'AKIA234567ABCDEFGHIJ' ) end @@ -240,11 +240,19 @@ it 'calls get_caller_identity with a token' do expect(awsapi.verify_cred(key: key, secret: secret, token: token)).to be(true) end + + it 'calls get_account_id with a valid token' do + expect(awsapi.get_account_id(key: key)).to eq('747118721026') + end + + it 'calls get_account_id returning a short account number' do + expect(awsapi.get_account_id(key: 'AKIAQAAA67ABCDEFGHIJ')).to eq('000002029570') + end end context 'when keys are roated' do let(:account) { 'test' } - let(:key) { 'AKIA1234567890ABCDEF' } + let(:key) { 'AKIA234567ABCDEFGHIJ' } let(:secret) { 'AbCkTEsTAAAi8ni0987ASDFwer23j14FEQW3IUJV' } let(:new_key) { 'AKIAIOSFODNN7EXAMPLE' } let(:new_secret) { 'wJalrXUtnFEMI/K7MDENG/bPxRiCYzEXAMPLEKEY' } @@ -258,7 +266,7 @@ allow(iam_client).to receive_messages( list_access_keys: { access_key_metadata: [ { - access_key_id: 'AKIATESTTEST', + access_key_id: 'AKIA234567ABCDEFGHIJ', create_date: Time.parse('2016-12-01T22:19:58Z'), status: 'Active', user_name: 'Alice' @@ -293,7 +301,7 @@ context 'when key rotation fails' do let(:account) { 'test' } - let(:key) { 'AKIA1234567890ABCDEF' } + let(:key) { 'AKIA234567ABCDEFGHIJ' } let(:secret) { 'AbCkTEsTAAAi8ni0987ASDFwer23j14FEQW3IUJV' } let(:key_message) { '# You have two access keys for account test' } let(:iam_client) { instance_double(Aws::IAM::Client) } @@ -333,7 +341,7 @@ context 'when key rotation fails to delete' do let(:account) { 'test' } - let(:key) { 'AKIA1234567890ABCDEF' } + let(:key) { 'AKIA234567ABCDEFGHIJ' } let(:secret) { 'AbCkTEsTAAAi8ni0987ASDFwer23j14FEQW3IUJV' } let(:new_key) { 'AKIAIOSFODNN7EXAMPLE' } let(:new_secret) { 'wJalrXUtnFEMI/K7MDENG/bPxRiCYzEXAMPLEKEY' } @@ -402,13 +410,14 @@ expect(awsapi.get_env_array( account: 'test', expiry: 1_489_305_329, - key: 'ASIAIOSFODNN7EXAMPLE', + key: 'ASIA234567ABCDEFGHIJ', secret: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY', token: role_token )).to eq( - 'AWS_ACCESS_KEY' => 'ASIAIOSFODNN7EXAMPLE', - 'AWS_ACCESS_KEY_ID' => 'ASIAIOSFODNN7EXAMPLE', + 'AWS_ACCESS_KEY' => 'ASIA234567ABCDEFGHIJ', + 'AWS_ACCESS_KEY_ID' => 'ASIA234567ABCDEFGHIJ', 'AWS_ACCOUNT_NAME' => 'test', + 'AWS_ACCOUNT_ID' => '747118721026', 'AWS_CREDENTIAL_EXPIRATION' => Time.at(1_489_305_329).iso8601, 'AWS_DEFAULT_REGION' => 'us-east-1', 'AWS_SECRET_ACCESS_KEY' => 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY', @@ -420,7 +429,7 @@ end context 'when existing creds are loaded from a file' do - let(:key) { 'AKIA1234567890ABCDEF' } + let(:key) { 'AKIA234567ABCDEFGHIJ' } let(:secret) { 'AbCkTEsTAAAi8ni0987ASDFwer23j14FEQW3IUJV' } let(:token) { 'AQoDYXdzEPT//////////wEXAMPLEtc764assume_roleDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMi' } let(:account_key) { 'AKIAIOSFODNN7EXAMPLE' } @@ -523,5 +532,9 @@ ) end.to raise_error(SystemExit).and output(/The security token included in the request is invalid/).to_stderr end + + it 'calls get_account_id with an invalid token' do + expect(awsapi.get_account_id(key: key)).to eq('000000000000') + end end end diff --git a/spec/lib/awskeyring_command_exceptional_spec.rb b/spec/lib/awskeyring_command_exceptional_spec.rb index 6ccccee..a6b70c6 100644 --- a/spec/lib/awskeyring_command_exceptional_spec.rb +++ b/spec/lib/awskeyring_command_exceptional_spec.rb @@ -14,7 +14,7 @@ allow(Awskeyring::Awsapi).to receive(:region).and_return(nil) allow(Awskeyring).to receive_messages( get_valid_creds: { account: 'test', - key: 'ASIATESTTEST', + key: 'AKIA234567ABCDEFGHIJ', secret: 'bigerlongbase64', token: nil, updated: Time.parse('2011-08-01T22:20:01Z') }, @@ -89,8 +89,9 @@ expect { described_class.start(%w[env test --force]) } .to output(%(export AWS_DEFAULT_REGION="us-east-1" export AWS_ACCOUNT_NAME="test" -export AWS_ACCESS_KEY_ID="ASIATESTTEST" -export AWS_ACCESS_KEY="ASIATESTTEST" +export AWS_ACCOUNT_ID="747118721026" +export AWS_ACCESS_KEY_ID="AKIA234567ABCDEFGHIJ" +export AWS_ACCESS_KEY="AKIA234567ABCDEFGHIJ" export AWS_SECRET_ACCESS_KEY="bigerlongbase64" export AWS_SECRET_KEY="bigerlongbase64" unset AWS_CREDENTIAL_EXPIRATION diff --git a/spec/lib/awskeyring_command_spec.rb b/spec/lib/awskeyring_command_spec.rb index 0314646..49523bc 100644 --- a/spec/lib/awskeyring_command_spec.rb +++ b/spec/lib/awskeyring_command_spec.rb @@ -90,8 +90,9 @@ context 'when accounts and roles are set' do before do allow(Awskeyring).to receive_messages( - list_account_names: %w[company personal servian], - list_token_names: %w[personal sersaml], + list_account_names: %w[company personal sarviun], + list_account_names_plus: %W[company\t123456 personal\t345678 sarviun\t432765], + list_token_names: %w[personal sarsaml], list_role_names: %w[admin minion readonly], list_role_names_plus: %W[admin\tarn1 minion\tarn2 readonly\tarn3], list_console_path: %w[iam cloudformation vpc], @@ -104,24 +105,29 @@ ['awskeyring con', %w[con awskeyring], "console\n", 'commands'], ['awskeyring list', %w[list awskeyring], "list\nlist-role\n", 'similar commands'], ['awskeyring help list', %w[list help], "list\nlist-role\n", 'commands for help'], - ['awskeyring token ser', %w[ser token], "servian\n", 'account names'], - ['awskeyring exec ser', %w[ser exec], "servian\n", 'accounts for exec'], + ['awskeyring token sar', %w[sar token], "sarviun\n", 'account names'], + ['awskeyring exec sar', %w[sar exec], "sarviun\n", 'accounts for exec'], ['awskeyring remove-role min', %w[min remove-role], "minion\n", 'roles'], ['awskeyring rmr min', %w[min rmr], "minion\n", 'roles for short commands'], - ['awskeyring rmt ser', %w[ser rmt], "sersaml\n", 'tokens'], - ['awskeyring token servian minion 123456 --dura', %w[--dura 123456], "--duration\n", 'flags'], - ['awskeyring token servian minion --dura', %w[--dura minion], "--duration\n", 'flags'], - ['awskeyring con servian --p', %w[--p servian], "--path\n", 'flags'], + ['awskeyring rmt sar', %w[sar rmt], "sarsaml\n", 'tokens'], + ['awskeyring token sarviun minion 123456 --dura', %w[--dura 123456], "--duration\n", 'flags'], + ['awskeyring token sarviun minion --dura', %w[--dura minion], "--duration\n", 'flags'], + ['awskeyring con sarviun --p', %w[--p sarviun], "--path\n", 'flags'], ['awskeyring add sarveun --n', %w[--n sarveun], "--no-remote\n", 'flags for add'], ['awskeyring -v --n', %w[--n -v], "--no-remote\n", 'flags for --version'], - ['awskeyring exec servian --no', %w[--no servian], "--no-bundle\n--no-token\n", 'flags for exec'], - ['awskeyring console servian --path cloud', %w[cloud --path], "cloudformation\n", 'console paths'], - ['awskeyring con servian --browser Sa', %w[Sa --browser], "Safari\n", 'browsers'] + ['awskeyring exec sarviun --no', %w[--no sarviun], "--no-bundle\n--no-token\n", 'flags for exec'], + ['awskeyring console sarviun --path cloud', %w[cloud --path], "cloudformation\n", 'console paths'], + ['awskeyring con sarviun --browser Sa', %w[Sa --browser], "Safari\n", 'browsers'] ] it 'list keychain items' do expect { described_class.start(%w[list]) } - .to output("company\npersonal\nservian\n").to_stdout + .to output("company\npersonal\nsarviun\n").to_stdout + end + + it 'list keychain items with detail' do + expect { described_class.start(%w[list -d]) } + .to output("company\t123456\npersonal\t345678\nsarviun\t432765\n").to_stdout end it 'list keychain roles' do @@ -134,6 +140,11 @@ .to output("admin\tarn1\nminion\tarn2\nreadonly\tarn3\n").to_stdout end + it 'decodes an account number from a key' do + expect { described_class.start(%w[decode AKIA234567ABCDEFGHIJ]) } + .to output("747118721026\n").to_stdout + end + test_cases.shuffle.each do |testcase| it "lists #{testcase[3]} with autocomplete" do ENV['COMP_LINE'] = testcase[0] @@ -176,13 +187,12 @@ allow(Awskeyring).to receive(:delete_role) allow(Awskeyring).to receive(:get_valid_creds).with(account: 'test', no_token: false).and_return( account: 'test', - key: 'AKIATESTTEST', + key: 'AKIA234567ABCDEFGHIJ', secret: 'biglongbase64', token: nil, updated: Time.parse('2011-08-11T22:20:01Z') ) allow(Time).to receive(:new).and_return(Time.parse('2011-07-11T19:55:29.611Z')) - allow(Awskeyring::Awsapi).to receive(:region).and_return(nil) allow(Awskeyring).to receive_messages( account_exists: 'test', role_exists: 'test', @@ -207,8 +217,9 @@ expect { described_class.start(%w[env test --force]) } .to output(%(export AWS_DEFAULT_REGION="us-east-1" export AWS_ACCOUNT_NAME="test" -export AWS_ACCESS_KEY_ID="AKIATESTTEST" -export AWS_ACCESS_KEY="AKIATESTTEST" +export AWS_ACCOUNT_ID="747118721026" +export AWS_ACCESS_KEY_ID="AKIA234567ABCDEFGHIJ" +export AWS_ACCESS_KEY="AKIA234567ABCDEFGHIJ" export AWS_SECRET_ACCESS_KEY="biglongbase64" export AWS_SECRET_KEY="biglongbase64" unset AWS_CREDENTIAL_EXPIRATION @@ -222,6 +233,7 @@ expect { described_class.start(%w[env --unset]) } .to output(%(export AWS_DEFAULT_REGION="us-east-1" unset AWS_ACCOUNT_NAME +unset AWS_ACCOUNT_ID unset AWS_ACCESS_KEY_ID unset AWS_ACCESS_KEY unset AWS_CREDENTIAL_EXPIRATION @@ -238,8 +250,9 @@ let(:env_vars) do { 'AWS_DEFAULT_REGION' => 'us-east-1', 'AWS_ACCOUNT_NAME' => 'test', - 'AWS_ACCESS_KEY_ID' => 'ASIATESTTEST', - 'AWS_ACCESS_KEY' => 'ASIATESTTEST', + 'AWS_ACCOUNT_ID' => '747118721026', + 'AWS_ACCESS_KEY_ID' => 'ASIA234567ABCDEFGHIJ', + 'AWS_ACCESS_KEY' => 'ASIA234567ABCDEFGHIJ', 'AWS_CREDENTIAL_EXPIRATION' => Time.at(1_310_414_129).iso8601, 'AWS_SECRET_ACCESS_KEY' => 'bigerlongbase64', 'AWS_SECRET_KEY' => 'bigerlongbase64', @@ -253,7 +266,7 @@ allow(Awskeyring).to receive(:delete_token) allow(Awskeyring).to receive(:get_valid_creds).with(account: 'test', no_token: false).and_return( account: 'test', - key: 'ASIATESTTEST', + key: 'ASIA234567ABCDEFGHIJ', secret: 'bigerlongbase64', token: 'evenlongerbase64token', role: 'role', @@ -262,7 +275,7 @@ ) allow(Awskeyring).to receive(:get_valid_creds).with(account: 'test', no_token: true).and_return( account: 'test', - key: 'AKIATESTTEST', + key: 'AKIA234567ABCDEFGHIJ', secret: 'biglongbase64', token: nil, expiry: nil, @@ -295,13 +308,14 @@ expect { described_class.start(%w[env test]) } .to output(%(export AWS_DEFAULT_REGION="us-east-1" export AWS_ACCOUNT_NAME="test" -export AWS_ACCESS_KEY_ID="ASIATESTTEST" -export AWS_ACCESS_KEY="ASIATESTTEST" +export AWS_ACCOUNT_ID="747118721026" +export AWS_ACCESS_KEY_ID="ASIA234567ABCDEFGHIJ" +export AWS_ACCESS_KEY="ASIA234567ABCDEFGHIJ" +export AWS_CREDENTIAL_EXPIRATION="#{Time.at(1_310_414_129).iso8601}" export AWS_SECRET_ACCESS_KEY="bigerlongbase64" export AWS_SECRET_KEY="bigerlongbase64" export AWS_SECURITY_TOKEN="evenlongerbase64token" export AWS_SESSION_TOKEN="evenlongerbase64token" -export AWS_CREDENTIAL_EXPIRATION="#{Time.at(1_310_414_129).iso8601}" )).to_stdout expect(Awskeyring).to have_received(:get_valid_creds).with(account: 'test', no_token: false) end @@ -310,8 +324,9 @@ expect { described_class.start(%w[env test --no-token]) } .to output(%(export AWS_DEFAULT_REGION="us-east-1" export AWS_ACCOUNT_NAME="test" -export AWS_ACCESS_KEY_ID="AKIATESTTEST" -export AWS_ACCESS_KEY="AKIATESTTEST" +export AWS_ACCOUNT_ID="747118721026" +export AWS_ACCESS_KEY_ID="AKIA234567ABCDEFGHIJ" +export AWS_ACCESS_KEY="AKIA234567ABCDEFGHIJ" export AWS_SECRET_ACCESS_KEY="biglongbase64" export AWS_SECRET_KEY="biglongbase64" unset AWS_CREDENTIAL_EXPIRATION @@ -325,7 +340,7 @@ expect { described_class.start(%w[json test]) } .to output("#{JSON.pretty_generate( Version: 1, - AccessKeyId: 'ASIATESTTEST', + AccessKeyId: 'ASIA234567ABCDEFGHIJ', SecretAccessKey: 'bigerlongbase64', SessionToken: 'evenlongerbase64token', Expiration: Time.at(Time.parse('2011-07-11T19:55:29.611Z').to_i).iso8601 diff --git a/spec/lib/awskeyring_spec.rb b/spec/lib/awskeyring_spec.rb index 3135a29..35cf9a2 100644 --- a/spec/lib/awskeyring_spec.rb +++ b/spec/lib/awskeyring_spec.rb @@ -84,9 +84,9 @@ Keychain::Item, attributes: { label: 'account test', - account: 'AKIATESTTEST', + account: 'AKIA234567ABCDEFGHIJ', updated_at: Time.parse('2016-12-01T22:20:01Z'), - comment: 'arn:aws:iam::012345678901:mfa/ec2-user' + comment: 'arn:aws:iam::747118721026:mfa/ec2-user' }, password: 'biglongbase64' ) @@ -94,14 +94,14 @@ let(:role) do instance_double( Keychain::Item, - attributes: { label: 'role test', account: 'arn:aws:iam::012345678901:role/test' }, + attributes: { label: 'role test', account: 'arn:aws:iam::747118721026:role/test' }, password: '' ) end let(:roleee) do instance_double( Keychain::Item, - attributes: { label: 'role testee', account: 'arn:aws:iam::012345678901:role/testee' }, + attributes: { label: 'role testee', account: 'arn:aws:iam::747118721026:role/testee' }, password: '' ) end @@ -131,11 +131,11 @@ it 'returns a hash with the creds' do expect(awskeyring.get_valid_creds(account: 'test', no_token: true)).to eq( account: 'test', - key: 'AKIATESTTEST', + key: 'AKIA234567ABCDEFGHIJ', secret: 'biglongbase64', token: nil, expiry: nil, - mfa: 'arn:aws:iam::012345678901:mfa/ec2-user', + mfa: 'arn:aws:iam::747118721026:mfa/ec2-user', updated: Time.parse('2016-12-01T22:20:01Z') ) end @@ -197,7 +197,7 @@ it 'returns a hash with the role' do expect(awskeyring.get_role_arn(role_name: 'test')).to eq( - 'arn:aws:iam::012345678901:role/test' + 'arn:aws:iam::747118721026:role/test' ) end @@ -215,14 +215,14 @@ context 'when there is accounts and roles and tokens' do let(:access_key) { 'AKIA234567ABCDEFGHIJ' } - let(:role_arn) { 'arn:aws:iam::012345678901:role/test' } + let(:role_arn) { 'arn:aws:iam::747118721026:role/test' } let(:item) do instance_double( Keychain::Item, attributes: { label: 'account test', account: access_key, - comment: 'arn:aws:iam::012345678901:mfa/ec2-user', + comment: 'arn:aws:iam::747118721026:mfa/ec2-user', updated_at: Time.parse('2016-12-01T22:20:01Z') }, password: 'biglongbase64' @@ -240,7 +240,7 @@ Keychain::Item, attributes: { label: 'session-key test', - account: 'ASIATESTTEST', + account: 'ASIA234567ABCTESTHIJ', comment: 'role role', updated_at: Time.parse('2016-12-01T22:20:01Z') }, @@ -290,7 +290,7 @@ end.to output(/# Using temporary session credentials/).to_stdout expect(test_hash).to eq( account: 'test', - key: 'ASIATESTTEST', + key: 'ASIA234567ABCTESTHIJ', secret: 'bigerlongbase64', token: 'evenlongerbase64token', expiry: Time.parse('2016-12-20T22:20:01Z').to_i, @@ -306,14 +306,14 @@ secret: 'biglongbase64', token: nil, expiry: nil, - mfa: 'arn:aws:iam::012345678901:mfa/ec2-user', + mfa: 'arn:aws:iam::747118721026:mfa/ec2-user', updated: Time.parse('2016-12-01T22:20:01Z') ) end it 'returns a hash with the role' do expect(awskeyring.get_role_arn(role_name: 'role')).to eq( - 'arn:aws:iam::012345678901:role/test' + 'arn:aws:iam::747118721026:role/test' ) end @@ -351,6 +351,12 @@ ) end + it 'lists all accounts with detail' do + expect(awskeyring.list_account_names_plus).to eq( + ["test\t747118721026"] + ) + end + it 'lists all tokens' do expect(awskeyring.list_token_names).to eq( ['test'] @@ -389,20 +395,20 @@ it 'lists all roles with detail' do expect(awskeyring.list_role_names_plus).to eq( - ["role\tarn:aws:iam::012345678901:role/test"] + ["role\tarn:aws:iam::747118721026:role/test"] ) end end context 'when there is an expired token' do - let(:access_key) { 'AKIA1234567890ABCDEF' } + let(:access_key) { 'AKIA234567ABCDEFGHIJ' } let(:item) do instance_double( Keychain::Item, attributes: { label: 'account test', account: access_key, - comment: 'arn:aws:iam::012345678901:mfa/ec2-user', + comment: 'arn:aws:iam::747118721026:mfa/ec2-user', updated_at: Time.parse('2016-12-01T22:20:01Z') }, password: 'biglongbase64' @@ -413,7 +419,7 @@ Keychain::Item, attributes: { label: 'session-key test', - account: 'ASIATESTTEST', + account: 'ASIA234567ABCTESTHIJ', comment: 'role role', updated_at: Time.parse('2016-12-01T22:20:01Z') }, @@ -462,7 +468,7 @@ end.to output(/# Removing expired session credentials/).to_stdout expect(test_hash).to eq( account: 'test', - key: 'AKIA1234567890ABCDEF', + key: 'AKIA234567ABCDEFGHIJ', secret: 'biglongbase64', token: nil, expiry: nil,