14
14
limitations under the License.
15
15
"""
16
16
17
- import argparse
18
17
import gettext
19
18
import sys
20
19
from os .path import dirname
21
20
from typing import List
22
21
23
22
import pkg_resources
24
23
24
+ from provider .aws .command import aws_main
25
+ from shared .parameters import generate_parser
26
+
25
27
"""path to pip package"""
26
28
sys .path .append (dirname (__file__ ))
27
29
28
30
# pylint: disable=wrong-import-position
29
-
30
- from provider .policy .command import Policy
31
- from provider .vpc .command import Vpc
32
- from provider .iot .command import Iot
33
- from provider .all .command import All
34
- from provider .limit .command import Limit
35
- from provider .security .command import Security
36
-
37
31
from shared .common import (
38
32
exit_critical ,
39
33
Filterable ,
40
34
parse_filters ,
41
- message_handler ,
42
35
)
43
- from shared .common_aws import aws_verbose , generate_session
44
36
45
- # pylint: enable=wrong-import-position
46
37
# Check version
47
38
if sys .version_info < (3 , 8 ):
48
39
print ("Python 3.8 or newer is required" , file = sys .stderr )
51
42
__version__ = "2.3"
52
43
53
44
AVAILABLE_LANGUAGES = ["en_US" , "pt_BR" ]
54
- DEFAULT_REGION = "us-east-1"
55
- DEFAULT_PARTITION_CODE = "aws"
56
-
57
-
58
- def str2bool (v ):
59
- if isinstance (v , bool ):
60
- return v
61
- # pylint: disable=no-else-return
62
- if v .lower () in ("yes" , "true" , "t" , "y" , "1" ):
63
- return True
64
- elif v .lower () in ("no" , "false" , "f" , "n" , "0" ):
65
- return False
66
- else :
67
- raise argparse .ArgumentTypeError ("Boolean value expected." )
68
-
69
-
70
- def generate_parser ():
71
- parser = argparse .ArgumentParser ()
72
-
73
- subparsers = parser .add_subparsers (help = "commands" , dest = "command" )
74
-
75
- vpc_parser = subparsers .add_parser ("aws-vpc" , help = "Analyze VPCs" )
76
- add_default_arguments (vpc_parser )
77
- vpc_parser .add_argument (
78
- "-v" ,
79
- "--vpc-id" ,
80
- required = False ,
81
- help = "Inform VPC to analyze. If not informed, script will check all vpcs." ,
82
- )
83
-
84
- iot_parser = subparsers .add_parser ("aws-iot" , help = "Analyze IoTs" )
85
- add_default_arguments (iot_parser )
86
- iot_parser .add_argument (
87
- "-t" ,
88
- "--thing-name" ,
89
- required = False ,
90
- help = "Inform Thing Name to analyze. If not informed, script will check all things inside a region." ,
91
- )
92
-
93
- policy_parser = subparsers .add_parser ("aws-policy" , help = "Analyze policies" )
94
- add_default_arguments (policy_parser , is_global = True )
95
-
96
- all_parser = subparsers .add_parser ("aws-all" , help = "Analyze all resources" )
97
- add_default_arguments (all_parser , diagram_enabled = False )
98
- add_services_argument (all_parser )
99
-
100
- limit_parser = subparsers .add_parser (
101
- "aws-limit" , help = "Analyze aws limit resources."
102
- )
103
- add_default_arguments (limit_parser , diagram_enabled = False , filters_enabled = False )
104
- add_services_argument (limit_parser )
105
- limit_parser .add_argument (
106
- "-t" ,
107
- "--threshold" ,
108
- required = False ,
109
- help = "Select the %% of resource threshold between 0 and 100. \
110
- For example: --threshold 50 will report all resources with more than 50%% threshold." ,
111
- )
112
-
113
- security_parser = subparsers .add_parser (
114
- "aws-security" , help = "Analyze aws several security checks."
115
- )
116
- add_default_arguments (security_parser , diagram_enabled = False , filters_enabled = False )
117
- security_parser .add_argument (
118
- "-c" ,
119
- "--commands" ,
120
- action = "append" ,
121
- required = False ,
122
- help = 'Select the security check command that you want to run. \
123
- To see available commands, please type "-c list". \
124
- If not passed, command will check all services.' ,
125
- )
126
-
127
- return parser
128
-
129
-
130
- def add_services_argument (limit_parser ):
131
- limit_parser .add_argument (
132
- "-s" ,
133
- "--services" ,
134
- required = False ,
135
- help = 'Define services that you want to check, use "," (comma) to separate multiple names. \
136
- If not passed, command will check all services.' ,
137
- )
138
-
139
-
140
- def add_default_arguments (
141
- parser , is_global = False , diagram_enabled = True , filters_enabled = True
142
- ):
143
- if not is_global :
144
- parser .add_argument (
145
- "-r" ,
146
- "--region-name" ,
147
- required = False ,
148
- help = 'Inform REGION NAME to analyze or "all" to check on all regions. \
149
- If not informed, try to get from config file' ,
150
- )
151
- parser .add_argument (
152
- "-p" , "--profile-name" , required = False , help = "Profile to be used"
153
- )
154
- parser .add_argument (
155
- "-l" , "--language" , required = False , help = "Available languages: pt_BR, en_US"
156
- )
157
- parser .add_argument (
158
- "--verbose" ,
159
- "--verbose" ,
160
- type = str2bool ,
161
- nargs = "?" ,
162
- const = True ,
163
- default = False ,
164
- help = "Enable debug mode to sdk calls (default false)" ,
165
- )
166
- if filters_enabled :
167
- parser .add_argument (
168
- "-f" ,
169
- "--filters" ,
170
- action = "append" ,
171
- required = False ,
172
- help = "filter resources (tags only for now, you must specify name and values); multiple filters "
173
- "are possible to pass with -f <filter_1> -f <filter_2> approach, values can be separated by : sign; "
174
- "example: Name=tags.costCenter;Value=20000:'20001:1'" ,
175
- )
176
- if diagram_enabled :
177
- parser .add_argument (
178
- "-d" ,
179
- "--diagram" ,
180
- type = str2bool ,
181
- nargs = "?" ,
182
- const = True ,
183
- default = True ,
184
- help = "print diagram with resources (need Graphviz installed). Pass true/y[es] to "
185
- "view image or false/n[o] not to generate image. Default true" ,
186
- )
187
45
188
46
189
47
# pylint: disable=too-many-branches,too-many-statements,too-many-locals
@@ -197,10 +55,6 @@ def main():
197
55
198
56
args = parser .parse_args ()
199
57
200
- # Check if verbose mode is enabled
201
- if args .verbose :
202
- aws_verbose ()
203
-
204
58
if args .language is None or args .language not in AVAILABLE_LANGUAGES :
205
59
language = "en_US"
206
60
else :
@@ -228,83 +82,8 @@ def main():
228
82
if args .filters is not None :
229
83
filters = parse_filters (args .filters )
230
84
231
- # aws profile check
232
- if "region_name" not in args :
233
- session = generate_session (profile_name = args .profile_name , region_name = None )
234
- else :
235
- session = generate_session (
236
- profile_name = args .profile_name , region_name = args .region_name
237
- )
238
-
239
- session .get_credentials ()
240
- region_name = session .region_name
241
-
242
- partition_code = get_partition (session , region_name )
243
-
244
- if "region_name" not in args :
245
- region_names = [DEFAULT_REGION ]
246
- else :
247
- # checking region configuration
248
- check_region_profile (
249
- arg_region_name = args .region_name , profile_region_name = region_name
250
- )
251
-
252
- # assuming region parameter precedes region configuration
253
- if args .region_name is not None :
254
- region_name = args .region_name
255
-
256
- # get regions
257
- region_names = check_region (
258
- region_parameter = args .region_name ,
259
- region_name = region_name ,
260
- session = session ,
261
- partition_code = partition_code ,
262
- )
263
-
264
- if "threshold" in args :
265
- if args .threshold is not None :
266
- if args .threshold .isdigit () is False :
267
- exit_critical (_ ("Threshold must be between 0 and 100" ))
268
- else :
269
- if int (args .threshold ) < 0 or int (args .threshold ) > 100 :
270
- exit_critical (_ ("Threshold must be between 0 and 100" ))
271
-
272
- if args .command == "aws-vpc" :
273
- command = Vpc (
274
- vpc_id = args .vpc_id ,
275
- region_names = region_names ,
276
- session = session ,
277
- partition_code = partition_code ,
278
- )
279
- elif args .command == "aws-policy" :
280
- command = Policy (
281
- region_names = region_names , session = session , partition_code = partition_code
282
- )
283
- elif args .command == "aws-iot" :
284
- command = Iot (
285
- thing_name = args .thing_name ,
286
- region_names = region_names ,
287
- session = session ,
288
- partition_code = partition_code ,
289
- )
290
- elif args .command == "aws-all" :
291
- command = All (
292
- region_names = region_names , session = session , partition_code = partition_code
293
- )
294
- elif args .command == "aws-limit" :
295
- command = Limit (
296
- region_names = region_names ,
297
- session = session ,
298
- threshold = args .threshold ,
299
- partition_code = partition_code ,
300
- )
301
- elif args .command == "aws-security" :
302
- command = Security (
303
- region_names = region_names ,
304
- session = session ,
305
- commands = args .commands ,
306
- partition_code = partition_code ,
307
- )
85
+ if args .command .startswith ("aws" ):
86
+ command = aws_main (args )
308
87
else :
309
88
raise NotImplementedError ("Unknown command" )
310
89
@@ -316,28 +95,6 @@ def main():
316
95
command .run (diagram , args .verbose , services , filters )
317
96
318
97
319
- def get_partition (session , region_name ):
320
- partition_code = DEFAULT_PARTITION_CODE # assume it's always default partition, even if we can't find a region
321
- partition_name = "AWS Standard"
322
- # pylint: disable=protected-access
323
- loader = session ._session .get_component ("data_loader" )
324
- endpoints = loader .load_data ("endpoints" )
325
- for partition in endpoints ["partitions" ]:
326
- for region , _ in partition ["regions" ].items ():
327
- if region == region_name :
328
- partition_code = partition ["partition" ]
329
- partition_name = partition ["partitionName" ]
330
-
331
- if partition_code != DEFAULT_PARTITION_CODE :
332
- message_handler (
333
- "Found non-default partition: {} ({})" .format (
334
- partition_code , partition_name
335
- ),
336
- "HEADER" ,
337
- )
338
- return partition_code
339
-
340
-
341
98
def check_diagram_version (diagram ):
342
99
if diagram :
343
100
# Checking diagram version. Must be 0.13 or higher
@@ -348,37 +105,6 @@ def check_diagram_version(diagram):
348
105
)
349
106
350
107
351
- def check_region_profile (arg_region_name , profile_region_name ):
352
- if arg_region_name is None and profile_region_name is None :
353
- exit_critical ("Neither region parameter nor region config were passed" )
354
-
355
-
356
- def check_region (region_parameter , region_name , session , partition_code ):
357
- """
358
- Region us-east-1 as a default region here, if not aws partition, just return asked region
359
-
360
- This is just to list aws regions, doesn't matter default region
361
- """
362
- if partition_code != "aws" :
363
- return [region_name ]
364
-
365
- client = session .client ("ec2" , region_name = DEFAULT_REGION )
366
-
367
- valid_region_names = [
368
- region ["RegionName" ]
369
- for region in client .describe_regions (AllRegions = True )["Regions" ]
370
- ]
371
-
372
- if region_parameter != "all" :
373
- if region_name not in valid_region_names :
374
- message = "There is no region named: {0}" .format (region_name )
375
- exit_critical (message )
376
- else :
377
- valid_region_names = [region_name ]
378
-
379
- return valid_region_names
380
-
381
-
382
108
if __name__ == "__main__" :
383
109
try :
384
110
main ()
0 commit comments