sport_ngin_aws_auditor 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +1 -142
- data/bin/sport-ngin-aws-auditor +10 -1
- data/lib/sport_ngin_aws_auditor/audit_data.rb +4 -10
- data/lib/sport_ngin_aws_auditor/aws.rb +73 -35
- data/lib/sport_ngin_aws_auditor/cache_instance.rb +4 -6
- data/lib/sport_ngin_aws_auditor/commands/audit.rb +1 -1
- data/lib/sport_ngin_aws_auditor/commands/export.rb +1 -1
- data/lib/sport_ngin_aws_auditor/commands/inspect.rb +1 -1
- data/lib/sport_ngin_aws_auditor/convenience_wrappers.rb +0 -88
- data/lib/sport_ngin_aws_auditor/ec2_instance.rb +2 -5
- data/lib/sport_ngin_aws_auditor/instance.rb +0 -2
- data/lib/sport_ngin_aws_auditor/instance_helper.rb +0 -3
- data/lib/sport_ngin_aws_auditor/output.rb +4 -0
- data/lib/sport_ngin_aws_auditor/rds_instance.rb +3 -7
- data/lib/sport_ngin_aws_auditor/recently_retired_tag.rb +0 -2
- data/lib/sport_ngin_aws_auditor/scripts/audit.rb +2 -8
- data/lib/sport_ngin_aws_auditor/scripts/export.rb +9 -11
- data/lib/sport_ngin_aws_auditor/scripts/inspect.rb +6 -11
- data/lib/sport_ngin_aws_auditor/version.rb +1 -1
- data/lib/sport_ngin_aws_auditor.rb +15 -11
- data/spec/sport_ngin_aws_auditor/audit_data_spec.rb +1 -0
- data/spec/sport_ngin_aws_auditor/aws_spec.rb +25 -23
- data/spec/sport_ngin_aws_auditor/cache_instance_spec.rb +1 -0
- data/spec/sport_ngin_aws_auditor/rds_instance_spec.rb +1 -0
- metadata +2 -3
- data/lib/sport_ngin_aws_auditor/stack.rb +0 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6e2a11ed64e5f72238b80eb808015489df6a243
|
4
|
+
data.tar.gz: 1b09c49f16a8bf21db028a1be599ed09ff107526
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3e794c240a871df8314544b34a2a065409cd83e5bd09f8842e6f5fd6a3a75ad1d9b1ce4f5c4ab5ca0c3bad72cdbcdbd55636b4f52021ff95f6a545ad12fb2ee
|
7
|
+
data.tar.gz: 4d845435e3ede6990360081c22a084545adc66dd76be55234ac1182945b77dca3967b541432da25f3d23601c4ae67d1fdde53aa2c44316f764beda3768037219
|
data/CHANGELOG.markdown
CHANGED
@@ -1,142 +1 @@
|
|
1
|
-
#### v4.
|
2
|
-
* Write a message reporting when the auditor fails for any reason
|
3
|
-
|
4
|
-
> Emma Sax: Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/36
|
5
|
-
|
6
|
-
#### v4.0.2
|
7
|
-
* Define availability zone as attribute for RDS object to avoid errors
|
8
|
-
|
9
|
-
> Emma Sax: Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/35
|
10
|
-
|
11
|
-
#### v4.0.1
|
12
|
-
* Concat all of the similar values into one value right before printing
|
13
|
-
|
14
|
-
> Emma Sax: Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/27
|
15
|
-
|
16
|
-
#### v4.0.0
|
17
|
-
* Adding abilities to audit cross account
|
18
|
-
|
19
|
-
> Emma Sax: Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/31
|
20
|
-
|
21
|
-
#### v3.11.3
|
22
|
-
* Missed this bug because I did not test previous bug's fix in Slack
|
23
|
-
|
24
|
-
> Emma Sax: Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/30
|
25
|
-
|
26
|
-
#### v3.11.2
|
27
|
-
* We actually do not want to cache the counts of instances and reserved instances between multiple runs
|
28
|
-
|
29
|
-
> Emma Sax: Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/29
|
30
|
-
|
31
|
-
#### v3.11.1
|
32
|
-
* Must merge this PR in to run the audit command correctly
|
33
|
-
|
34
|
-
> Emma Sax: Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/28
|
35
|
-
|
36
|
-
#### v3.11.0
|
37
|
-
* Automatically ignore instances based on a regex string
|
38
|
-
|
39
|
-
> Emma Sax: Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/26
|
40
|
-
|
41
|
-
#### v3.10.1
|
42
|
-
* Caching should not affect RI counts between runs
|
43
|
-
|
44
|
-
> Emma Sax: Andy Fleener, Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/25
|
45
|
-
|
46
|
-
#### v3.10.0
|
47
|
-
* Handling region-based RIs
|
48
|
-
|
49
|
-
> Emma Sax: Andy Fleener, Luke Ludwig, Tim Sandquist, Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/21
|
50
|
-
|
51
|
-
#### v3.9.0
|
52
|
-
* Add the ability to pass config data in as a flag
|
53
|
-
|
54
|
-
> Emma Sax: Andy Fleener, Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/24
|
55
|
-
|
56
|
-
#### v3.8.3
|
57
|
-
* Fixing bugs with outputs and counts
|
58
|
-
|
59
|
-
> Emma Sax: Tim Sandquist, Unknown User: https://github.com/sportngin/sport_ngin_aws_auditor/pull/23
|
60
|
-
|
61
|
-
#### v3.8.2
|
62
|
-
* Fixing bugs so that counts are accurate again
|
63
|
-
|
64
|
-
> Emma Sax: : https://github.com/sportngin/sport_ngin_aws_auditor/pull/20
|
65
|
-
|
66
|
-
#### v3.8.1
|
67
|
-
#### v3.8.0
|
68
|
-
* Clarifying printout of audit command
|
69
|
-
|
70
|
-
> Emma Sax: : https://github.com/sportngin/sport_ngin_aws_auditor/pull/18
|
71
|
-
|
72
|
-
#### v3.7.0
|
73
|
-
* Print retired tags into slack/terminal on audit
|
74
|
-
|
75
|
-
> Emma Sax: Brian Bergstrom: https://github.com/sportngin/sport_ngin_aws_auditor/pull/17
|
76
|
-
|
77
|
-
#### v3.6.0
|
78
|
-
* Print reserved instances that have retired in past week
|
79
|
-
|
80
|
-
> Emma Sax: Andy Fleener: https://github.com/sportngin/sport_ngin_aws_auditor/pull/16
|
81
|
-
|
82
|
-
#### v3.5.0
|
83
|
-
* Cleaning up slack printouts with the audit command
|
84
|
-
|
85
|
-
> Emma Sax: Brian Bergstrom: https://github.com/sportngin/sport_ngin_aws_auditor/pull/15
|
86
|
-
|
87
|
-
#### v3.4.1
|
88
|
-
#### v3.4.0
|
89
|
-
* Add other RDS engine types
|
90
|
-
|
91
|
-
> matl33t: Emma Sax, Brian Bergstrom: https://github.com/sportngin/sport_ngin_aws_auditor/pull/11
|
92
|
-
|
93
|
-
#### v3.3.1
|
94
|
-
* Fixing bug where Slack will print discrepancies if there are *only* tagged instances
|
95
|
-
|
96
|
-
> Emma Sax: : https://github.com/sportngin/sport_ngin_aws_auditor/pull/13
|
97
|
-
|
98
|
-
#### v3.3.0
|
99
|
-
* Slack should print instances that have tags
|
100
|
-
|
101
|
-
> Emma Sax: Andy Fleener: https://github.com/sportngin/sport_ngin_aws_auditor/pull/12
|
102
|
-
|
103
|
-
#### v3.2.0
|
104
|
-
* Proper recognition of windows/linux/vpc instances
|
105
|
-
|
106
|
-
> Emma Sax: Andy Fleener: https://github.com/sportngin/sport_ngin_aws_auditor/pull/8
|
107
|
-
|
108
|
-
#### v3.1.2
|
109
|
-
#### v3.1.0
|
110
|
-
* Authentication with AWS roles instead of credentials file
|
111
|
-
|
112
|
-
> Emma Sax: Brian Bergstrom: https://github.com/sportngin/sport_ngin_aws_auditor/pull/7
|
113
|
-
|
114
|
-
#### v3.0.2
|
115
|
-
#### v3.0.1
|
116
|
-
#### v3.0.0
|
117
|
-
* Rename gem directories and modules
|
118
|
-
|
119
|
-
> Emma Sax: Brian Bergstrom: https://github.com/sportngin/sport_ngin_aws_auditor/pull/6
|
120
|
-
|
121
|
-
#### v2.1.0
|
122
|
-
* Adding option to print audit results to Slack channel
|
123
|
-
|
124
|
-
> Emma Sax, Matt Krieger: Brian Bergstrom: https://github.com/sportngin/aws_auditor/pull/4
|
125
|
-
|
126
|
-
* Adding option to print audit results to Slack channel
|
127
|
-
|
128
|
-
> Emma Sax, Matt Krieger: Brian Bergstrom: https://github.com/sportngin/aws_auditor/pull/4
|
129
|
-
|
130
|
-
#### v2.0.0
|
131
|
-
* Adding enhancements for taking no-reserved-instance tag into consideration during audit
|
132
|
-
|
133
|
-
> Emma Sax: Brian Bergstrom: https://github.com/sportngin/aws_auditor/pull/2
|
134
|
-
|
135
|
-
#### v1.0.0
|
136
|
-
* Upgrading aws-sdk version from v1 to v2
|
137
|
-
|
138
|
-
> Emma Sax: Brian Bergstrom: https://github.com/sportngin/aws_auditor/pull/3
|
139
|
-
|
140
|
-
* First tests, Travis CI, MFA support, and fog file compatibility
|
141
|
-
|
142
|
-
> Brian Bergstrom: Emma Sax: https://github.com/sportngin/aws_auditor/pull/1
|
1
|
+
#### v4.2.0
|
data/bin/sport-ngin-aws-auditor
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'rubygems'
|
3
3
|
require 'gli'
|
4
|
-
|
4
|
+
require 'sport_ngin_aws_auditor'
|
5
5
|
|
6
6
|
include GLI::App
|
7
7
|
|
@@ -33,4 +33,13 @@ pre do |global,command,options,args|
|
|
33
33
|
true
|
34
34
|
end
|
35
35
|
|
36
|
+
on_error do |exception|
|
37
|
+
if ENV['GLI_DEBUG']
|
38
|
+
puts exception
|
39
|
+
puts exception.backtrace
|
40
|
+
else
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
36
45
|
exit run(ARGV)
|
@@ -1,13 +1,7 @@
|
|
1
|
-
require_relative './instance_helper'
|
2
|
-
require_relative './convenience_wrappers'
|
3
|
-
|
4
1
|
module SportNginAwsAuditor
|
5
2
|
class AuditData
|
6
|
-
extend EC2Wrapper
|
7
|
-
extend RDSWrapper
|
8
|
-
extend CacheWrapper
|
9
|
-
|
10
3
|
attr_accessor :data, :retired_tags, :retired_ris, :selected_audit_type, :klass, :tag_name, :region, :ignore_instances_regexes, :client
|
4
|
+
|
11
5
|
def initialize(info)
|
12
6
|
self.selected_audit_type = (!info[:instances] && !info[:reserved]) ? "all" : (info[:instances] ? "instances" : "reserved")
|
13
7
|
self.klass = SportNginAwsAuditor.const_get(info[:class])
|
@@ -16,11 +10,11 @@ module SportNginAwsAuditor
|
|
16
10
|
self.region = info[:region].match(/(\w{2}-\w{4,})/)[0] if info[:region].match(/(\w{2}-\w{4,})/)
|
17
11
|
|
18
12
|
if info[:class] == "EC2Instance"
|
19
|
-
self.client =
|
13
|
+
self.client = AWS.ec2(info[:region])
|
20
14
|
elsif info[:class] == "RDSInstance"
|
21
|
-
self.client =
|
15
|
+
self.client = AWS.rds(info[:region])
|
22
16
|
elsif info[:class] == "CacheInstance"
|
23
|
-
self.client =
|
17
|
+
self.client = AWS.cache(info[:region])
|
24
18
|
end
|
25
19
|
end
|
26
20
|
|
@@ -1,61 +1,99 @@
|
|
1
1
|
require 'aws-sdk'
|
2
|
-
require 'yaml'
|
3
|
-
require 'hashie'
|
4
2
|
|
5
3
|
module SportNginAwsAuditor
|
6
|
-
class
|
7
|
-
|
8
|
-
|
4
|
+
class AWS
|
5
|
+
DEFAULT_REGION = 'us-east-1'
|
6
|
+
|
7
|
+
@environment = nil
|
8
|
+
@aws_roles = false
|
9
|
+
@assume_roles = false
|
10
|
+
@credentials = nil
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_reader :environment, :aws_roles, :assume_roles, :credentials
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configure(environment, global_options)
|
17
|
+
@environment = environment
|
18
|
+
|
19
|
+
if global_options[:aws_roles]
|
20
|
+
puts "Authenticating with AWS using server roles."
|
21
|
+
@credentials = nil # Auth using server role.
|
22
|
+
elsif global_options[:assume_roles]
|
23
|
+
puts "Authenticating with AWS by assuming roles."
|
24
|
+
auth_with_assumed_roles(global_options[:arn_id], global_options[:role_name])
|
25
|
+
else
|
26
|
+
puts "Authenticating with AWS using credentials file."
|
27
|
+
auth_with_iam
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.reset
|
32
|
+
@environment = @credentials = nil
|
33
|
+
@aws_roles = @assume_roles = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.client_options(region=DEFAULT_REGION)
|
37
|
+
if @credentials.nil? && @aws_roles == false
|
38
|
+
raise "Unable to set AWS SDK client options because credentials not set and not flagged to use server role."
|
39
|
+
end
|
40
|
+
opts = { region: region }
|
41
|
+
opts[:credentials] = @credentials unless @credentials.nil?
|
42
|
+
opts
|
43
|
+
end
|
9
44
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
45
|
+
def self.get_account_id
|
46
|
+
Aws::STS::Client.new(client_options).get_caller_identity.account
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.sts_for_instance
|
50
|
+
Aws::STS::Client.new(region: DEFAULT_REGION, credentials: Aws::InstanceProfileCredentials.new)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.ec2(region=DEFAULT_REGION)
|
54
|
+
Aws::EC2::Client.new(client_options(region))
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.rds(region=DEFAULT_REGION)
|
58
|
+
Aws::RDS::Client.new(client_options(region))
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.cache(region=DEFAULT_REGION)
|
62
|
+
Aws::ElastiCache::Client.new(client_options(region))
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def self.auth_with_iam
|
67
|
+
@credentials = Aws::SharedCredentials.new(profile_name: @environment)
|
68
|
+
iam = Aws::IAM::Client.new(client_options)
|
15
69
|
|
16
70
|
# this will be an array of 0 or 1 because iam.list_mfa_devices.mfa_devices will only return 0 or 1 device per user;
|
17
71
|
# if user doesn't have MFA enabled, then this loop won't even execute
|
18
72
|
iam.list_mfa_devices.mfa_devices.each do |mfadevice|
|
19
|
-
|
73
|
+
auth_with_mfa(mfadevice)
|
20
74
|
end
|
21
75
|
end
|
22
76
|
|
23
|
-
def self.
|
77
|
+
def self.auth_with_mfa(mfadevice)
|
24
78
|
mfa_serial_number = mfadevice.serial_number
|
25
79
|
mfa_token = Output.ask("Enter MFA token: "){ |q| q.validate = /^\d{6}$/ }
|
26
|
-
session_credentials_hash = get_session(mfa_token,
|
27
|
-
mfa_serial_number,
|
28
|
-
shared_credentials.credentials.access_key_id,
|
29
|
-
shared_credentials.credentials.secret_access_key).credentials
|
80
|
+
session_credentials_hash = get_session(mfa_token, mfa_serial_number).credentials
|
30
81
|
|
31
|
-
|
82
|
+
@credentials = Aws::Credentials.new(session_credentials_hash.access_key_id,
|
32
83
|
session_credentials_hash.secret_access_key,
|
33
84
|
session_credentials_hash.session_token)
|
34
|
-
update_aws_config({region: 'us-east-1', credentials: session_credentials})
|
35
85
|
end
|
36
86
|
|
37
|
-
def self.
|
87
|
+
def self.auth_with_assumed_roles(arn_id, role_name)
|
38
88
|
role_arn = "arn:aws:iam::#{arn_id}:role/#{role_name}"
|
39
89
|
session_name = "auditor#{Time.now.to_i}"
|
40
|
-
|
41
|
-
role_arn: role_arn,
|
42
|
-
role_session_name: session_name)
|
43
|
-
update_aws_config({region: 'us-east-1', credentials: assumed_role_credentials})
|
44
|
-
return assumed_role_credentials
|
90
|
+
@credentials = Aws::AssumeRoleCredentials.new(client: sts_for_instance, role_arn: role_arn, role_session_name: session_name)
|
45
91
|
end
|
46
92
|
|
47
|
-
def self.get_session(mfa_token, mfa_serial_number
|
93
|
+
def self.get_session(mfa_token, mfa_serial_number)
|
48
94
|
return @session if @session
|
49
|
-
|
50
|
-
secret_access_key: secret_access_key,
|
51
|
-
region: 'us-east-1')
|
52
|
-
@session = sts.get_session_token(duration_seconds: 3600,
|
53
|
-
serial_number: mfa_serial_number,
|
54
|
-
token_code: mfa_token)
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.update_aws_config(options)
|
58
|
-
Aws.config.update(options)
|
95
|
+
@session = sts_for_instance.get_session_token(duration_seconds: 3600, serial_number: mfa_serial_number, token_code: mfa_token)
|
59
96
|
end
|
97
|
+
|
60
98
|
end
|
61
99
|
end
|
@@ -1,21 +1,19 @@
|
|
1
|
-
|
1
|
+
require 'sport_ngin_aws_auditor/instance_helper'
|
2
2
|
|
3
3
|
module SportNginAwsAuditor
|
4
4
|
class CacheInstance
|
5
5
|
extend InstanceHelper
|
6
|
-
extend CacheWrapper
|
7
|
-
extend AWSWrapper
|
8
6
|
|
9
7
|
class << self
|
10
|
-
def get_instances(client, tag_name=nil)
|
11
|
-
account_id = get_account_id
|
8
|
+
def get_instances(client=AWS.cache, tag_name=nil)
|
9
|
+
account_id = AWS.get_account_id
|
12
10
|
client.describe_cache_clusters.cache_clusters.map do |instance|
|
13
11
|
next unless instance.cache_cluster_status.to_s == 'available'
|
14
12
|
new(instance, account_id, tag_name, client)
|
15
13
|
end.compact
|
16
14
|
end
|
17
15
|
|
18
|
-
def get_reserved_instances(client)
|
16
|
+
def get_reserved_instances(client=AWS.cache)
|
19
17
|
client.describe_reserved_cache_nodes.reserved_cache_nodes.map do |instance|
|
20
18
|
next unless instance.state.to_s == 'active'
|
21
19
|
new(instance)
|
@@ -15,7 +15,7 @@ command 'audit' do |c|
|
|
15
15
|
one of these strings in the name,
|
16
16
|
pass in like: string1, string2, string3"
|
17
17
|
c.action do |global_options, options, args|
|
18
|
-
|
18
|
+
require 'sport_ngin_aws_auditor/scripts/audit'
|
19
19
|
raise ArgumentError, 'You must specify an AWS account' unless args.first
|
20
20
|
SportNginAwsAuditor::Scripts::Audit.execute(args.first, options, global_options)
|
21
21
|
end
|
@@ -4,7 +4,7 @@ command 'export' do |c|
|
|
4
4
|
c.switch [:c, :csv], :desc => "Exports to CSV"
|
5
5
|
c.switch [:d, :drive], :desc => "Exports to Google Drive"
|
6
6
|
c.action do |global_options, options, args|
|
7
|
-
|
7
|
+
require 'sport_ngin_aws_auditor/scripts/export'
|
8
8
|
raise ArgumentError, 'You must specify an AWS account' unless args.first
|
9
9
|
SportNginAwsAuditor::Scripts::Export.execute(args.first, options, global_options)
|
10
10
|
end
|
@@ -5,7 +5,7 @@ command 'inspect' do |c|
|
|
5
5
|
c.switch [:d, :rds], :desc => "Only inspect RDS instances"
|
6
6
|
c.switch [:c, :cache], :desc => "Only inspect ElastiCache instances"
|
7
7
|
c.action do |global_options, options, args|
|
8
|
-
|
8
|
+
require 'sport_ngin_aws_auditor/scripts/inspect'
|
9
9
|
raise ArgumentError, 'You must specify an AWS account' unless args.first
|
10
10
|
SportNginAwsAuditor::Scripts::Inspect.execute(args.first,options, global_options)
|
11
11
|
end
|
@@ -1,92 +1,4 @@
|
|
1
|
-
require_relative './aws'
|
2
|
-
require 'aws-sdk'
|
3
|
-
require_relative './google'
|
4
|
-
|
5
1
|
module SportNginAwsAuditor
|
6
|
-
attr_accessor :assume_role_creds
|
7
|
-
|
8
|
-
module AWSWrapper
|
9
|
-
def aws(environment, global_options)
|
10
|
-
if global_options[:aws_roles]
|
11
|
-
SportNginAwsAuditor::AWSSDK.update_aws_config({region: 'us-east-1'})
|
12
|
-
elsif global_options[:assume_roles]
|
13
|
-
@assume_role_creds = SportNginAwsAuditor::AWSSDK.authenticate_with_assumed_roles(environment,
|
14
|
-
global_options[:arn_id],
|
15
|
-
global_options[:role_name],
|
16
|
-
get_sts_client(environment))
|
17
|
-
else
|
18
|
-
SportNginAwsAuditor::AWSSDK.authenticate_with_iam(environment)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def get_account_id
|
23
|
-
Aws::STS::Client.new.get_caller_identity.account
|
24
|
-
end
|
25
|
-
|
26
|
-
def get_sts_client(environment)
|
27
|
-
@sts_client ||= Aws::STS::Client.new(profile: environment, region: 'us-east-1')
|
28
|
-
end
|
29
|
-
|
30
|
-
def reset_credentials
|
31
|
-
SportNginAwsAuditor::AWSSDK.update_aws_config({credentials: Aws::InstanceProfileCredentials.new})
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
module EC2Wrapper
|
36
|
-
def self.ec2(region=nil)
|
37
|
-
if @assume_role_creds && region
|
38
|
-
@ec2 = Aws::EC2::Client.new(credentials: @assume_role_creds, region: region)
|
39
|
-
elsif @assume_role_creds && !region
|
40
|
-
@ec2 = Aws::EC2::Client.new(credentials: @assume_role_creds)
|
41
|
-
elsif @assume_role_creds.nil? && region
|
42
|
-
@ec2 = Aws::EC2::Client.new(region: region)
|
43
|
-
else
|
44
|
-
@ec2 = Aws::EC2::Client.new
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
module OpsWorksWrapper
|
50
|
-
attr_accessor :opsworks
|
51
|
-
|
52
|
-
def opsworks
|
53
|
-
return @opsworks if @opsworks
|
54
|
-
if @assume_role_creds
|
55
|
-
@opsworks = Aws::Opsworks::Client.new(credentials: @assume_role_creds)
|
56
|
-
else
|
57
|
-
@opsworks = Aws::OpsWorks::Client.new
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
module RDSWrapper
|
63
|
-
def self.rds(region=nil)
|
64
|
-
if @assume_role_creds && region
|
65
|
-
@rds = Aws::RDS::Client.new(credentials: @assume_role_creds, region: region)
|
66
|
-
elsif @assume_role_creds && !region
|
67
|
-
@rds = Aws::RDS::Client.new(credentials: @assume_role_creds)
|
68
|
-
elsif @assume_role_creds.nil? && region
|
69
|
-
@rds = Aws::RDS::Client.new(region: region)
|
70
|
-
else
|
71
|
-
@rds = Aws::RDS::Client.new
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
module CacheWrapper
|
77
|
-
def self.cache(region=nil)
|
78
|
-
if @assume_role_creds && region
|
79
|
-
@cache = Aws::ElastiCache::Client.new(credentials: @assume_role_creds, region: region)
|
80
|
-
elsif @assume_role_creds && !region
|
81
|
-
@cache = Aws::ElastiCache::Client.new(credentials: @assume_role_creds)
|
82
|
-
elsif @assume_role_creds.nil? && region
|
83
|
-
@cache = Aws::ElastiCache::Client.new(region: region)
|
84
|
-
else
|
85
|
-
@cache = Aws::ElastiCache::Client.new
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
2
|
module GoogleWrapper
|
91
3
|
attr_accessor :google
|
92
4
|
|
@@ -1,12 +1,9 @@
|
|
1
|
-
require_relative './instance_helper'
|
2
|
-
|
3
1
|
module SportNginAwsAuditor
|
4
2
|
class EC2Instance
|
5
3
|
extend InstanceHelper
|
6
|
-
extend EC2Wrapper
|
7
4
|
|
8
5
|
class << self
|
9
|
-
def get_instances(client, tag_name=nil)
|
6
|
+
def get_instances(client=AWS.ec2, tag_name=nil)
|
10
7
|
instances = client.describe_instances.reservations.map do |reservation|
|
11
8
|
reservation.instances.map do |instance|
|
12
9
|
next unless instance.state.name == 'running'
|
@@ -16,7 +13,7 @@ module SportNginAwsAuditor
|
|
16
13
|
get_more_info(instances, client)
|
17
14
|
end
|
18
15
|
|
19
|
-
def get_reserved_instances(client)
|
16
|
+
def get_reserved_instances(client=AWS.ec2)
|
20
17
|
client.describe_reserved_instances.reserved_instances.map do |instance|
|
21
18
|
next unless instance.state == 'active'
|
22
19
|
new(instance, nil, instance.instance_count)
|
@@ -1,21 +1,17 @@
|
|
1
|
-
require_relative './instance_helper'
|
2
|
-
|
3
1
|
module SportNginAwsAuditor
|
4
2
|
class RDSInstance
|
5
3
|
extend InstanceHelper
|
6
|
-
extend RDSWrapper
|
7
|
-
extend AWSWrapper
|
8
4
|
|
9
5
|
class << self
|
10
|
-
def get_instances(client, tag_name=nil)
|
11
|
-
account_id = get_account_id
|
6
|
+
def get_instances(client=AWS.rds, tag_name=nil)
|
7
|
+
account_id = AWS.get_account_id
|
12
8
|
client.describe_db_instances.db_instances.map do |instance|
|
13
9
|
next unless instance.db_instance_status.to_s == 'available'
|
14
10
|
new(instance, account_id, tag_name, client)
|
15
11
|
end.compact
|
16
12
|
end
|
17
13
|
|
18
|
-
def get_reserved_instances(client)
|
14
|
+
def get_reserved_instances(client=AWS.rds)
|
19
15
|
client.describe_reserved_db_instances.reserved_db_instances.map do |instance|
|
20
16
|
next unless instance.state.to_s == 'active'
|
21
17
|
new(instance)
|
@@ -3,13 +3,9 @@ require 'colorize'
|
|
3
3
|
require 'aws-sdk'
|
4
4
|
require_relative "../notify_slack"
|
5
5
|
require_relative "../instance"
|
6
|
-
require_relative "../audit_data"
|
7
|
-
|
8
6
|
module SportNginAwsAuditor
|
9
7
|
module Scripts
|
10
8
|
class Audit
|
11
|
-
extend AWSWrapper
|
12
|
-
|
13
9
|
class << self
|
14
10
|
attr_accessor :options, :audit_results
|
15
11
|
end
|
@@ -18,11 +14,10 @@ module SportNginAwsAuditor
|
|
18
14
|
|
19
15
|
def self.execute(environment, options, global_options)
|
20
16
|
begin
|
21
|
-
|
17
|
+
AWS.configure(environment, global_options)
|
22
18
|
collect_options(environment, options, global_options)
|
23
19
|
print_title
|
24
20
|
@regions.each { |region| audit_region(region) }
|
25
|
-
reset_credentials
|
26
21
|
rescue StandardError => e
|
27
22
|
if options[:slack]
|
28
23
|
NotifySlack.new("Sorry, something seems to have gone wrong.", options[:config_json]).perform
|
@@ -232,8 +227,7 @@ module SportNginAwsAuditor
|
|
232
227
|
#################### OTHER HELPFUL METHODS ####################
|
233
228
|
|
234
229
|
def self.gather_regions
|
235
|
-
|
236
|
-
regions = ec2.describe_regions[:regions]
|
230
|
+
regions = AWS.ec2.describe_regions[:regions]
|
237
231
|
us_regions = regions.select { |region| region.region_name.include?("us") }
|
238
232
|
us_regions.collect { |r| r.region_name }
|
239
233
|
end
|
@@ -1,11 +1,9 @@
|
|
1
1
|
require 'csv'
|
2
|
-
require_relative "../google"
|
3
2
|
|
4
3
|
module SportNginAwsAuditor
|
5
4
|
module Scripts
|
6
5
|
class Export
|
7
6
|
extend GoogleWrapper
|
8
|
-
extend AWSWrapper
|
9
7
|
|
10
8
|
class << self
|
11
9
|
attr_accessor :ec2_instances, :rds_instances, :cache_instances, :options, :file, :keys_hash, :environment
|
@@ -16,7 +14,7 @@ module SportNginAwsAuditor
|
|
16
14
|
def self.execute(environment, options = nil, global_options = nil)
|
17
15
|
@environment = environment
|
18
16
|
(puts "Must specify either --drive or --csv"; exit) unless options[:csv] || options[:drive]
|
19
|
-
|
17
|
+
AWS.configure(environment, global_options)
|
20
18
|
print "Gathering info, please wait..."
|
21
19
|
all_keys = get_all_keys
|
22
20
|
all_info = prepare
|
@@ -78,7 +76,7 @@ module SportNginAwsAuditor
|
|
78
76
|
|
79
77
|
def self.ec2_array
|
80
78
|
instance_array = [{name: "OPSWORKS"}]
|
81
|
-
EC2Instance.bucketize.map do |stack_name, stack_instances|
|
79
|
+
EC2Instance.bucketize(AWS.ec2).map do |stack_name, stack_instances|
|
82
80
|
instance_array << {:name => stack_name}.merge(EC2Instance.instance_count_hash(stack_instances))
|
83
81
|
end
|
84
82
|
instance_array
|
@@ -112,33 +110,33 @@ module SportNginAwsAuditor
|
|
112
110
|
klass = SportNginAwsAuditor.const_get(class_type)
|
113
111
|
instances = klass.instance_count_hash(klass.get_instances) if options[:instance]
|
114
112
|
instances = klass.instance_count_hash(klass.get_reserved_instances) if options[:reserved]
|
115
|
-
instances = klass.compare if options[:compare]
|
113
|
+
instances = klass.compare if options[:compare] #TODO fix me
|
116
114
|
instances
|
117
115
|
end.inject(:merge)
|
118
116
|
end
|
119
117
|
|
120
118
|
def self.ec2_instances
|
121
|
-
@ec2_instances ||= EC2Instance.instance_hash
|
119
|
+
@ec2_instances ||= EC2Instance.instance_hash(AWS.ec2)
|
122
120
|
end
|
123
121
|
|
124
122
|
def self.ec2_reserved_instances
|
125
|
-
@ec2_reserved_instances ||= EC2Instance.reserved_instance_hash
|
123
|
+
@ec2_reserved_instances ||= EC2Instance.reserved_instance_hash(AWS.ec2)
|
126
124
|
end
|
127
125
|
|
128
126
|
def self.rds_instances
|
129
|
-
@rds_instances ||= RDSInstance.instance_hash
|
127
|
+
@rds_instances ||= RDSInstance.instance_hash(AWS.rds)
|
130
128
|
end
|
131
129
|
|
132
130
|
def self.rds_reserved_instances
|
133
|
-
@rds_reserved_instances ||= RDSInstance.reserved_instance_hash
|
131
|
+
@rds_reserved_instances ||= RDSInstance.reserved_instance_hash(AWS.rds)
|
134
132
|
end
|
135
133
|
|
136
134
|
def self.cache_instances
|
137
|
-
@cache_instances ||= CacheInstance.instance_hash
|
135
|
+
@cache_instances ||= CacheInstance.instance_hash(AWS.cache)
|
138
136
|
end
|
139
137
|
|
140
138
|
def self.cache_reserved_instances
|
141
|
-
@cache_reserved_instances ||= CacheInstance.reserved_instance_hash
|
139
|
+
@cache_reserved_instances ||= CacheInstance.reserved_instance_hash(AWS.cache)
|
142
140
|
end
|
143
141
|
|
144
142
|
end
|
@@ -1,14 +1,9 @@
|
|
1
1
|
module SportNginAwsAuditor
|
2
2
|
module Scripts
|
3
3
|
class Inspect
|
4
|
-
extend AWSWrapper
|
5
|
-
extend OpsWorksWrapper
|
6
|
-
extend EC2Wrapper
|
7
|
-
extend RDSWrapper
|
8
|
-
extend CacheWrapper
|
9
4
|
|
10
5
|
def self.execute(environment, options=nil, global_options=nil)
|
11
|
-
|
6
|
+
AWS.configure(environment, global_options)
|
12
7
|
region = (global_options[:region].split(', ') if global_options[:region]) || 'us-east-1'
|
13
8
|
no_selection = options.values.uniq == [false]
|
14
9
|
output("EC2Instance", region) if options[:ec2] || no_selection
|
@@ -20,16 +15,16 @@ module SportNginAwsAuditor
|
|
20
15
|
klass = SportNginAwsAuditor.const_get(class_type)
|
21
16
|
|
22
17
|
if class_type == "EC2Instance"
|
23
|
-
client =
|
18
|
+
client = AWS.ec2(region)
|
24
19
|
elsif class_type == "RDSInstance"
|
25
|
-
client =
|
20
|
+
client = AWS.rds(region)
|
26
21
|
elsif class_type == "CacheInstance"
|
27
|
-
client =
|
22
|
+
client = AWS.cache(region)
|
28
23
|
end
|
29
24
|
|
30
25
|
print "Gathering info, please wait..."; print "\r"
|
31
26
|
instances = class_type == "EC2Instance" ? klass.bucketize(client) : klass.instance_hash(client)
|
32
|
-
say "<%= color('#{header(class_type)}', :white) %>"
|
27
|
+
Output.say "<%= color('#{header(class_type)}', :white) %>"
|
33
28
|
instances.each do |key, value|
|
34
29
|
pretty_print(key, klass.instance_count_hash(Array(value)))
|
35
30
|
end
|
@@ -49,7 +44,7 @@ module SportNginAwsAuditor
|
|
49
44
|
puts "======================================="
|
50
45
|
puts "#{title}"
|
51
46
|
puts "======================================="
|
52
|
-
body.each{ |key, value| say "<%= color('#{key}: #{value[:count]}', :white) %>" }
|
47
|
+
body.each{ |key, value| Output.say "<%= color('#{key}: #{value[:count]}', :white) %>" }
|
53
48
|
puts "\n"
|
54
49
|
end
|
55
50
|
end
|
@@ -1,14 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
require 'sport_ngin_aws_auditor/audit_data'
|
2
|
+
require 'sport_ngin_aws_auditor/aws'
|
3
|
+
require 'sport_ngin_aws_auditor/cache_instance'
|
4
|
+
require 'sport_ngin_aws_auditor/config'
|
5
|
+
require 'sport_ngin_aws_auditor/convenience_wrappers'
|
6
|
+
require 'sport_ngin_aws_auditor/ec2_instance'
|
7
|
+
require 'sport_ngin_aws_auditor/google'
|
8
|
+
require 'sport_ngin_aws_auditor/google_sheet'
|
9
|
+
require 'sport_ngin_aws_auditor/instance'
|
10
|
+
require 'sport_ngin_aws_auditor/instance_helper'
|
11
|
+
require 'sport_ngin_aws_auditor/notify_slack'
|
12
|
+
require 'sport_ngin_aws_auditor/output'
|
13
|
+
require 'sport_ngin_aws_auditor/rds_instance'
|
14
|
+
require 'sport_ngin_aws_auditor/recently_retired_tag'
|
15
|
+
require 'sport_ngin_aws_auditor/version'
|
12
16
|
|
13
17
|
module SportNginAwsAuditor
|
14
18
|
|
@@ -24,6 +24,7 @@ module SportNginAwsAuditor
|
|
24
24
|
'instance2' => 1})
|
25
25
|
allow(SportNginAwsAuditor::EC2Instance).to receive(:get_recent_retired_reserved_instances).and_return(@retired_ris)
|
26
26
|
allow(Instance).to receive(:new).and_return(@instance)
|
27
|
+
allow(SportNginAwsAuditor::AWS).to receive(:client_options).and_return(region: 'us-east-1', credentials: {})
|
27
28
|
end
|
28
29
|
|
29
30
|
context '#initialization' do
|
@@ -1,29 +1,34 @@
|
|
1
1
|
require "sport_ngin_aws_auditor"
|
2
2
|
|
3
3
|
module SportNginAwsAuditor
|
4
|
-
describe
|
5
|
-
|
4
|
+
describe AWS do
|
5
|
+
before do
|
6
|
+
AWS.reset
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'shared credentials file without mfa' do
|
6
10
|
before :each do
|
7
11
|
mfa_devices = double('mfa_devices', mfa_devices: [])
|
8
12
|
iam_client = double('iam_client', list_mfa_devices: mfa_devices)
|
9
13
|
allow(Aws::IAM::Client).to receive(:new).and_return(iam_client)
|
14
|
+
AWS.configure('staging', {})
|
10
15
|
end
|
11
16
|
|
12
17
|
it "should receive new Aws::SharedCredentials" do
|
13
|
-
expect(Aws::SharedCredentials).to receive(:new).with(profile_name: 'staging')
|
14
|
-
|
18
|
+
expect(Aws::SharedCredentials).to receive(:new).with(profile_name: 'staging').and_call_original
|
19
|
+
AWS.auth_with_iam
|
15
20
|
end
|
16
21
|
|
17
|
-
it "should
|
22
|
+
it "should set credentials" do
|
18
23
|
coffee_types = {:coffee => "cappuccino", :beans => "arabica"}
|
19
24
|
allow(Aws::SharedCredentials).to receive(:new).and_return(coffee_types)
|
20
|
-
|
21
|
-
|
25
|
+
AWS.auth_with_iam
|
26
|
+
expect(AWS.credentials).to_not be_nil
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
25
|
-
context 'with mfa
|
26
|
-
it "should use MFA
|
30
|
+
context 'shared credentials file with mfa' do
|
31
|
+
it "should use MFA when user has device configured" do
|
27
32
|
shared_credentials = double('shared_credentials', access_key_id: 'access_key_id',
|
28
33
|
secret_access_key: 'secret_access_key')
|
29
34
|
shared_creds = double('shared_creds', credentials: shared_credentials)
|
@@ -41,18 +46,20 @@ module SportNginAwsAuditor
|
|
41
46
|
|
42
47
|
expect(Aws::Credentials).to receive(:new).and_return(cred_double).at_least(:once)
|
43
48
|
expect(Aws::SharedCredentials).to receive(:new).and_return(shared_creds)
|
44
|
-
|
49
|
+
AWS.auth_with_iam
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
48
|
-
context
|
49
|
-
it "should
|
50
|
-
|
51
|
-
|
53
|
+
context "using AWS server role" do
|
54
|
+
it "should configure SDK integration and return client" do
|
55
|
+
AWS.configure('staging', aws_roles: true)
|
56
|
+
expect(AWS.environment).to eq('staging')
|
57
|
+
expect(AWS.credentials).to be_nil
|
58
|
+
expect(AWS.ec2).to_not be_nil
|
52
59
|
end
|
53
60
|
end
|
54
61
|
|
55
|
-
context '
|
62
|
+
context 'using cross account assumed roles' do
|
56
63
|
before :each do
|
57
64
|
cred_double = double('cred_hash', access_key_id: 'access_key_id',
|
58
65
|
secret_access_key: 'secret_access_key',
|
@@ -63,14 +70,9 @@ module SportNginAwsAuditor
|
|
63
70
|
allow(Aws::AssumeRoleCredentials).to receive(:new).and_return(cred_double)
|
64
71
|
end
|
65
72
|
|
66
|
-
it "should
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should call for some credentials" do
|
72
|
-
expect(Aws::AssumeRoleCredentials).to receive(:new)
|
73
|
-
AWSSDK::authenticate_with_assumed_roles('staging', '999999999999', 'CrossAccountAuditorAccess', @sts)
|
73
|
+
it "should set credentials" do
|
74
|
+
AWS.auth_with_assumed_roles('999999999999', 'CrossAccountAuditorAccess')
|
75
|
+
expect(AWS.credentials).to_not be_nil
|
74
76
|
end
|
75
77
|
end
|
76
78
|
end
|
@@ -8,6 +8,7 @@ module SportNginAwsAuditor
|
|
8
8
|
client = double('client', get_caller_identity: identity)
|
9
9
|
allow(Aws::STS::Client).to receive(:new).and_return(client)
|
10
10
|
# @client = Aws::ElastiCache::Client.new(region: 'us-east-1')
|
11
|
+
allow(SportNginAwsAuditor::AWS).to receive(:client_options).and_return(region: 'us-east-1', credentials: {})
|
11
12
|
end
|
12
13
|
|
13
14
|
after :each do
|
@@ -7,6 +7,7 @@ module SportNginAwsAuditor
|
|
7
7
|
identity = double('identity', account: 123456789)
|
8
8
|
client = double('client', get_caller_identity: identity)
|
9
9
|
allow(Aws::STS::Client).to receive(:new).and_return(client)
|
10
|
+
allow(SportNginAwsAuditor::AWS).to receive(:client_options).and_return(region: 'us-east-1', credentials: {})
|
10
11
|
end
|
11
12
|
|
12
13
|
after :each do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sport_ngin_aws_auditor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elliot Hursh
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-03-
|
13
|
+
date: 2017-03-07 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: aws-sdk
|
@@ -238,7 +238,6 @@ files:
|
|
238
238
|
- lib/sport_ngin_aws_auditor/scripts/audit.rb
|
239
239
|
- lib/sport_ngin_aws_auditor/scripts/export.rb
|
240
240
|
- lib/sport_ngin_aws_auditor/scripts/inspect.rb
|
241
|
-
- lib/sport_ngin_aws_auditor/stack.rb
|
242
241
|
- lib/sport_ngin_aws_auditor/version.rb
|
243
242
|
- spec/spec_helper.rb
|
244
243
|
- spec/sport_ngin_aws_auditor/audit_data_spec.rb
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'highline/import'
|
2
|
-
|
3
|
-
module SportNginAwsAuditor
|
4
|
-
class Stack
|
5
|
-
extend OpsWorksWrapper
|
6
|
-
extend EC2Wrapper
|
7
|
-
|
8
|
-
class << self
|
9
|
-
attr_accessor :instances, :stacks
|
10
|
-
end
|
11
|
-
|
12
|
-
attr_accessor :id, :name, :instances
|
13
|
-
def initialize(aws_stack)
|
14
|
-
@id = aws_stack[:stack_id]
|
15
|
-
@name = aws_stack[:name]
|
16
|
-
@instances = get_instances.compact
|
17
|
-
end
|
18
|
-
|
19
|
-
def get_instances
|
20
|
-
return @instances if @instances
|
21
|
-
@instances = self.class.opsworks.describe_instances({stack_id: id})[:instances].map do |instance|
|
22
|
-
next unless instance[:status].to_s == 'online'
|
23
|
-
self.class.all_instances[instance[:ec2_instance_id]].stack_id = id
|
24
|
-
self.class.all_instances[instance[:ec2_instance_id]]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def print_instances
|
29
|
-
EC2Instance.instance_count_hash(self.instances).each do |key,value|
|
30
|
-
say "<%= color('#{key}: #{value}', :white) %>"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def pretty_print
|
35
|
-
puts "----------------------------------"
|
36
|
-
puts "#{@name}"
|
37
|
-
puts "----------------------------------"
|
38
|
-
print_instances
|
39
|
-
puts "\n"
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.all
|
43
|
-
return @stacks if @stacks
|
44
|
-
@stacks = opsworks.describe_stacks.data[:stacks].map do |stack|
|
45
|
-
new(stack)
|
46
|
-
end.sort! { |a,b| a.name.downcase <=> b.name.downcase }
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.all_instances
|
50
|
-
@all_instances ||= EC2Instance.instance_hash
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.instances_without_stack
|
54
|
-
all #simply getting all stacks to make sure instance stack_ids is set
|
55
|
-
all_instances.map do |id, instance|
|
56
|
-
next if instance.stack_id
|
57
|
-
instance
|
58
|
-
end.compact
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|