iam-policy-validator 1.4.0__py3-none-any.whl → 1.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {iam_policy_validator-1.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/METADATA +18 -19
- {iam_policy_validator-1.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/RECORD +31 -20
- iam_validator/__version__.py +1 -1
- iam_validator/checks/__init__.py +13 -3
- iam_validator/checks/action_condition_enforcement.py +1 -6
- iam_validator/checks/condition_key_validation.py +21 -1
- iam_validator/checks/full_wildcard.py +67 -0
- iam_validator/checks/principal_validation.py +497 -3
- iam_validator/checks/sensitive_action.py +178 -0
- iam_validator/checks/service_wildcard.py +105 -0
- iam_validator/checks/utils/sensitive_action_matcher.py +39 -31
- iam_validator/checks/wildcard_action.py +62 -0
- iam_validator/checks/wildcard_resource.py +131 -0
- iam_validator/commands/download_services.py +3 -8
- iam_validator/commands/validate.py +28 -2
- iam_validator/core/aws_fetcher.py +25 -12
- iam_validator/core/check_registry.py +15 -21
- iam_validator/core/config/__init__.py +83 -0
- iam_validator/core/config/aws_api.py +35 -0
- iam_validator/core/config/condition_requirements.py +535 -0
- iam_validator/core/config/defaults.py +390 -0
- iam_validator/core/config/principal_requirements.py +421 -0
- iam_validator/core/config/sensitive_actions.py +133 -0
- iam_validator/core/config/service_principals.py +95 -0
- iam_validator/core/config/wildcards.py +124 -0
- iam_validator/core/config_loader.py +29 -9
- iam_validator/core/formatters/enhanced.py +11 -5
- iam_validator/core/formatters/sarif.py +78 -14
- iam_validator/checks/security_best_practices.py +0 -536
- iam_validator/core/defaults.py +0 -393
- {iam_policy_validator-1.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/entry_points.txt +0 -0
- {iam_policy_validator-1.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Condition requirement configurations for action_condition_enforcement check.
|
|
3
|
+
|
|
4
|
+
This module defines default condition requirements for sensitive actions,
|
|
5
|
+
making it easy to manage complex condition enforcement rules without
|
|
6
|
+
deeply nested YAML/dict structures.
|
|
7
|
+
|
|
8
|
+
Using Python provides:
|
|
9
|
+
- Better readability and maintainability
|
|
10
|
+
- Type hints and IDE support
|
|
11
|
+
- Easy to add/modify requirements
|
|
12
|
+
- No parsing overhead
|
|
13
|
+
- Compiled to .pyc
|
|
14
|
+
|
|
15
|
+
Configuration Fields Reference:
|
|
16
|
+
- description: Technical description of what the requirement does (shown in output)
|
|
17
|
+
- example: Concrete code example showing proper condition usage
|
|
18
|
+
- condition_key: The IAM condition key to validate
|
|
19
|
+
- expected_value: (Optional) Expected value for the condition key
|
|
20
|
+
- severity: (Optional) Override default severity for this requirement
|
|
21
|
+
|
|
22
|
+
Field Progression: detect (condition_key) → explain (description) → demonstrate (example)
|
|
23
|
+
|
|
24
|
+
For detailed explanation of these fields and how to customize requirements,
|
|
25
|
+
see: docs/condition-requirements.md and docs/configuration.md#customizing-messages
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from typing import Any, Final
|
|
29
|
+
|
|
30
|
+
# ============================================================================
|
|
31
|
+
# Condition Requirement Definitions
|
|
32
|
+
# ============================================================================
|
|
33
|
+
|
|
34
|
+
# IAM PassRole - CRITICAL: Prevent privilege escalation
|
|
35
|
+
IAM_PASS_ROLE_REQUIREMENT: Final[dict[str, Any]] = {
|
|
36
|
+
"actions": ["iam:PassRole"],
|
|
37
|
+
"severity": "high",
|
|
38
|
+
"required_conditions": [
|
|
39
|
+
{
|
|
40
|
+
"condition_key": "iam:PassedToService",
|
|
41
|
+
"description": (
|
|
42
|
+
"Restrict which AWS services can assume the passed role to prevent privilege escalation"
|
|
43
|
+
),
|
|
44
|
+
"example": (
|
|
45
|
+
'"Condition": {\n'
|
|
46
|
+
' "StringEquals": {\n'
|
|
47
|
+
' "iam:PassedToService": [\n'
|
|
48
|
+
' "lambda.amazonaws.com",\n'
|
|
49
|
+
' "ecs-tasks.amazonaws.com",\n'
|
|
50
|
+
' "ec2.amazonaws.com",\n'
|
|
51
|
+
' "glue.amazonaws.com"\n'
|
|
52
|
+
" ]\n"
|
|
53
|
+
" }\n"
|
|
54
|
+
"}"
|
|
55
|
+
),
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# IAM Write Operations - Require permissions boundary
|
|
61
|
+
IAM_WRITE_PERMISSIONS_BOUNDARY: Final[dict[str, Any]] = {
|
|
62
|
+
"actions": [
|
|
63
|
+
"iam:CreateRole",
|
|
64
|
+
"iam:PutRolePolicy*",
|
|
65
|
+
"iam:PutUserPolicy",
|
|
66
|
+
"iam:PutRolePolicy",
|
|
67
|
+
"iam:Attach*Policy*",
|
|
68
|
+
"iam:AttachUserPolicy",
|
|
69
|
+
"iam:AttachRolePolicy",
|
|
70
|
+
],
|
|
71
|
+
"severity": "high",
|
|
72
|
+
"required_conditions": [
|
|
73
|
+
{
|
|
74
|
+
"condition_key": "iam:PermissionsBoundary",
|
|
75
|
+
"description": (
|
|
76
|
+
"Require permissions boundary for sensitive IAM operations to prevent privilege escalation"
|
|
77
|
+
),
|
|
78
|
+
"expected_value": "arn:aws:iam::*:policy/DeveloperBoundary",
|
|
79
|
+
"example": (
|
|
80
|
+
"# See: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html\n"
|
|
81
|
+
"{\n"
|
|
82
|
+
' "Condition": {\n'
|
|
83
|
+
' "StringEquals": {\n'
|
|
84
|
+
' "iam:PermissionsBoundary": "arn:aws:iam::123456789012:policy/XCompanyBoundaries"\n'
|
|
85
|
+
" }\n"
|
|
86
|
+
" }\n"
|
|
87
|
+
"}"
|
|
88
|
+
),
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# S3 Write Operations - Require organization ID
|
|
94
|
+
S3_WRITE_ORG_ID: Final[dict[str, Any]] = {
|
|
95
|
+
"actions": ["s3:PutObject"],
|
|
96
|
+
"severity": "medium",
|
|
97
|
+
"required_conditions": [
|
|
98
|
+
{
|
|
99
|
+
"condition_key": "aws:ResourceOrgId",
|
|
100
|
+
"description": (
|
|
101
|
+
"Require aws:ResourceOrgId condition for S3 write actions to enforce organization-level access control"
|
|
102
|
+
),
|
|
103
|
+
"example": (
|
|
104
|
+
"{\n"
|
|
105
|
+
' "Condition": {\n'
|
|
106
|
+
' "StringEquals": {\n'
|
|
107
|
+
' "aws:ResourceOrgId": "${aws:PrincipalOrgID}"\n'
|
|
108
|
+
" }\n"
|
|
109
|
+
" }\n"
|
|
110
|
+
"}"
|
|
111
|
+
),
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# IP Restrictions - Source IP requirements
|
|
117
|
+
SOURCE_IP_RESTRICTIONS: Final[dict[str, Any]] = {
|
|
118
|
+
"action_patterns": [
|
|
119
|
+
"^ssm:StartSession$",
|
|
120
|
+
"^ssm:Run.*$",
|
|
121
|
+
"^s3:GetObject$",
|
|
122
|
+
"^rds-db:Connect$",
|
|
123
|
+
],
|
|
124
|
+
"severity": "low",
|
|
125
|
+
"required_conditions": [
|
|
126
|
+
{
|
|
127
|
+
"condition_key": "aws:SourceIp",
|
|
128
|
+
"description": "Restrict access to corporate IP ranges",
|
|
129
|
+
"example": (
|
|
130
|
+
"{\n"
|
|
131
|
+
' "Condition": {\n'
|
|
132
|
+
' "IpAddress": {\n'
|
|
133
|
+
' "aws:SourceIp": [\n'
|
|
134
|
+
' "10.0.0.0/8",\n'
|
|
135
|
+
' "172.16.0.0/12"\n'
|
|
136
|
+
" ]\n"
|
|
137
|
+
" }\n"
|
|
138
|
+
" }\n"
|
|
139
|
+
"}"
|
|
140
|
+
),
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
# S3 Secure Transport - Never allow insecure transport
|
|
146
|
+
S3_SECURE_TRANSPORT: Final[dict[str, Any]] = {
|
|
147
|
+
"actions": ["s3:GetObject", "s3:PutObject"],
|
|
148
|
+
"required_conditions": {
|
|
149
|
+
"none_of": [
|
|
150
|
+
{
|
|
151
|
+
"condition_key": "aws:SecureTransport",
|
|
152
|
+
"expected_value": False,
|
|
153
|
+
"description": "Never allow insecure transport to be explicitly permitted",
|
|
154
|
+
"example": (
|
|
155
|
+
"# Set this condition to true to enforce secure transport or remove it entirely\n"
|
|
156
|
+
"{\n"
|
|
157
|
+
' "Condition": {\n'
|
|
158
|
+
' "Bool": {\n'
|
|
159
|
+
' "aws:SecureTransport": "true"\n'
|
|
160
|
+
" }\n"
|
|
161
|
+
" }\n"
|
|
162
|
+
"}"
|
|
163
|
+
),
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
# ============================================================================
|
|
170
|
+
# Optional Requirements (Commented Examples for Users)
|
|
171
|
+
# ============================================================================
|
|
172
|
+
# These are disabled by default but can be enabled by users
|
|
173
|
+
|
|
174
|
+
# S3 Destructive Operations - Require MFA
|
|
175
|
+
S3_DESTRUCTIVE_MFA: Final[dict[str, Any]] = {
|
|
176
|
+
"actions": [
|
|
177
|
+
"s3:DeleteBucket",
|
|
178
|
+
"s3:DeleteBucketPolicy",
|
|
179
|
+
"s3:PutBucketPolicy",
|
|
180
|
+
],
|
|
181
|
+
"severity": "high",
|
|
182
|
+
"required_conditions": [
|
|
183
|
+
{
|
|
184
|
+
"condition_key": "aws:MultiFactorAuthPresent",
|
|
185
|
+
"description": "Require MFA for S3 destructive operations",
|
|
186
|
+
"expected_value": "true",
|
|
187
|
+
"example": (
|
|
188
|
+
"{\n"
|
|
189
|
+
' "Condition": {\n'
|
|
190
|
+
' "Bool": {\n'
|
|
191
|
+
' "aws:MultiFactorAuthPresent": "true"\n'
|
|
192
|
+
" }\n"
|
|
193
|
+
" }\n"
|
|
194
|
+
"}"
|
|
195
|
+
),
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# All S3 Operations - Require HTTPS
|
|
201
|
+
S3_REQUIRE_HTTPS: Final[dict[str, Any]] = {
|
|
202
|
+
"action_patterns": ["^s3:.*"],
|
|
203
|
+
"severity": "medium",
|
|
204
|
+
"required_conditions": [
|
|
205
|
+
{
|
|
206
|
+
"condition_key": "aws:SecureTransport",
|
|
207
|
+
"description": "Require HTTPS for all S3 operations",
|
|
208
|
+
"expected_value": True,
|
|
209
|
+
"example": (
|
|
210
|
+
"{\n"
|
|
211
|
+
' "Condition": {\n'
|
|
212
|
+
' "Bool": {\n'
|
|
213
|
+
' "aws:SecureTransport": "true"\n'
|
|
214
|
+
" }\n"
|
|
215
|
+
" }\n"
|
|
216
|
+
"}"
|
|
217
|
+
),
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
# EC2 Instances - Must be in specific VPCs
|
|
223
|
+
EC2_VPC_RESTRICTION: Final[dict[str, Any]] = {
|
|
224
|
+
"actions": ["ec2:RunInstances"],
|
|
225
|
+
"severity": "high",
|
|
226
|
+
"required_conditions": [
|
|
227
|
+
{
|
|
228
|
+
"condition_key": "ec2:Vpc",
|
|
229
|
+
"description": "EC2 instances must be launched in approved VPCs",
|
|
230
|
+
"example": (
|
|
231
|
+
"{\n"
|
|
232
|
+
' "Condition": {\n'
|
|
233
|
+
' "StringEquals": {\n'
|
|
234
|
+
' "ec2:Vpc": "arn:aws:ec2:us-east-1:123456789012:vpc/vpc-12345678"\n'
|
|
235
|
+
" }\n"
|
|
236
|
+
" }\n"
|
|
237
|
+
"}"
|
|
238
|
+
),
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
# EC2 Instances - Tag requirements (ABAC)
|
|
244
|
+
EC2_TAG_REQUIREMENTS: Final[dict[str, Any]] = {
|
|
245
|
+
"actions": ["ec2:RunInstances"],
|
|
246
|
+
"severity": "high",
|
|
247
|
+
"required_conditions": {
|
|
248
|
+
"all_of": [
|
|
249
|
+
{
|
|
250
|
+
"condition_key": "aws:RequestTag/env",
|
|
251
|
+
"operator": "StringEquals",
|
|
252
|
+
"expected_value": ["prod", "pre", "dev", "sandbox"],
|
|
253
|
+
"description": "Must specify a valid Environment tag",
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
"any_of": [
|
|
257
|
+
{
|
|
258
|
+
"condition_key": "aws:ResourceTag/owner",
|
|
259
|
+
"operator": "StringEquals",
|
|
260
|
+
"expected_value": "${aws:PrincipalTag/owner}",
|
|
261
|
+
"description": "Resource owner must match the principal's owner tag",
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"condition_key": "aws:RequestTag/owner",
|
|
265
|
+
"description": "Must specify resource owner",
|
|
266
|
+
"expected_value": "${aws:PrincipalTag/owner}",
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
},
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# RDS - Database tag requirements
|
|
273
|
+
RDS_TAG_REQUIREMENTS: Final[dict[str, Any]] = {
|
|
274
|
+
"action_patterns": [
|
|
275
|
+
"^rds:Create.*",
|
|
276
|
+
"^rds:Modify.*",
|
|
277
|
+
],
|
|
278
|
+
"severity": "medium",
|
|
279
|
+
"required_conditions": {
|
|
280
|
+
"all_of": [
|
|
281
|
+
{
|
|
282
|
+
"condition_key": "aws:RequestTag/DataClassification",
|
|
283
|
+
"description": "Must specify data classification",
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"condition_key": "aws:RequestTag/BackupPolicy",
|
|
287
|
+
"description": "Must specify backup policy",
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"condition_key": "aws:RequestTag/Owner",
|
|
291
|
+
"description": "Must specify resource owner",
|
|
292
|
+
},
|
|
293
|
+
],
|
|
294
|
+
},
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
# S3 Bucket Operations - Data classification matching
|
|
298
|
+
S3_BUCKET_TAG_REQUIREMENTS: Final[dict[str, Any]] = {
|
|
299
|
+
"actions": ["s3:CreateBucket", "s3:PutObject"],
|
|
300
|
+
"severity": "medium",
|
|
301
|
+
"required_conditions": {
|
|
302
|
+
"all_of": [
|
|
303
|
+
{
|
|
304
|
+
"condition_key": "aws:ResourceTag/DataClassification",
|
|
305
|
+
"operator": "StringEquals",
|
|
306
|
+
"expected_value": "${aws:PrincipalTag/DataClassification}",
|
|
307
|
+
"description": "Data classification must match principal's tag",
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"condition_key": "aws:RequestTag/Owner",
|
|
311
|
+
"description": "Must specify owner",
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"condition_key": "aws:RequestTag/CostCenter",
|
|
315
|
+
"description": "Must specify cost center",
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
},
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
# Forbidden Actions - Flag if these dangerous actions appear
|
|
322
|
+
FORBIDDEN_ACTIONS: Final[dict[str, Any]] = {
|
|
323
|
+
"actions": {
|
|
324
|
+
"none_of": [
|
|
325
|
+
"iam:*",
|
|
326
|
+
"s3:DeleteBucket",
|
|
327
|
+
"s3:DeleteBucketPolicy",
|
|
328
|
+
],
|
|
329
|
+
},
|
|
330
|
+
"severity": "critical",
|
|
331
|
+
"description": "These highly sensitive actions are forbidden in this policy",
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
# Prevent overly permissive IP ranges
|
|
335
|
+
PREVENT_PUBLIC_IP: Final[dict[str, Any]] = {
|
|
336
|
+
"action_patterns": ["^s3:.*"],
|
|
337
|
+
"severity": "high",
|
|
338
|
+
"required_conditions": {
|
|
339
|
+
"none_of": [
|
|
340
|
+
{
|
|
341
|
+
"condition_key": "aws:SourceIp",
|
|
342
|
+
"expected_value": "0.0.0.0/0",
|
|
343
|
+
"description": "Do not allow access from any IP address",
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
},
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
# ============================================================================
|
|
350
|
+
# Default Requirements List
|
|
351
|
+
# ============================================================================
|
|
352
|
+
|
|
353
|
+
# Requirements enabled by default
|
|
354
|
+
DEFAULT_CONDITION_REQUIREMENTS: Final[list[dict[str, Any]]] = [
|
|
355
|
+
IAM_PASS_ROLE_REQUIREMENT,
|
|
356
|
+
IAM_WRITE_PERMISSIONS_BOUNDARY,
|
|
357
|
+
S3_WRITE_ORG_ID,
|
|
358
|
+
SOURCE_IP_RESTRICTIONS,
|
|
359
|
+
S3_SECURE_TRANSPORT,
|
|
360
|
+
]
|
|
361
|
+
|
|
362
|
+
# All available requirements (including optional ones)
|
|
363
|
+
ALL_CONDITION_REQUIREMENTS: Final[dict[str, dict[str, Any]]] = {
|
|
364
|
+
# Default (enabled)
|
|
365
|
+
"iam_pass_role": IAM_PASS_ROLE_REQUIREMENT,
|
|
366
|
+
"iam_permissions_boundary": IAM_WRITE_PERMISSIONS_BOUNDARY,
|
|
367
|
+
"s3_org_id": S3_WRITE_ORG_ID,
|
|
368
|
+
"source_ip_restrictions": SOURCE_IP_RESTRICTIONS,
|
|
369
|
+
"s3_secure_transport": S3_SECURE_TRANSPORT,
|
|
370
|
+
# Optional (disabled by default)
|
|
371
|
+
"s3_destructive_mfa": S3_DESTRUCTIVE_MFA,
|
|
372
|
+
"s3_require_https": S3_REQUIRE_HTTPS,
|
|
373
|
+
"ec2_vpc_restriction": EC2_VPC_RESTRICTION,
|
|
374
|
+
"ec2_tag_requirements": EC2_TAG_REQUIREMENTS,
|
|
375
|
+
"rds_tag_requirements": RDS_TAG_REQUIREMENTS,
|
|
376
|
+
"s3_bucket_tag_requirements": S3_BUCKET_TAG_REQUIREMENTS,
|
|
377
|
+
"forbidden_actions": FORBIDDEN_ACTIONS,
|
|
378
|
+
"prevent_public_ip": PREVENT_PUBLIC_IP,
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
# ============================================================================
|
|
383
|
+
# Helper Functions
|
|
384
|
+
# ============================================================================
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def get_default_requirements() -> list[dict[str, Any]]:
|
|
388
|
+
"""
|
|
389
|
+
Get the default condition requirements.
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
List of default condition requirement configurations
|
|
393
|
+
"""
|
|
394
|
+
# Return a copy to prevent modification
|
|
395
|
+
import copy
|
|
396
|
+
|
|
397
|
+
return copy.deepcopy(DEFAULT_CONDITION_REQUIREMENTS)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def get_requirement(name: str) -> dict[str, Any] | None:
|
|
401
|
+
"""
|
|
402
|
+
Get a specific requirement by name.
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
name: Requirement name (e.g., "iam_pass_role", "s3_destructive_mfa")
|
|
406
|
+
|
|
407
|
+
Returns:
|
|
408
|
+
Requirement configuration dict, or None if not found
|
|
409
|
+
"""
|
|
410
|
+
import copy
|
|
411
|
+
|
|
412
|
+
req = ALL_CONDITION_REQUIREMENTS.get(name)
|
|
413
|
+
return copy.deepcopy(req) if req else None
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def get_all_requirement_names() -> list[str]:
|
|
417
|
+
"""
|
|
418
|
+
Get list of all available requirement names.
|
|
419
|
+
|
|
420
|
+
Returns:
|
|
421
|
+
List of requirement names
|
|
422
|
+
"""
|
|
423
|
+
return list(ALL_CONDITION_REQUIREMENTS.keys())
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def get_requirements_by_names(names: list[str]) -> list[dict[str, Any]]:
|
|
427
|
+
"""
|
|
428
|
+
Get multiple requirements by name.
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
names: List of requirement names
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
List of requirement configurations
|
|
435
|
+
"""
|
|
436
|
+
import copy
|
|
437
|
+
|
|
438
|
+
requirements = []
|
|
439
|
+
for name in names:
|
|
440
|
+
req = ALL_CONDITION_REQUIREMENTS.get(name)
|
|
441
|
+
if req:
|
|
442
|
+
requirements.append(copy.deepcopy(req))
|
|
443
|
+
return requirements
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def get_requirements_by_severity(
|
|
447
|
+
min_severity: str = "low",
|
|
448
|
+
) -> list[dict[str, Any]]:
|
|
449
|
+
"""
|
|
450
|
+
Get requirements filtered by minimum severity.
|
|
451
|
+
|
|
452
|
+
Args:
|
|
453
|
+
min_severity: Minimum severity level (low, medium, high, critical)
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
List of requirements matching severity criteria
|
|
457
|
+
"""
|
|
458
|
+
import copy
|
|
459
|
+
|
|
460
|
+
severity_order = {"low": 0, "medium": 1, "high": 2, "critical": 3}
|
|
461
|
+
min_level = severity_order.get(min_severity, 0)
|
|
462
|
+
|
|
463
|
+
requirements = []
|
|
464
|
+
for req in ALL_CONDITION_REQUIREMENTS.values():
|
|
465
|
+
req_severity = req.get("severity", "low")
|
|
466
|
+
req_level = severity_order.get(req_severity, 0)
|
|
467
|
+
if req_level >= min_level:
|
|
468
|
+
requirements.append(copy.deepcopy(req))
|
|
469
|
+
|
|
470
|
+
return requirements
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def describe_requirement(name: str) -> dict[str, Any]:
|
|
474
|
+
"""
|
|
475
|
+
Get description and metadata for a requirement.
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
name: Requirement name
|
|
479
|
+
|
|
480
|
+
Returns:
|
|
481
|
+
Dictionary with requirement metadata
|
|
482
|
+
"""
|
|
483
|
+
descriptions = {
|
|
484
|
+
"iam_pass_role": {
|
|
485
|
+
"name": "IAM PassRole Restriction",
|
|
486
|
+
"category": "privilege_escalation",
|
|
487
|
+
"severity": "high",
|
|
488
|
+
"description": "Prevents privilege escalation by requiring iam:PassedToService condition",
|
|
489
|
+
"required": True,
|
|
490
|
+
},
|
|
491
|
+
"iam_permissions_boundary": {
|
|
492
|
+
"name": "IAM Permissions Boundary",
|
|
493
|
+
"category": "privilege_escalation",
|
|
494
|
+
"severity": "high",
|
|
495
|
+
"description": "Requires permissions boundary for IAM write operations",
|
|
496
|
+
"required": True,
|
|
497
|
+
},
|
|
498
|
+
"s3_org_id": {
|
|
499
|
+
"name": "S3 Organization ID",
|
|
500
|
+
"category": "data_exfiltration",
|
|
501
|
+
"severity": "medium",
|
|
502
|
+
"description": "Ensures S3 operations stay within organization",
|
|
503
|
+
"required": True,
|
|
504
|
+
},
|
|
505
|
+
"source_ip_restrictions": {
|
|
506
|
+
"name": "Source IP Restrictions",
|
|
507
|
+
"category": "network_security",
|
|
508
|
+
"severity": "low",
|
|
509
|
+
"description": "Restricts access to corporate IP ranges",
|
|
510
|
+
"required": False,
|
|
511
|
+
},
|
|
512
|
+
"s3_secure_transport": {
|
|
513
|
+
"name": "S3 Secure Transport",
|
|
514
|
+
"category": "encryption",
|
|
515
|
+
"severity": "medium",
|
|
516
|
+
"description": "Prevents explicitly allowing insecure transport",
|
|
517
|
+
"required": True,
|
|
518
|
+
},
|
|
519
|
+
"s3_destructive_mfa": {
|
|
520
|
+
"name": "S3 Destructive MFA",
|
|
521
|
+
"category": "data_protection",
|
|
522
|
+
"severity": "high",
|
|
523
|
+
"description": "Requires MFA for destructive S3 operations",
|
|
524
|
+
"required": False,
|
|
525
|
+
},
|
|
526
|
+
"ec2_tag_requirements": {
|
|
527
|
+
"name": "EC2 Tag Requirements (ABAC)",
|
|
528
|
+
"category": "abac",
|
|
529
|
+
"severity": "high",
|
|
530
|
+
"description": "Enforces tag-based access control for EC2 instances",
|
|
531
|
+
"required": False,
|
|
532
|
+
},
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return descriptions.get(name, {"name": "Unknown", "description": "Unknown requirement"})
|