aws_recon 0.5.0 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/check-aws-regions.yml +18 -0
- data/aws_recon.gemspec +1 -1
- data/lib/aws_recon/collectors/ec2.rb +18 -18
- data/lib/aws_recon/collectors/iam.rb +1 -1
- data/lib/aws_recon/options.rb +2 -2
- data/lib/aws_recon/services.yaml +3 -12
- data/lib/aws_recon/version.rb +1 -1
- data/readme.md +5 -5
- data/utils/aws/check_region_exclusions.rb +112 -0
- data/utils/aws/regions.yaml +43 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7574ac2a2ffd096dae78183fe03998f59540d1f9672724b2e705894fc0fb5da
|
4
|
+
data.tar.gz: 1af2a00fa0e5a656f36b3966ada67b1c898763ecf2018a0dd087f2d7214d0506
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e00e5416344bd5964e43b81677c90e483b522d5b116c7607f08215d83037088f67d8bd614979d3d056506d1c8a940108cf97ef2e2dddd0566c593d52fb1f56b
|
7
|
+
data.tar.gz: 49903877096060c68333b68022a7badde671183775b08b03efcc16e4c8967ab148903bd69e9e9eb7a0860350acafbb051d3aee2186e68667c6ed9b4075212f2b
|
@@ -0,0 +1,18 @@
|
|
1
|
+
name: check-service-regions
|
2
|
+
|
3
|
+
on:
|
4
|
+
workflow_dispatch:
|
5
|
+
schedule:
|
6
|
+
- cron: '0 10 * * *'
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
region-check:
|
10
|
+
runs-on: ubuntu-20.04
|
11
|
+
steps:
|
12
|
+
- name: Checkout
|
13
|
+
uses: actions/checkout@v2
|
14
|
+
with:
|
15
|
+
fetch-depth: 1
|
16
|
+
- name: Check AWS service regions
|
17
|
+
run: |
|
18
|
+
cd utils/aws ; ruby check_region_exclusions.rb
|
data/aws_recon.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.name = 'aws_recon'
|
9
9
|
spec.version = AwsRecon::VERSION
|
10
10
|
spec.authors = ['Josh Larsen', 'Darkbit']
|
11
|
-
spec.required_ruby_version = '>= 2.
|
11
|
+
spec.required_ruby_version = '>= 2.6.0'
|
12
12
|
spec.summary = 'A multi-threaded AWS security-focused inventory collection tool.'
|
13
13
|
spec.description = 'AWS Recon is a command line tool to collect resources from an Amazon Web Services (AWS) account. The tool outputs JSON suitable for processing with other tools.'
|
14
14
|
spec.homepage = 'https://github.com/darkbitio/aws-recon'
|
@@ -29,7 +29,7 @@ class EC2 < Mapper
|
|
29
29
|
struct = OpenStruct.new
|
30
30
|
struct.attributes = response.account_attributes.map(&:to_h)
|
31
31
|
struct.type = 'account'
|
32
|
-
struct.arn = "arn:aws:ec2::#{@account}/account_attributes"
|
32
|
+
struct.arn = "arn:aws:ec2::#{@account}:attributes/account_attributes"
|
33
33
|
|
34
34
|
resources.push(struct.to_h)
|
35
35
|
end
|
@@ -45,7 +45,7 @@ class EC2 < Mapper
|
|
45
45
|
|
46
46
|
struct = OpenStruct.new(response.to_h)
|
47
47
|
struct.type = 'ebs_encryption_settings'
|
48
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/ebs_encryption_settings"
|
48
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:settings/ebs_encryption_settings"
|
49
49
|
|
50
50
|
resources.push(struct.to_h)
|
51
51
|
end
|
@@ -64,7 +64,7 @@ class EC2 < Mapper
|
|
64
64
|
reservation.instances.each do |instance|
|
65
65
|
struct = OpenStruct.new(instance.to_h)
|
66
66
|
struct.type = 'instance'
|
67
|
-
struct.arn = instance.instance_id # no true ARN
|
67
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:instance/#{instance.instance_id}" # no true ARN
|
68
68
|
struct.reservation_id = reservation.reservation_id
|
69
69
|
|
70
70
|
# collect instance user_data
|
@@ -96,7 +96,7 @@ class EC2 < Mapper
|
|
96
96
|
response.vpcs.each do |vpc|
|
97
97
|
struct = OpenStruct.new(vpc.to_h)
|
98
98
|
struct.type = 'vpc'
|
99
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{vpc.vpc_id}" # no true ARN
|
99
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:vpc/#{vpc.vpc_id}" # no true ARN
|
100
100
|
struct.flow_logs = @client
|
101
101
|
.describe_flow_logs({ filter: [{ name: 'resource-id', values: [vpc.vpc_id] }] })
|
102
102
|
.flow_logs.first.to_h
|
@@ -114,7 +114,7 @@ class EC2 < Mapper
|
|
114
114
|
response.security_groups.each do |security_group|
|
115
115
|
struct = OpenStruct.new(security_group.to_h)
|
116
116
|
struct.type = 'security_group'
|
117
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{security_group.group_id}" # no true ARN
|
117
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:security_group/#{security_group.group_id}" # no true ARN
|
118
118
|
|
119
119
|
resources.push(struct.to_h)
|
120
120
|
end
|
@@ -129,7 +129,7 @@ class EC2 < Mapper
|
|
129
129
|
response.network_interfaces.each do |network_interface|
|
130
130
|
struct = OpenStruct.new(network_interface.to_h)
|
131
131
|
struct.type = 'network_interface'
|
132
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{network_interface.network_interface_id}" # no true ARN
|
132
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:network_interface/#{network_interface.network_interface_id}" # no true ARN
|
133
133
|
|
134
134
|
resources.push(struct.to_h)
|
135
135
|
end
|
@@ -144,7 +144,7 @@ class EC2 < Mapper
|
|
144
144
|
response.network_acls.each do |network_acl|
|
145
145
|
struct = OpenStruct.new(network_acl.to_h)
|
146
146
|
struct.type = 'network_acl'
|
147
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{network_acl.network_acl_id}" # no true ARN
|
147
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:network_acl/#{network_acl.network_acl_id}" # no true ARN
|
148
148
|
|
149
149
|
resources.push(struct.to_h)
|
150
150
|
end
|
@@ -159,7 +159,7 @@ class EC2 < Mapper
|
|
159
159
|
response.subnets.each do |subnet|
|
160
160
|
struct = OpenStruct.new(subnet.to_h)
|
161
161
|
struct.type = 'subnet'
|
162
|
-
struct.arn =
|
162
|
+
struct.arn = subnet.subnet_arn
|
163
163
|
|
164
164
|
resources.push(struct.to_h)
|
165
165
|
end
|
@@ -174,7 +174,7 @@ class EC2 < Mapper
|
|
174
174
|
response.addresses.each do |address|
|
175
175
|
struct = OpenStruct.new(address.to_h)
|
176
176
|
struct.type = 'eip_address'
|
177
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{address.allocation_id}" # no true ARN
|
177
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:eip_address/#{address.allocation_id}" # no true ARN
|
178
178
|
|
179
179
|
resources.push(struct.to_h)
|
180
180
|
end
|
@@ -189,7 +189,7 @@ class EC2 < Mapper
|
|
189
189
|
response.nat_gateways.each do |gateway|
|
190
190
|
struct = OpenStruct.new(gateway.to_h)
|
191
191
|
struct.type = 'nat_gateway'
|
192
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{gateway.nat_gateway_id}" # no true ARN
|
192
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:nat_gateway/#{gateway.nat_gateway_id}" # no true ARN
|
193
193
|
|
194
194
|
resources.push(struct.to_h)
|
195
195
|
end
|
@@ -204,7 +204,7 @@ class EC2 < Mapper
|
|
204
204
|
response.internet_gateways.each do |gateway|
|
205
205
|
struct = OpenStruct.new(gateway.to_h)
|
206
206
|
struct.type = 'internet_gateway'
|
207
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{gateway.internet_gateway_id}" # no true ARN
|
207
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:internet_gateway/#{gateway.internet_gateway_id}" # no true ARN
|
208
208
|
|
209
209
|
resources.push(struct.to_h)
|
210
210
|
end
|
@@ -219,7 +219,7 @@ class EC2 < Mapper
|
|
219
219
|
response.route_tables.each do |table|
|
220
220
|
struct = OpenStruct.new(table.to_h)
|
221
221
|
struct.type = 'route_table'
|
222
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{table.route_table_id}" # no true ARN
|
222
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:route_table/#{table.route_table_id}" # no true ARN
|
223
223
|
|
224
224
|
resources.push(struct.to_h)
|
225
225
|
end
|
@@ -234,7 +234,7 @@ class EC2 < Mapper
|
|
234
234
|
response.images.each do |image|
|
235
235
|
struct = OpenStruct.new(image.to_h)
|
236
236
|
struct.type = 'image'
|
237
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{image.image_id}" # no true ARN
|
237
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:image/#{image.image_id}" # no true ARN
|
238
238
|
|
239
239
|
resources.push(struct.to_h)
|
240
240
|
end
|
@@ -249,7 +249,7 @@ class EC2 < Mapper
|
|
249
249
|
response.snapshots.each do |snapshot|
|
250
250
|
struct = OpenStruct.new(snapshot.to_h)
|
251
251
|
struct.type = 'snapshot'
|
252
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{snapshot.snapshot_id}" # no true ARN
|
252
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:snapshot/#{snapshot.snapshot_id}" # no true ARN
|
253
253
|
struct.create_volume_permissions = @client.describe_snapshot_attribute({
|
254
254
|
attribute: 'createVolumePermission',
|
255
255
|
snapshot_id: snapshot.snapshot_id
|
@@ -268,7 +268,7 @@ class EC2 < Mapper
|
|
268
268
|
response.flow_logs.each do |flow_log|
|
269
269
|
struct = OpenStruct.new(flow_log.to_h)
|
270
270
|
struct.type = 'flow_log'
|
271
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{flow_log.flow_log_id}" # no true ARN
|
271
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:flow_log/#{flow_log.flow_log_id}" # no true ARN
|
272
272
|
|
273
273
|
resources.push(struct.to_h)
|
274
274
|
end
|
@@ -283,7 +283,7 @@ class EC2 < Mapper
|
|
283
283
|
response.volumes.each do |volume|
|
284
284
|
struct = OpenStruct.new(volume.to_h)
|
285
285
|
struct.type = 'volume'
|
286
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{volume.volume_id}" # no true ARN
|
286
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:volume/#{volume.volume_id}" # no true ARN
|
287
287
|
|
288
288
|
resources.push(struct.to_h)
|
289
289
|
end
|
@@ -298,7 +298,7 @@ class EC2 < Mapper
|
|
298
298
|
response.vpn_gateways.each do |gateway|
|
299
299
|
struct = OpenStruct.new(gateway.to_h)
|
300
300
|
struct.type = 'vpn_gateway'
|
301
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{gateway.vpn_gateway_id}" # no true ARN
|
301
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:vpn_gateway/#{gateway.vpn_gateway_id}" # no true ARN
|
302
302
|
|
303
303
|
resources.push(struct.to_h)
|
304
304
|
end
|
@@ -313,7 +313,7 @@ class EC2 < Mapper
|
|
313
313
|
response.vpc_peering_connections.each do |peer|
|
314
314
|
struct = OpenStruct.new(peer.to_h)
|
315
315
|
struct.type = 'peering_connection'
|
316
|
-
struct.arn = "arn:aws:ec2:#{@region}:#{@account}/#{peer.vpc_peering_connection_id}" # no true ARN
|
316
|
+
struct.arn = "arn:aws:ec2:#{@region}:#{@account}:peering_connection/#{peer.vpc_peering_connection_id}" # no true ARN
|
317
317
|
|
318
318
|
resources.push(struct.to_h)
|
319
319
|
end
|
data/lib/aws_recon/options.rb
CHANGED
@@ -36,8 +36,8 @@ class Parser
|
|
36
36
|
aws_regions = ['global'].concat(Aws::EC2::Client.new.describe_regions.regions.map(&:region_name))
|
37
37
|
end
|
38
38
|
rescue Aws::Errors::ServiceError => e
|
39
|
-
|
40
|
-
exit
|
39
|
+
warn "\nAWS Error: #{e.code}\n\n"
|
40
|
+
exit(1)
|
41
41
|
end
|
42
42
|
|
43
43
|
aws_services = YAML.load(File.read(SERVICES_CONFIG_FILE), symbolize_names: true)
|
data/lib/aws_recon/services.yaml
CHANGED
@@ -37,8 +37,6 @@
|
|
37
37
|
alias: ecs
|
38
38
|
- name: ElasticLoadBalancing
|
39
39
|
alias: elb
|
40
|
-
excluded_regions:
|
41
|
-
- ap-southeast-1
|
42
40
|
- name: ElasticLoadBalancingV2
|
43
41
|
alias: elbv2
|
44
42
|
- name: ElastiCache
|
@@ -85,15 +83,15 @@
|
|
85
83
|
- name: Shield
|
86
84
|
global: true
|
87
85
|
alias: shield
|
86
|
+
excluded_regions:
|
87
|
+
- ap-northeast-3
|
88
88
|
- name: CloudFormation
|
89
89
|
alias: cloudformation
|
90
90
|
- name: SES
|
91
91
|
alias: ses
|
92
92
|
excluded_regions:
|
93
|
-
- af-south-1
|
94
93
|
- ap-east-1
|
95
94
|
- ap-northeast-3
|
96
|
-
- eu-south-1
|
97
95
|
- name: CloudWatch
|
98
96
|
alias: cloudwatch
|
99
97
|
- name: CloudWatchLogs
|
@@ -106,9 +104,7 @@
|
|
106
104
|
- name: SecretsManager
|
107
105
|
alias: sm
|
108
106
|
- name: SecurityHub
|
109
|
-
alias:
|
110
|
-
excluded_regions:
|
111
|
-
- ap-northeast-3
|
107
|
+
alias: securityhub
|
112
108
|
- name: Support
|
113
109
|
global: true
|
114
110
|
alias: support
|
@@ -116,16 +112,12 @@
|
|
116
112
|
alias: ssm
|
117
113
|
- name: GuardDuty
|
118
114
|
alias: guardduty
|
119
|
-
excluded_regions:
|
120
|
-
- ap-northeast-3
|
121
115
|
- name: Athena
|
122
116
|
alias: athena
|
123
117
|
excluded_regions:
|
124
118
|
- ap-northeast-3
|
125
119
|
- name: EFS
|
126
120
|
alias: efs
|
127
|
-
excluded_regions:
|
128
|
-
- ap-northeast-3
|
129
121
|
- name: Firehose
|
130
122
|
alias: firehose
|
131
123
|
- name: Lightsail
|
@@ -145,7 +137,6 @@
|
|
145
137
|
- af-south-1
|
146
138
|
- ap-east-1
|
147
139
|
- ap-northeast-3
|
148
|
-
- ap-south-1
|
149
140
|
- eu-north-1
|
150
141
|
- eu-south-1
|
151
142
|
- eu-west-3
|
data/lib/aws_recon/version.rb
CHANGED
data/readme.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
[![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/darkbitio/aws-recon/smoke-test/main)](https://github.com/darkbitio/aws-recon/actions?query=branch%3Amain)
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/aws_recon.svg)](https://rubygems.org/gems/aws_recon)
|
3
|
-
|
3
|
+
[![AWS Service Regions](https://github.com/darkbitio/aws-recon/actions/workflows/check-aws-regions.yml/badge.svg?branch=main&event=schedule)](https://github.com/darkbitio/aws-recon/actions/workflows/check-aws-regions.yml)
|
4
4
|
# AWS Recon
|
5
5
|
|
6
6
|
A multi-threaded AWS security-focused inventory collection tool written in Ruby.
|
@@ -54,13 +54,13 @@ To run locally, first install the gem:
|
|
54
54
|
|
55
55
|
```
|
56
56
|
$ gem install aws_recon
|
57
|
-
Fetching aws_recon-0.
|
57
|
+
Fetching aws_recon-0.5.2.gem
|
58
58
|
Fetching aws-sdk-3.0.1.gem
|
59
59
|
Fetching parallel-1.20.1.gem
|
60
60
|
...
|
61
61
|
Successfully installed aws-sdk-3.0.1
|
62
62
|
Successfully installed parallel-1.20.1
|
63
|
-
Successfully installed aws_recon-0.
|
63
|
+
Successfully installed aws_recon-0.5.2
|
64
64
|
```
|
65
65
|
|
66
66
|
Or add it to your Gemfile using `bundle`:
|
@@ -72,7 +72,7 @@ Resolving dependencies...
|
|
72
72
|
...
|
73
73
|
Using aws-sdk 3.0.1
|
74
74
|
Using parallel-1.20.1
|
75
|
-
Using aws_recon 0.
|
75
|
+
Using aws_recon 0.5.2
|
76
76
|
```
|
77
77
|
|
78
78
|
## Usage
|
@@ -249,7 +249,7 @@ Most users will want to limit collection to relevant services and regions. Runni
|
|
249
249
|
```
|
250
250
|
$ aws_recon -h
|
251
251
|
|
252
|
-
AWS Recon - AWS Inventory Collector (0.
|
252
|
+
AWS Recon - AWS Inventory Collector (0.5.2)
|
253
253
|
|
254
254
|
Usage: aws_recon [options]
|
255
255
|
-r, --regions [REGIONS] Regions to scan, separated by comma (default: all)
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Check regional service availability against services.yaml exclusions.
|
5
|
+
#
|
6
|
+
# AWS updates the regional service table daily. By checking regional service
|
7
|
+
# coverage, we can identify regions that should be excluded from AWS Recon
|
8
|
+
# checks. We exclude non-supported regions because service APIs handle non-
|
9
|
+
# availability differently. Some will respond with an error that can be handled
|
10
|
+
# by the errors defined in the AWS Ruby SDK client. Others will fail at the
|
11
|
+
# network level (i.e. there is no API endpoint even available). We could handle
|
12
|
+
# those errors and silently fail, but we choose not to so we can identify cases
|
13
|
+
# where there is a lack of service availability in a particular region.
|
14
|
+
#
|
15
|
+
require 'net/http'
|
16
|
+
require 'json'
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
TS = Time.now.to_i
|
20
|
+
# AWS Regional services table
|
21
|
+
URL = "https://api.regional-table.region-services.aws.a2z.com/index.json?timestamp=#{TS}000"
|
22
|
+
|
23
|
+
service_to_query = ARGV[0]
|
24
|
+
region_exclusion_mistmatch = nil
|
25
|
+
|
26
|
+
#
|
27
|
+
# load current AWS Recon regions
|
28
|
+
#
|
29
|
+
recon_services = YAML.safe_load(File.read('../../lib/aws_recon/services.yaml'))
|
30
|
+
abort('Errors loading AWS Recon services') unless recon_services.is_a?(Array)
|
31
|
+
|
32
|
+
#
|
33
|
+
# load current AWS regions (non-gov, non-cn)
|
34
|
+
#
|
35
|
+
regions = YAML.safe_load(File.read('regions.yaml'))
|
36
|
+
abort('Errors loading regions') unless regions['Regions']
|
37
|
+
|
38
|
+
all_regions = regions['Regions'].map { |r| r['RegionName'] }
|
39
|
+
|
40
|
+
#
|
41
|
+
# get service/price list from AWS
|
42
|
+
#
|
43
|
+
uri = URI(URL)
|
44
|
+
res = Net::HTTP.get_response(uri)
|
45
|
+
abort('Error loading AWS services from API') unless res.code == '200'
|
46
|
+
|
47
|
+
map = {}
|
48
|
+
|
49
|
+
#
|
50
|
+
# load service region availability
|
51
|
+
#
|
52
|
+
data = res.body
|
53
|
+
json = JSON.parse(data)
|
54
|
+
|
55
|
+
#
|
56
|
+
# query regions for a single service
|
57
|
+
#
|
58
|
+
if service_to_query
|
59
|
+
single_service_regions = []
|
60
|
+
|
61
|
+
json['prices'].each do |p|
|
62
|
+
single_service_regions << p['id'].split(':').last
|
63
|
+
end
|
64
|
+
|
65
|
+
single_service_regions.uniq.sort.each { |r| puts r }
|
66
|
+
|
67
|
+
exit 0
|
68
|
+
end
|
69
|
+
|
70
|
+
# iterate through AWS provided services & regions
|
71
|
+
json['prices'].each do |p|
|
72
|
+
at = p['attributes']
|
73
|
+
service_name = at['aws:serviceName']
|
74
|
+
service_id, service_region = p['id'].split(':')
|
75
|
+
|
76
|
+
# skip this service unless AWS Recon already has exclusions
|
77
|
+
next unless recon_services.filter { |s| s['alias'] == service_id }&.length&.positive?
|
78
|
+
|
79
|
+
if map.key?(service_name)
|
80
|
+
map[service_name]['regions'] << service_region
|
81
|
+
else
|
82
|
+
map[service_name] = {
|
83
|
+
'id' => service_id,
|
84
|
+
'regions' => [service_region]
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# iterate through the services AWS Recon knows about
|
90
|
+
map.sort.each do |k, v|
|
91
|
+
service_excluded_regions = all_regions.reject { |r| v['regions'].include?(r) }
|
92
|
+
|
93
|
+
aws_recon_service = recon_services.filter { |s| s['alias'] == v['id'] }&.first
|
94
|
+
aws_recon_service_excluded_regions = aws_recon_service['excluded_regions'] || []
|
95
|
+
|
96
|
+
# move on if AWS Recon region exclusions match AWS service region exclusions
|
97
|
+
next unless service_excluded_regions.sort != aws_recon_service_excluded_regions.sort
|
98
|
+
|
99
|
+
region_exclusion_mistmatch = true
|
100
|
+
|
101
|
+
puts "#{k} (#{v['id']})"
|
102
|
+
|
103
|
+
# determine the direction of the exclusion mismatch
|
104
|
+
if (service_excluded_regions - aws_recon_service_excluded_regions).length.positive?
|
105
|
+
puts " + missing region exclusion: #{(service_excluded_regions - aws_recon_service_excluded_regions).join(', ')}"
|
106
|
+
else
|
107
|
+
puts " - unnecessary region exclusion: #{(aws_recon_service_excluded_regions - service_excluded_regions).join(', ')}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# exit code 1 if we have any mismatches
|
112
|
+
exit 1 if region_exclusion_mistmatch
|
@@ -0,0 +1,43 @@
|
|
1
|
+
Regions:
|
2
|
+
- Endpoint: ec2.af-south-1.amazonaws.com
|
3
|
+
RegionName: af-south-1
|
4
|
+
- Endpoint: ec2.eu-north-1.amazonaws.com
|
5
|
+
RegionName: eu-north-1
|
6
|
+
- Endpoint: ec2.ap-south-1.amazonaws.com
|
7
|
+
RegionName: ap-south-1
|
8
|
+
- Endpoint: ec2.eu-west-3.amazonaws.com
|
9
|
+
RegionName: eu-west-3
|
10
|
+
- Endpoint: ec2.eu-west-2.amazonaws.com
|
11
|
+
RegionName: eu-west-2
|
12
|
+
- Endpoint: ec2.eu-south-1.amazonaws.com
|
13
|
+
RegionName: eu-south-1
|
14
|
+
- Endpoint: ec2.eu-west-1.amazonaws.com
|
15
|
+
RegionName: eu-west-1
|
16
|
+
- Endpoint: ec2.ap-northeast-3.amazonaws.com
|
17
|
+
RegionName: ap-northeast-3
|
18
|
+
- Endpoint: ec2.ap-northeast-2.amazonaws.com
|
19
|
+
RegionName: ap-northeast-2
|
20
|
+
- Endpoint: ec2.me-south-1.amazonaws.com
|
21
|
+
RegionName: me-south-1
|
22
|
+
- Endpoint: ec2.ap-northeast-1.amazonaws.com
|
23
|
+
RegionName: ap-northeast-1
|
24
|
+
- Endpoint: ec2.sa-east-1.amazonaws.com
|
25
|
+
RegionName: sa-east-1
|
26
|
+
- Endpoint: ec2.ca-central-1.amazonaws.com
|
27
|
+
RegionName: ca-central-1
|
28
|
+
- Endpoint: ec2.ap-east-1.amazonaws.com
|
29
|
+
RegionName: ap-east-1
|
30
|
+
- Endpoint: ec2.ap-southeast-1.amazonaws.com
|
31
|
+
RegionName: ap-southeast-1
|
32
|
+
- Endpoint: ec2.ap-southeast-2.amazonaws.com
|
33
|
+
RegionName: ap-southeast-2
|
34
|
+
- Endpoint: ec2.eu-central-1.amazonaws.com
|
35
|
+
RegionName: eu-central-1
|
36
|
+
- Endpoint: ec2.us-east-1.amazonaws.com
|
37
|
+
RegionName: us-east-1
|
38
|
+
- Endpoint: ec2.us-east-2.amazonaws.com
|
39
|
+
RegionName: us-east-2
|
40
|
+
- Endpoint: ec2.us-west-1.amazonaws.com
|
41
|
+
RegionName: us-west-1
|
42
|
+
- Endpoint: ec2.us-west-2.amazonaws.com
|
43
|
+
RegionName: us-west-2
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws_recon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Larsen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-04-
|
12
|
+
date: 2021-04-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk
|
@@ -163,6 +163,7 @@ extensions: []
|
|
163
163
|
extra_rdoc_files: []
|
164
164
|
files:
|
165
165
|
- ".github/stale.yml"
|
166
|
+
- ".github/workflows/check-aws-regions.yml"
|
166
167
|
- ".github/workflows/docker-build.yml"
|
167
168
|
- ".github/workflows/smoke-test.yml"
|
168
169
|
- ".gitignore"
|
@@ -245,6 +246,8 @@ files:
|
|
245
246
|
- lib/aws_recon/services.yaml
|
246
247
|
- lib/aws_recon/version.rb
|
247
248
|
- readme.md
|
249
|
+
- utils/aws/check_region_exclusions.rb
|
250
|
+
- utils/aws/regions.yaml
|
248
251
|
- utils/cloudformation/aws-recon-cfn-template.yml
|
249
252
|
- utils/terraform/cloudwatch.tf
|
250
253
|
- utils/terraform/ecs.tf
|
@@ -267,7 +270,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
267
270
|
requirements:
|
268
271
|
- - ">="
|
269
272
|
- !ruby/object:Gem::Version
|
270
|
-
version: 2.
|
273
|
+
version: 2.6.0
|
271
274
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
272
275
|
requirements:
|
273
276
|
- - ">="
|