Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add awareness of quota, and exit
  • Loading branch information
ikatz-drizly committed Jan 6, 2021
commit b8add7e654a54f909d6657785d18139c1b4e2f22
33 changes: 29 additions & 4 deletions lib/aws_rotate_keys/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ def initialize(iam: Aws::IAM::Client.new,
end

def call
log "Reading key quota..."
quota = access_key_quota

log "Reading existing keys..."
access_keys = aws_access_keys

if quota <= access_keys.size
log "Key set is already at quota limit of #{quota}:"
log_keylist(access_keys)
raise "You must manually delete a key or use one of the command-line overrides"
end
end

log "Creating access key..."
new_key = create_access_key

Expand All @@ -34,7 +47,7 @@ def call
write_aws_credentials_file(new_key)

log "Deleting your oldest access key..."
delete_oldest_access_key
delete_oldest_access_key(access_keys)

log aws_environment_variables_warning_message if aws_environment_variables?

Expand Down Expand Up @@ -63,14 +76,26 @@ def write_aws_credentials_file(access_key)
end
end

def delete_oldest_access_key
def access_key_quota
ret = @iam.get_account_summary.summary_map["AccessKeysPerUserQuota"]
end

def aws_access_keys
list_access_keys_response = iam.list_access_keys
access_keys = list_access_keys_response.access_key_metadata
list_access_keys_response.access_key_metadata
end

oldest_access_key = access_keys.sort_by(&:create_date).first
def delete_oldest_access_key(access_key_list)
oldest_access_key = access_key_list.min_by(&:create_date)
iam.delete_access_key(access_key_id: oldest_access_key.access_key_id)
end

def log_keylist(access_keys)
access_keys.each do |k|
log " #{k['create_date']} #{k['access_key_id']} #{k['status']}"
end
end

def log(msg)
stdout.puts msg
end
Expand Down
33 changes: 23 additions & 10 deletions spec/aws_rotate_keys_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,21 @@
NEW_SECRET = "SECRET123".freeze

class IAMDouble
def initialize
@keys = [
Aws::IAM::Types::AccessKeyMetadata.new(
access_key_id: OLD_KEY_ID,
create_date: Time.new(2017, 1, 1)
)
]
end

def create_access_key
@keys << Aws::IAM::Types::AccessKeyMetadata.new(
access_key_id: NEW_KEY_ID,
create_date: Time.new(2017, 2, 1)
)

Aws::IAM::Types::CreateAccessKeyResponse.new(
access_key: Aws::IAM::Types::AccessKey.new(
access_key_id: NEW_KEY_ID,
Expand All @@ -18,16 +32,15 @@ def create_access_key

def list_access_keys
Aws::IAM::Types::ListAccessKeysResponse.new(
access_key_metadata: [
Aws::IAM::Types::AccessKeyMetadata.new(
access_key_id: NEW_KEY_ID,
create_date: Time.new(2017, 2, 1)
),
Aws::IAM::Types::AccessKeyMetadata.new(
access_key_id: OLD_KEY_ID,
create_date: Time.new(2017, 1, 1)
)
]
access_key_metadata: @keys
)
end

def get_account_summary
Aws::IAM::Types::GetAccountSummaryResponse.new(
summary_map: {
"AccessKeysPerUserQuota" => 2
}
)
end

Expand Down
60 changes: 60 additions & 0 deletions spec/aws_rotate_keys_unsuccessfully_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require "spec_helper"
require "myio"

describe AwsRotateKeys do
ACTIVE_KEY_ID = "ACTKEEEY".freeze
INACTIVE_KEY_ID = "INACTKEY".freeze

class IAMAnotherDouble
def initialize
@keys = [
Aws::IAM::Types::AccessKeyMetadata.new(
access_key_id: INACTIVE_KEY_ID,
status: "Inactive",
create_date: Time.new(2017, 1, 1)
),
Aws::IAM::Types::AccessKeyMetadata.new(
access_key_id: ACTIVE_KEY_ID,
status: "Active",
create_date: Time.new(2017, 2, 1)
)
]
end

def list_access_keys
Aws::IAM::Types::ListAccessKeysResponse.new(
access_key_metadata: @keys
)
end

def get_account_summary
Aws::IAM::Types::GetAccountSummaryResponse.new(
summary_map: {
"AccessKeysPerUserQuota" => 2
}
)
end
end

let(:iam_double) { IAMAnotherDouble.new }
let(:credentials_path) { "./spec/tmp/aws/credentials" }

def rotate_keys(args = {})
AwsRotateKeys::CLI.call(
{
iam: iam_double,
credentials_path: credentials_path
}.merge(args)
)
end

context "when at quota and no override" do
it "raises an error" do
stdout = MyIO.new
expected_err = "You must manually delete a key or use one of the command-line overrides"
expect { rotate_keys(stdout: stdout) }.to raise_error(RuntimeError, expected_err)
expect(stdout.to_s).to include "Key set is already at quota limit"
end
end

end