iam-policy-validator 1.14.6__py3-none-any.whl → 1.15.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.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/METADATA +34 -23
- {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/RECORD +42 -29
- iam_policy_validator-1.15.0.dist-info/entry_points.txt +4 -0
- iam_validator/__version__.py +1 -1
- iam_validator/checks/__init__.py +2 -0
- iam_validator/checks/action_validation.py +91 -27
- iam_validator/checks/not_action_not_resource.py +163 -0
- iam_validator/checks/resource_validation.py +132 -81
- iam_validator/checks/wildcard_resource.py +136 -6
- iam_validator/commands/__init__.py +3 -0
- iam_validator/commands/cache.py +66 -24
- iam_validator/commands/completion.py +94 -15
- iam_validator/commands/mcp.py +210 -0
- iam_validator/commands/query.py +489 -65
- iam_validator/core/aws_service/__init__.py +5 -1
- iam_validator/core/aws_service/cache.py +20 -0
- iam_validator/core/aws_service/fetcher.py +180 -11
- iam_validator/core/aws_service/storage.py +14 -6
- iam_validator/core/aws_service/validators.py +32 -41
- iam_validator/core/check_registry.py +100 -35
- iam_validator/core/config/aws_global_conditions.py +13 -0
- iam_validator/core/config/check_documentation.py +104 -51
- iam_validator/core/config/config_loader.py +39 -3
- iam_validator/core/config/defaults.py +6 -0
- iam_validator/core/constants.py +11 -4
- iam_validator/core/models.py +39 -14
- iam_validator/mcp/__init__.py +162 -0
- iam_validator/mcp/models.py +118 -0
- iam_validator/mcp/server.py +2928 -0
- iam_validator/mcp/session_config.py +319 -0
- iam_validator/mcp/templates/__init__.py +79 -0
- iam_validator/mcp/templates/builtin.py +856 -0
- iam_validator/mcp/tools/__init__.py +72 -0
- iam_validator/mcp/tools/generation.py +888 -0
- iam_validator/mcp/tools/org_config_tools.py +263 -0
- iam_validator/mcp/tools/query.py +395 -0
- iam_validator/mcp/tools/validation.py +376 -0
- iam_validator/sdk/__init__.py +64 -63
- iam_validator/sdk/context.py +3 -2
- iam_validator/sdk/policy_utils.py +31 -5
- iam_policy_validator-1.14.6.dist-info/entry_points.txt +0 -2
- {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.14.6.dist-info → iam_policy_validator-1.15.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iam-policy-validator
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.15.0
|
|
4
4
|
Summary: Validate AWS IAM policies for correctness and security using AWS Service Reference API
|
|
5
5
|
Project-URL: Homepage, https://github.com/boogy/iam-policy-validator
|
|
6
|
-
Project-URL: Documentation, https://github.
|
|
6
|
+
Project-URL: Documentation, https://boogy.github.io/iam-policy-validator
|
|
7
7
|
Project-URL: Repository, https://github.com/boogy/iam-policy-validator
|
|
8
8
|
Project-URL: Issues, https://github.com/boogy/iam-policy-validator/issues
|
|
9
|
-
Project-URL: Changelog, https://github.com/boogy/iam-policy-validator/blob/main/
|
|
9
|
+
Project-URL: Changelog, https://github.com/boogy/iam-policy-validator/blob/main/CHANGELOG.md
|
|
10
10
|
Author-email: boogy <0xboogy@gmail.com>
|
|
11
11
|
License: MIT
|
|
12
12
|
License-File: LICENSE
|
|
13
13
|
Keywords: aws,github-action,iam,policy,security,validation
|
|
14
|
-
Classifier: Development Status ::
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
16
16
|
Classifier: Intended Audience :: System Administrators
|
|
17
17
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -19,6 +19,8 @@ Classifier: Programming Language :: Python :: 3
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
24
|
Classifier: Topic :: Security
|
|
23
25
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
26
|
Classifier: Topic :: System :: Systems Administration
|
|
@@ -38,17 +40,27 @@ Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
|
38
40
|
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
39
41
|
Requires-Dist: types-boto3; extra == 'dev'
|
|
40
42
|
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
43
|
+
Provides-Extra: docs
|
|
44
|
+
Requires-Dist: mkdocs-gen-files>=0.5.0; extra == 'docs'
|
|
45
|
+
Requires-Dist: mkdocs-literate-nav>=0.6.0; extra == 'docs'
|
|
46
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
|
|
47
|
+
Requires-Dist: mkdocs>=1.6.0; extra == 'docs'
|
|
48
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'docs'
|
|
49
|
+
Provides-Extra: mcp
|
|
50
|
+
Requires-Dist: fastmcp>=2.14.1; extra == 'mcp'
|
|
41
51
|
Description-Content-Type: text/markdown
|
|
42
52
|
|
|
43
53
|
# IAM Policy Validator
|
|
44
54
|
|
|
45
|
-
**
|
|
55
|
+
**Stop IAM misconfigurations before they become breaches** — Catch overprivileged permissions, dangerous wildcards, and policy errors before deployment.
|
|
46
56
|
|
|
47
57
|
[](https://github.com/marketplace/actions/iam-policy-validator)
|
|
48
58
|
[](https://www.python.org/downloads/)
|
|
49
59
|
[](LICENSE)
|
|
50
60
|
[](https://scorecard.dev/viewer/?uri=github.com/boogy/iam-policy-validator)
|
|
51
61
|
|
|
62
|
+
**[📖 Full Documentation](https://boogy.github.io/iam-policy-validator/)**
|
|
63
|
+
|
|
52
64
|
---
|
|
53
65
|
|
|
54
66
|
## Why This Tool Exists
|
|
@@ -120,7 +132,7 @@ iam-validator validate --path examples/quick-start/ --format enhanced
|
|
|
120
132
|
```
|
|
121
133
|
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
|
122
134
|
│ │
|
|
123
|
-
│ IAM Policy Validation Report (v1.
|
|
135
|
+
│ IAM Policy Validation Report (v1.14.1) │
|
|
124
136
|
│ │
|
|
125
137
|
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
126
138
|
───────────────────────────────────────── Detailed Results ─────────────────────────────────────────
|
|
@@ -294,7 +306,7 @@ sensitive_action:
|
|
|
294
306
|
message: "CloudFormation + PassRole enables infrastructure privilege escalation"
|
|
295
307
|
```
|
|
296
308
|
|
|
297
|
-
See [
|
|
309
|
+
See [Security Checks Documentation](docs/user-guide/checks/security-checks.md) for all built-in patterns and custom configuration.
|
|
298
310
|
|
|
299
311
|
**Comparison:**
|
|
300
312
|
|
|
@@ -428,15 +440,14 @@ Validates against official AWS IAM requirements:
|
|
|
428
440
|
|
|
429
441
|
Identifies overly permissive configurations:
|
|
430
442
|
|
|
431
|
-
| Check
|
|
432
|
-
|
|
|
433
|
-
| **Wildcard Action**
|
|
434
|
-
| **Wildcard Resource**
|
|
435
|
-
| **Full Wildcard**
|
|
436
|
-
| **Service Wildcards**
|
|
437
|
-
| **Sensitive Actions
|
|
438
|
-
| **
|
|
439
|
-
| **Condition Enforcement** | Organization-specific requirements (your custom rules) |
|
|
443
|
+
| Check | What It Catches |
|
|
444
|
+
| ------------------------- | ------------------------------------------------------ |
|
|
445
|
+
| **Wildcard Action** | `Action: "*"` grants all AWS permissions |
|
|
446
|
+
| **Wildcard Resource** | `Resource: "*"` applies to all resources |
|
|
447
|
+
| **Full Wildcard** | Both `Action: "*"` AND `Resource: "*"` (admin access) |
|
|
448
|
+
| **Service Wildcards** | `s3:*`, `iam:*`, `ec2:*` (overly broad) |
|
|
449
|
+
| **Sensitive Actions** | 490+ privilege escalation patterns and dangerous actions |
|
|
450
|
+
| **Condition Enforcement** | Organization-specific condition requirements |
|
|
440
451
|
|
|
441
452
|
**Note on Sensitive Actions:** This check has two modes:
|
|
442
453
|
|
|
@@ -635,7 +646,7 @@ sensitive_action:
|
|
|
635
646
|
|
|
636
647
|
For more details, see:
|
|
637
648
|
|
|
638
|
-
- [
|
|
649
|
+
- [Configuration Guide](docs/user-guide/configuration.md) - How to configure condition requirements
|
|
639
650
|
- [examples/configs/full-reference-config.yaml](examples/configs/full-reference-config.yaml) - Complete configuration reference
|
|
640
651
|
|
|
641
652
|
---
|
|
@@ -710,12 +721,12 @@ iam-validator analyze --path new-policy.json \
|
|
|
710
721
|
|
|
711
722
|
**Guides:**
|
|
712
723
|
|
|
713
|
-
- [Check Reference](docs/
|
|
714
|
-
- [Configuration Guide](docs/configuration.md) - Customize checks and behavior
|
|
715
|
-
- [GitHub Actions Guide](docs/github-actions
|
|
716
|
-
- [Python Library Guide](docs/
|
|
717
|
-
- [Trust Policy
|
|
718
|
-
- [
|
|
724
|
+
- [Check Reference](docs/user-guide/checks/) - All checks with examples
|
|
725
|
+
- [Configuration Guide](docs/user-guide/configuration.md) - Customize checks and behavior
|
|
726
|
+
- [GitHub Actions Guide](docs/integrations/github-actions.md) - CI/CD integration
|
|
727
|
+
- [Python Library Guide](docs/developer-guide/sdk/) - Use as Python package
|
|
728
|
+
- [Trust Policy Examples](examples/trust-policies/) - Trust policy validation examples
|
|
729
|
+
- [Changelog](CHANGELOG.md) - Version history and migration guides
|
|
719
730
|
|
|
720
731
|
**Examples:**
|
|
721
732
|
|
|
@@ -1,76 +1,78 @@
|
|
|
1
1
|
iam_validator/__init__.py,sha256=xHdUASOxFHwEXfT_GSr_KrkLlnxZ-pAAr1wW1PwAGko,693
|
|
2
2
|
iam_validator/__main__.py,sha256=to_nz3n_IerJpVVZZ6WSFlFR5s_06J0csfPOTfQZG8g,197
|
|
3
|
-
iam_validator/__version__.py,sha256=
|
|
4
|
-
iam_validator/checks/__init__.py,sha256=
|
|
3
|
+
iam_validator/__version__.py,sha256=nBQw8c9_j3cm0AjlGzltWfPi7BYKIJlC0VQImhHNMGQ,374
|
|
4
|
+
iam_validator/checks/__init__.py,sha256=wFU5Lz-ZIQBcn2y1u0Kl88B--vEO3btOOaTGPPSjJ74,2106
|
|
5
5
|
iam_validator/checks/action_condition_enforcement.py,sha256=2-XUMbof9tQ7SHZNmAHMkR1DgbOIzY2eFWlp9S9dwLk,60625
|
|
6
6
|
iam_validator/checks/action_resource_matching.py,sha256=qND0hfDgNoxFEdLWwrxOPVDfdj3k50nzedT2qF7nK7o,19428
|
|
7
|
-
iam_validator/checks/action_validation.py,sha256=
|
|
7
|
+
iam_validator/checks/action_validation.py,sha256=gy9_mujYbojBboLk0WwuJYJjggrY2sRwHAFvJnoLTYE,4823
|
|
8
8
|
iam_validator/checks/condition_key_validation.py,sha256=5i8LqqV78SjWK6pLrbttWmeMAD4pDC12_FjTjx5dFSU,4024
|
|
9
9
|
iam_validator/checks/condition_type_mismatch.py,sha256=KJp7zQHDd8VeTcfjcD-ur3S4070cXEDTWkFtxfp7CuE,10652
|
|
10
10
|
iam_validator/checks/full_wildcard.py,sha256=0TkkHtV0MZ6nZtJRtGdn3wwOMM96TRyGO7l7mmdHNUo,2325
|
|
11
11
|
iam_validator/checks/mfa_condition_check.py,sha256=y1LbqcvQ_fL2BPTNaKRQoBYM5hM7JET9cDPUOWKFEVs,4814
|
|
12
|
+
iam_validator/checks/not_action_not_resource.py,sha256=WWKOCLCq7yxOG9tgi1n5xPpphTLZ9RfcfPwZ-TP6n9Y,8097
|
|
12
13
|
iam_validator/checks/policy_size.py,sha256=eJd36Nj4gqWLIkQ5imhHR1hGtQ6T-iJsC22Wd1VSUf0,4681
|
|
13
14
|
iam_validator/checks/policy_structure.py,sha256=LExdm93JeqsyhikWrh9lfJ9sBiZ4818Ts0-N3MwUrtk,22089
|
|
14
15
|
iam_validator/checks/policy_type_validation.py,sha256=-Q2Yn_sa7Cba_Fb9ESxSL5qNbRpncuC7NQy7R_fdJtY,16521
|
|
15
16
|
iam_validator/checks/principal_validation.py,sha256=TthgDW5YXFfv5li1u4nn56k0Feqt5HeOEtQgo5pBKqo,27911
|
|
16
|
-
iam_validator/checks/resource_validation.py,sha256=
|
|
17
|
+
iam_validator/checks/resource_validation.py,sha256=k7qHIwX7IDf4MCWIvl9G17aINzTuZLOHDHRWrujbCaM,7787
|
|
17
18
|
iam_validator/checks/sensitive_action.py,sha256=LHicl6dd5E1JV19cLKvFAMGzLzYr5h_Y7QvS8s57kvA,18952
|
|
18
19
|
iam_validator/checks/service_wildcard.py,sha256=1epcET5oDclAmzxhtmQfKBg3Q5Rl4VXBMoZouxCJLpM,4114
|
|
19
20
|
iam_validator/checks/set_operator_validation.py,sha256=GMZ1OWqySptYWV7565-K4R5ODs1eYgWXDozwtU-3sgY,7422
|
|
20
21
|
iam_validator/checks/sid_uniqueness.py,sha256=MPQwALBjcvbY4Q55mpxDrGMqmVCMb13YSg621YbQYF8,6048
|
|
21
22
|
iam_validator/checks/trust_policy_validation.py,sha256=r3fM2hU7W0yCFS6hbd4ZSlD8y2tm0zk99mUVlIt0LsI,17956
|
|
22
23
|
iam_validator/checks/wildcard_action.py,sha256=VhWezb1JXmFnwV9WKgVu-48ythScGfZasg8fFd6tAG4,2001
|
|
23
|
-
iam_validator/checks/wildcard_resource.py,sha256=
|
|
24
|
+
iam_validator/checks/wildcard_resource.py,sha256=YO2I4q0QssOyjFrG62Yz148n3yRUJPTm_LD-bkVQj28,22351
|
|
24
25
|
iam_validator/checks/utils/__init__.py,sha256=iI9jHIDlDuuPK2vxjJA-qc927PaWC9zVJb9z3vBRUsQ,356
|
|
25
26
|
iam_validator/checks/utils/action_parser.py,sha256=zA_NGknc5gJvsmIlf4aC14eHFIkBLyL9if5ad80gHwY,4421
|
|
26
27
|
iam_validator/checks/utils/policy_level_checks.py,sha256=pr-uLo-otB612YLZ-rd8W5Kl9ENaTHuzTNOUhQaULKc,7593
|
|
27
28
|
iam_validator/checks/utils/sensitive_action_matcher.py,sha256=qDXcJa_2sCJu9pBbjDlI7x5lPtLRc6jQCpKPMheCOJQ,11215
|
|
28
29
|
iam_validator/checks/utils/wildcard_expansion.py,sha256=3W13hlyWcP2wJ6w-BwM887VOnRzglK6Bk3eHMjUtOco,3131
|
|
29
|
-
iam_validator/commands/__init__.py,sha256=
|
|
30
|
+
iam_validator/commands/__init__.py,sha256=BgtZqCIazIhCpQIw49J8hOG853Y-sltg4w-SsSEDr14,793
|
|
30
31
|
iam_validator/commands/analyze.py,sha256=rtXZmevC7GCXrADoGrxihRkrLbma59wMAMP2yBhqWPU,21752
|
|
31
32
|
iam_validator/commands/base.py,sha256=5baCCMwxz7pdQ6XMpWfXFNz7i1l5dB8Qv9dKKR04Gzs,1074
|
|
32
|
-
iam_validator/commands/cache.py,sha256=
|
|
33
|
-
iam_validator/commands/completion.py,sha256=
|
|
33
|
+
iam_validator/commands/cache.py,sha256=ZMfNe1HfKlCKESqa-9OkBcgZUqAIcV6m7rDrBxLq700,16162
|
|
34
|
+
iam_validator/commands/completion.py,sha256=mrvGoOOYJVC68SJbqmEJYBvqDHsDVm_4kLRbl15TtHY,23265
|
|
34
35
|
iam_validator/commands/download_services.py,sha256=KKz3ybMLT8DQUf9aFZ0tilJ-o1b6PE8Pf1pC4K6cT8I,9175
|
|
36
|
+
iam_validator/commands/mcp.py,sha256=ttJXeWvV9GIK7ipa5xjS0gMjRjw3qcuRhJajF_8_rrU,6315
|
|
35
37
|
iam_validator/commands/post_to_pr.py,sha256=CvUXs2xvO-UhluxdfNM6F0TCWD8hDBEOiYw60fm1Dms,2363
|
|
36
|
-
iam_validator/commands/query.py,sha256=
|
|
38
|
+
iam_validator/commands/query.py,sha256=6EQc3mGRqTZ8k8-yMNMBzV6vLCI0NaP-1P5zeAL1Vvo,35948
|
|
37
39
|
iam_validator/commands/validate.py,sha256=4wk-eSwhgqnQvyUre426S831JadVUctb0FDeCZD4RTk,34176
|
|
38
40
|
iam_validator/core/__init__.py,sha256=hYXkSbxplKzhM6dqrVzV4M3k7GKLsZbgExypxKq74gs,376
|
|
39
41
|
iam_validator/core/access_analyzer.py,sha256=mtMaY-FnKjKEVITky_9ywZe1FaCAm61ElRv5Z_ZeC7E,24562
|
|
40
42
|
iam_validator/core/access_analyzer_report.py,sha256=UMm2RNGj2rAKav1zsCw_htQZZRwRC0jjayd2zvKma1A,24896
|
|
41
43
|
iam_validator/core/aws_fetcher.py,sha256=op93QvtGmeLF9dHobl2IuoPDeunn33pBLb8h7XjtmoQ,920
|
|
42
|
-
iam_validator/core/check_registry.py,sha256=
|
|
44
|
+
iam_validator/core/check_registry.py,sha256=cRvFko_cTrip94VgVqwkxgrjR6oz3JfSiwertESicRc,28567
|
|
43
45
|
iam_validator/core/cli.py,sha256=PkXiZjlgrQ21QustBbspefYsdbxst4gxoClyG2_HQR8,3843
|
|
44
46
|
iam_validator/core/codeowners.py,sha256=dfRjYTpcTVmc-h95i4EoPXCXlcblD8yryeJBaTKQfjM,7530
|
|
45
47
|
iam_validator/core/condition_validators.py,sha256=7zBjlcf2xGFKGbcFrXSLvWT5tFhWxoqwzhsJqS2E8uY,21524
|
|
46
|
-
iam_validator/core/constants.py,sha256=
|
|
48
|
+
iam_validator/core/constants.py,sha256=O80dQ6AtgsCJPempRtNlKaSIVE61rg6YDPV5vgaSnAY,7771
|
|
47
49
|
iam_validator/core/diff_parser.py,sha256=5Jxa6WvQZtG5grblZeUH2OQ2R46tFLK-h8tvkHOSfLk,12110
|
|
48
50
|
iam_validator/core/finding_fingerprint.py,sha256=NJIlu8NhdenWbLS7ww8LyWFasJgpKWN63-DprrNW7Zs,4353
|
|
49
51
|
iam_validator/core/ignore_patterns.py,sha256=pZqDJBtkbck-85QK5eFPM5ZOPEKs3McRh3avqiCT5z0,10398
|
|
50
52
|
iam_validator/core/ignore_processor.py,sha256=zgWfS-4BU4c_W6VxUxHIHorMtB5XzB410wZ3bbzVgH8,10686
|
|
51
53
|
iam_validator/core/ignored_findings.py,sha256=b4PySz46so1rGKNt4prg2dkysHPfTJP4wsHYorVn1FA,12756
|
|
52
54
|
iam_validator/core/label_manager.py,sha256=qKQ60shsW8yJELkHgd9rXgzLW9oKErPd4hFTTQkHjbI,8776
|
|
53
|
-
iam_validator/core/models.py,sha256=
|
|
55
|
+
iam_validator/core/models.py,sha256=QgL1p5-GEPOSEi6VB-eqHR0dHH4Akq0bI_r-yVa2V9c,17060
|
|
54
56
|
iam_validator/core/policy_checks.py,sha256=FNVuS2GTffwCjjrlupVIazC172gSxKYAAT_ObV6Apbo,8803
|
|
55
57
|
iam_validator/core/policy_loader.py,sha256=iid3mGfDzSXASzKDqbLnrqJHBdVQvvebofVqNImsGKM,29201
|
|
56
58
|
iam_validator/core/pr_commenter.py,sha256=IZu2FQqzw73U_8ugTUq197ECLqk9mRCQpTWXPu5qk0k,35490
|
|
57
59
|
iam_validator/core/report.py,sha256=IDjBjSrzrE_JdkA8eTiSxyUL3g36sJMhTkxehEYzuBQ,45476
|
|
58
|
-
iam_validator/core/aws_service/__init__.py,sha256=
|
|
59
|
-
iam_validator/core/aws_service/cache.py,sha256=
|
|
60
|
+
iam_validator/core/aws_service/__init__.py,sha256=vSmYBn6GGeEcRxxyBmeKcBHFioZlWWBEwbvXmE6ZXVk,800
|
|
61
|
+
iam_validator/core/aws_service/cache.py,sha256=HkxBLCkgf9VYOZKVZd_MidR_TOlUkwbvX3D421ADFZ8,4421
|
|
60
62
|
iam_validator/core/aws_service/client.py,sha256=Zv7rIpEFdUCDXKGp3migPDkj8L5eZltgrGe64M2t2Ko,7336
|
|
61
|
-
iam_validator/core/aws_service/fetcher.py,sha256=
|
|
63
|
+
iam_validator/core/aws_service/fetcher.py,sha256=TqaCp6yKOEXCJdcQIFVBB5RW0pxLMOmQXjJFHZsrBr4,31209
|
|
62
64
|
iam_validator/core/aws_service/parsers.py,sha256=gJzR7HCD8ItCWCCbguTQIZpPEdj2rdMwC7LPhu7ve14,5174
|
|
63
65
|
iam_validator/core/aws_service/patterns.py,sha256=gGc55Tn-EJ3cmcWtmYAZROUajKYz7DaMchYWGEhHpC0,1726
|
|
64
|
-
iam_validator/core/aws_service/storage.py,sha256=
|
|
65
|
-
iam_validator/core/aws_service/validators.py,sha256=
|
|
66
|
+
iam_validator/core/aws_service/storage.py,sha256=A98ui_THAyZ86ik-t6HWB22vOqwmbFklG10uhdf26p4,10881
|
|
67
|
+
iam_validator/core/aws_service/validators.py,sha256=qWMB4iQi9Oc0SGXOJVrlyjnsMwmPlqhUaywyRL4d-hM,19385
|
|
66
68
|
iam_validator/core/config/__init__.py,sha256=CWSyIA7kEyzrskEenjYbs9Iih10BXRpiY9H2dHg61rU,2671
|
|
67
69
|
iam_validator/core/config/aws_api.py,sha256=HLIzOItQ0A37wxHcgWck6ZFO0wmNY8JNTiWMMK6JKYU,1248
|
|
68
|
-
iam_validator/core/config/aws_global_conditions.py,sha256=
|
|
70
|
+
iam_validator/core/config/aws_global_conditions.py,sha256=Ny20rnwp0OGxW8NdrHw8d3Lv3wh8YbL5vCIFQw7ZQh4,8006
|
|
69
71
|
iam_validator/core/config/category_suggestions.py,sha256=fopaZ9kXDrsLgi_r0pERrLwgdPPJl5VIiKvXtQK9tj0,8583
|
|
70
|
-
iam_validator/core/config/check_documentation.py,sha256
|
|
72
|
+
iam_validator/core/config/check_documentation.py,sha256=-wK6-wfU7SEHX3h2Jj5pOFqgxD9ULW-NvEkSVp_66WA,18718
|
|
71
73
|
iam_validator/core/config/condition_requirements.py,sha256=1CeQJfWV-Y2ImW0Mq9YdrgvH-hj9IXe0gVOm3B36Rc8,10655
|
|
72
|
-
iam_validator/core/config/config_loader.py,sha256=
|
|
73
|
-
iam_validator/core/config/defaults.py,sha256=
|
|
74
|
+
iam_validator/core/config/config_loader.py,sha256=Fohz9R-H5edYMYXoT3HkjmsmZE32rjLWlAjnZaz1Xrc,25649
|
|
75
|
+
iam_validator/core/config/defaults.py,sha256=EKlmfX04IGPb4Qs9ctqrStoJ-_LAGEr2PWTJX9fjenk,38920
|
|
74
76
|
iam_validator/core/config/principal_requirements.py,sha256=VCX7fBDgeDTJQyoz7_x7GI7Kf9O1Eu-sbihoHOrKv6o,15105
|
|
75
77
|
iam_validator/core/config/sensitive_actions.py,sha256=uATDIp_TD3OQQlsYTZp79qd1mSK2Bf9hJ0JwcqLBr84,25344
|
|
76
78
|
iam_validator/core/config/service_principals.py,sha256=8pys5H_yycVJ9KTyimAKFYBg83Aol2Iri53wiHjtnEM,3959
|
|
@@ -87,20 +89,31 @@ iam_validator/core/formatters/sarif.py,sha256=03MHSyuZm9FlzaPeWg7wH-UTzzCDhSy6vM
|
|
|
87
89
|
iam_validator/integrations/__init__.py,sha256=7Hlor_X9j0NZaEjFuSvoXAAuSKQ-zgY19Rk-Dz3JpKo,616
|
|
88
90
|
iam_validator/integrations/github_integration.py,sha256=0aeQ_RPTZf5ij7dsBjmtIDz4oHl0BXLno9GperFzTbc,69004
|
|
89
91
|
iam_validator/integrations/ms_teams.py,sha256=t2PlWuTDb6GGH-eDU1jnOKd8D1w4FCB68bahGA7MJcE,14475
|
|
90
|
-
iam_validator/
|
|
92
|
+
iam_validator/mcp/__init__.py,sha256=dHCPuxLNKG3EMDYTBum8FTdskoebWJN6TaC03rkcnYQ,4927
|
|
93
|
+
iam_validator/mcp/models.py,sha256=EJaDHaGdVvNzSauxYH3L4hmfbtBLLyzuHX_CbXOZr8Q,4473
|
|
94
|
+
iam_validator/mcp/server.py,sha256=V_d4SmNSNMsPG6nul6II0G9GyvWiAvfnMX5B9_U3RQw,108422
|
|
95
|
+
iam_validator/mcp/session_config.py,sha256=dtzPqHVycpMUQH7qG68LW7ZikUz6APJrzttyFZkXwak,10336
|
|
96
|
+
iam_validator/mcp/templates/__init__.py,sha256=OY1C7Af9O46W5-A2TEuZb3jB7gwrG6N-dZ-LQS6FHpw,2408
|
|
97
|
+
iam_validator/mcp/templates/builtin.py,sha256=3cSPOqAzSQSWY2rBEwQ_sTHHKxur64NVASe0kVErbS8,31032
|
|
98
|
+
iam_validator/mcp/tools/__init__.py,sha256=JqFaQaBpavPpGEWF_GIY6YIXWhIL4kDcKCZQvUzmZyE,2040
|
|
99
|
+
iam_validator/mcp/tools/generation.py,sha256=R_pSLv5uxMyg6Pj-TEY2fY5UV9Pd1mh-P9A44Nvws-I,37124
|
|
100
|
+
iam_validator/mcp/tools/org_config_tools.py,sha256=Y13srYplK3SRIxpK3Sat9TocanThcrF8hWblcS7sJhI,7754
|
|
101
|
+
iam_validator/mcp/tools/query.py,sha256=05X0dhNGY0KcmyKJIn9vYw2ed3yGlFnRC2rqOoyVMLQ,13316
|
|
102
|
+
iam_validator/mcp/tools/validation.py,sha256=XrG7rBGbHnpeZSgNZdfNWyD3XeZwmdBTj-w5ErLOt2c,13219
|
|
103
|
+
iam_validator/sdk/__init__.py,sha256=rfWkijjIA8iKrHE2Wd1HnXAl0jJWHHwYgUFZeISQGiI,6297
|
|
91
104
|
iam_validator/sdk/arn_matching.py,sha256=HSDpLltOYISq-SoPebAlM89mKOaUaghq_04urchEFDA,12778
|
|
92
|
-
iam_validator/sdk/context.py,sha256=
|
|
105
|
+
iam_validator/sdk/context.py,sha256=b2XXlvsnqxl42d1wsdoynTqsZOy8nRjV73RgxIdKdPQ,6940
|
|
93
106
|
iam_validator/sdk/exceptions.py,sha256=tm91TxIwU157U_UHN7w5qICf_OhU11agj6pV5W_YP-4,1023
|
|
94
107
|
iam_validator/sdk/helpers.py,sha256=sjfK0na_Fo7O8GhEVhl44rVHqOdw6nAKkBL4FVL-QdU,5697
|
|
95
|
-
iam_validator/sdk/policy_utils.py,sha256=
|
|
108
|
+
iam_validator/sdk/policy_utils.py,sha256=zSn3UFdwr5pik-n1Y4pv_AZheyCuFqaGlSIt403L0is,14386
|
|
96
109
|
iam_validator/sdk/query_utils.py,sha256=kp1sORVnouRMt7kvzyZo1569l7j20jJGmHICR7O8Cqs,14455
|
|
97
110
|
iam_validator/sdk/shortcuts.py,sha256=EVNSYV7rv4TFH03ulsZ3mS1UVmTSp2jKpc2AXs4j1q4,8531
|
|
98
111
|
iam_validator/utils/__init__.py,sha256=NveA2F3G1E6-ANZzFr7J6Q6u5mogvMp862iFokmYuCs,1021
|
|
99
112
|
iam_validator/utils/cache.py,sha256=wOQKOBeoG6QqC5f0oXcHz63Cjtu_-SsSS-0pTSwyAiM,3254
|
|
100
113
|
iam_validator/utils/regex.py,sha256=xHoMECttb7qaMhts-c9b0GIxdhHNZTt-UBr7wNhWfzg,6219
|
|
101
114
|
iam_validator/utils/terminal.py,sha256=FsRaRMH_JAyDgXWBCOgOEhbS89cs17HCmKYoughq5io,724
|
|
102
|
-
iam_policy_validator-1.
|
|
103
|
-
iam_policy_validator-1.
|
|
104
|
-
iam_policy_validator-1.
|
|
105
|
-
iam_policy_validator-1.
|
|
106
|
-
iam_policy_validator-1.
|
|
115
|
+
iam_policy_validator-1.15.0.dist-info/METADATA,sha256=CkJmAGo-FcnQ0qpEb0_EDjNcbKRzTErYiIic3gUyHD8,34808
|
|
116
|
+
iam_policy_validator-1.15.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
117
|
+
iam_policy_validator-1.15.0.dist-info/entry_points.txt,sha256=VXAcx1evo9fuxX0Gtj3J2HnzWcBHSXugiZwBtQ1BXE0,162
|
|
118
|
+
iam_policy_validator-1.15.0.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
|
|
119
|
+
iam_policy_validator-1.15.0.dist-info/RECORD,,
|
iam_validator/__version__.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This file is the single source of truth for the package version.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
__version__ = "1.
|
|
6
|
+
__version__ = "1.15.0"
|
|
7
7
|
# Parse version, handling pre-release suffixes like -rc, -alpha, -beta
|
|
8
8
|
_version_base = __version__.split("-", maxsplit=1)[0] # Remove pre-release suffix if present
|
|
9
9
|
__version_info__ = tuple(int(part) for part in _version_base.split("."))
|
iam_validator/checks/__init__.py
CHANGED
|
@@ -11,6 +11,7 @@ from iam_validator.checks.condition_key_validation import ConditionKeyValidation
|
|
|
11
11
|
from iam_validator.checks.condition_type_mismatch import ConditionTypeMismatchCheck
|
|
12
12
|
from iam_validator.checks.full_wildcard import FullWildcardCheck
|
|
13
13
|
from iam_validator.checks.mfa_condition_check import MFAConditionCheck
|
|
14
|
+
from iam_validator.checks.not_action_not_resource import NotActionNotResourceCheck
|
|
14
15
|
from iam_validator.checks.policy_size import PolicySizeCheck
|
|
15
16
|
from iam_validator.checks.policy_structure import PolicyStructureCheck
|
|
16
17
|
from iam_validator.checks.principal_validation import PrincipalValidationCheck
|
|
@@ -31,6 +32,7 @@ __all__ = [
|
|
|
31
32
|
"ConditionTypeMismatchCheck",
|
|
32
33
|
"FullWildcardCheck",
|
|
33
34
|
"MFAConditionCheck",
|
|
35
|
+
"NotActionNotResourceCheck",
|
|
34
36
|
"PolicySizeCheck",
|
|
35
37
|
"PolicyStructureCheck",
|
|
36
38
|
"PrincipalValidationCheck",
|
|
@@ -9,6 +9,7 @@ validations. However, it can be useful in environments where Access Analyzer is
|
|
|
9
9
|
not available or for pre-deployment policy validation to catch errors early.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
+
import asyncio
|
|
12
13
|
from typing import ClassVar
|
|
13
14
|
|
|
14
15
|
from iam_validator.core.aws_service import AWSServiceFetcher
|
|
@@ -23,6 +24,51 @@ class ActionValidationCheck(PolicyCheck):
|
|
|
23
24
|
description: ClassVar[str] = "Validates that actions exist in AWS service definitions"
|
|
24
25
|
default_severity: ClassVar[str] = "error"
|
|
25
26
|
|
|
27
|
+
async def _validate_action(
|
|
28
|
+
self,
|
|
29
|
+
action: str,
|
|
30
|
+
fetcher: AWSServiceFetcher,
|
|
31
|
+
config: CheckConfig,
|
|
32
|
+
statement_sid: str | None,
|
|
33
|
+
statement_idx: int,
|
|
34
|
+
line_number: int | None,
|
|
35
|
+
field_name: str,
|
|
36
|
+
) -> ValidationIssue | None:
|
|
37
|
+
"""Validate a single action and return an issue if invalid.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
action: The action string to validate (e.g., "s3:GetObject")
|
|
41
|
+
fetcher: AWS service fetcher for validation
|
|
42
|
+
config: Check configuration
|
|
43
|
+
statement_sid: Statement ID for error reporting
|
|
44
|
+
statement_idx: Statement index for error reporting
|
|
45
|
+
line_number: Line number for error reporting
|
|
46
|
+
field_name: Field name ("action" or "not_action") for error reporting
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
ValidationIssue if action is invalid, None otherwise
|
|
50
|
+
"""
|
|
51
|
+
# Skip full wildcard - it's valid but handled by security checks
|
|
52
|
+
if action == "*":
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
# Validate the action exists in AWS (handles both exact and wildcard patterns)
|
|
56
|
+
is_valid, error_msg, _is_wildcard = await fetcher.validate_action(action)
|
|
57
|
+
|
|
58
|
+
if not is_valid:
|
|
59
|
+
return ValidationIssue(
|
|
60
|
+
severity=self.get_severity(config),
|
|
61
|
+
statement_sid=statement_sid,
|
|
62
|
+
statement_index=statement_idx,
|
|
63
|
+
issue_type="invalid_action",
|
|
64
|
+
message=error_msg or f"Invalid action: `{action}`",
|
|
65
|
+
action=action,
|
|
66
|
+
line_number=line_number,
|
|
67
|
+
field_name=field_name,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return None
|
|
71
|
+
|
|
26
72
|
async def execute(
|
|
27
73
|
self,
|
|
28
74
|
statement: Statement,
|
|
@@ -32,36 +78,54 @@ class ActionValidationCheck(PolicyCheck):
|
|
|
32
78
|
) -> list[ValidationIssue]:
|
|
33
79
|
"""Execute action validation on a statement.
|
|
34
80
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
""
|
|
38
|
-
|
|
81
|
+
Validates both Action and NotAction fields to ensure all specified
|
|
82
|
+
actions exist in AWS service definitions. Wildcard patterns like
|
|
83
|
+
"s3:Get*" are validated to ensure they match at least one real action.
|
|
84
|
+
|
|
85
|
+
Actions are validated in parallel for better performance.
|
|
39
86
|
|
|
40
|
-
|
|
41
|
-
|
|
87
|
+
Security implications of wildcards are handled by separate checks
|
|
88
|
+
(wildcard_action, service_wildcard, etc.).
|
|
89
|
+
"""
|
|
42
90
|
statement_sid = statement.sid
|
|
43
91
|
line_number = statement.line_number
|
|
44
92
|
|
|
45
|
-
for
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
issue_type="invalid_action",
|
|
60
|
-
message=error_msg or f"Invalid action: `{action}`",
|
|
61
|
-
action=action,
|
|
62
|
-
line_number=line_number,
|
|
63
|
-
field_name="action",
|
|
64
|
-
)
|
|
93
|
+
# Build list of validation tasks for parallel execution
|
|
94
|
+
tasks = []
|
|
95
|
+
|
|
96
|
+
# Validate Action field
|
|
97
|
+
for action in statement.get_actions():
|
|
98
|
+
tasks.append(
|
|
99
|
+
self._validate_action(
|
|
100
|
+
action=action,
|
|
101
|
+
fetcher=fetcher,
|
|
102
|
+
config=config,
|
|
103
|
+
statement_sid=statement_sid,
|
|
104
|
+
statement_idx=statement_idx,
|
|
105
|
+
line_number=line_number,
|
|
106
|
+
field_name="action",
|
|
65
107
|
)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Validate NotAction field (same validation - typos in NotAction are equally problematic)
|
|
111
|
+
for action in statement.get_not_actions():
|
|
112
|
+
tasks.append(
|
|
113
|
+
self._validate_action(
|
|
114
|
+
action=action,
|
|
115
|
+
fetcher=fetcher,
|
|
116
|
+
config=config,
|
|
117
|
+
statement_sid=statement_sid,
|
|
118
|
+
statement_idx=statement_idx,
|
|
119
|
+
line_number=line_number,
|
|
120
|
+
field_name="not_action",
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Execute all validations in parallel
|
|
125
|
+
if not tasks:
|
|
126
|
+
return []
|
|
127
|
+
|
|
128
|
+
results = await asyncio.gather(*tasks)
|
|
66
129
|
|
|
67
|
-
|
|
130
|
+
# Filter out None results (valid actions)
|
|
131
|
+
return [issue for issue in results if issue is not None]
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""NotAction/NotResource check - detects dangerous Not* patterns in IAM policies.
|
|
2
|
+
|
|
3
|
+
NotAction and NotResource are powerful IAM features that can be misused to
|
|
4
|
+
grant overly broad permissions. This check detects patterns that violate
|
|
5
|
+
the principle of least privilege.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import ClassVar
|
|
9
|
+
|
|
10
|
+
from iam_validator.core.aws_service import AWSServiceFetcher
|
|
11
|
+
from iam_validator.core.check_registry import CheckConfig, PolicyCheck
|
|
12
|
+
from iam_validator.core.models import Statement, ValidationIssue
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class NotActionNotResourceCheck(PolicyCheck):
|
|
16
|
+
"""Checks for dangerous NotAction/NotResource patterns.
|
|
17
|
+
|
|
18
|
+
Patterns detected:
|
|
19
|
+
1. NotAction with Effect: Allow - grants everything EXCEPT listed actions
|
|
20
|
+
2. NotResource with wildcards - grants access to all resources except listed
|
|
21
|
+
3. NotAction in Allow without strict conditions - missing safeguards
|
|
22
|
+
|
|
23
|
+
These patterns are particularly dangerous because they grant permissions
|
|
24
|
+
by exclusion rather than explicit inclusion, making it easy to accidentally
|
|
25
|
+
grant more access than intended.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
check_id: ClassVar[str] = "not_action_not_resource"
|
|
29
|
+
description: ClassVar[str] = "Checks for dangerous NotAction/NotResource patterns"
|
|
30
|
+
default_severity: ClassVar[str] = "high"
|
|
31
|
+
|
|
32
|
+
async def execute(
|
|
33
|
+
self,
|
|
34
|
+
statement: Statement,
|
|
35
|
+
statement_idx: int,
|
|
36
|
+
fetcher: AWSServiceFetcher,
|
|
37
|
+
config: CheckConfig,
|
|
38
|
+
) -> list[ValidationIssue]:
|
|
39
|
+
"""Execute NotAction/NotResource check on a statement."""
|
|
40
|
+
del fetcher # Unused
|
|
41
|
+
|
|
42
|
+
issues = []
|
|
43
|
+
|
|
44
|
+
not_actions = statement.get_not_actions()
|
|
45
|
+
not_resources = statement.get_not_resources()
|
|
46
|
+
effect = statement.effect
|
|
47
|
+
|
|
48
|
+
# Check 1: NotAction with Effect: Allow
|
|
49
|
+
# This grants ALL actions EXCEPT the listed ones - extremely dangerous
|
|
50
|
+
if not_actions and effect == "Allow":
|
|
51
|
+
has_conditions = bool(statement.condition)
|
|
52
|
+
|
|
53
|
+
if has_conditions:
|
|
54
|
+
# NotAction with conditions is still risky but less severe
|
|
55
|
+
issues.append(
|
|
56
|
+
ValidationIssue(
|
|
57
|
+
severity="medium",
|
|
58
|
+
statement_sid=statement.sid,
|
|
59
|
+
statement_index=statement_idx,
|
|
60
|
+
issue_type="not_action_allow",
|
|
61
|
+
message=(
|
|
62
|
+
"Statement uses NotAction with Allow effect. "
|
|
63
|
+
"This grants ALL actions except the listed ones. "
|
|
64
|
+
"While conditions are present, this pattern is still risky."
|
|
65
|
+
),
|
|
66
|
+
suggestion=(
|
|
67
|
+
"Consider using explicit Action lists instead of NotAction. "
|
|
68
|
+
"If NotAction is required, ensure conditions are comprehensive."
|
|
69
|
+
),
|
|
70
|
+
example='{\n "Effect": "Allow",\n "Action": ["s3:GetObject", "s3:ListBucket"],\n "Resource": "*"\n}',
|
|
71
|
+
line_number=statement.line_number,
|
|
72
|
+
field_name="action",
|
|
73
|
+
action=", ".join(not_actions[:3]) + ("..." if len(not_actions) > 3 else ""),
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
else:
|
|
77
|
+
# NotAction Allow without conditions is critical
|
|
78
|
+
issues.append(
|
|
79
|
+
ValidationIssue(
|
|
80
|
+
severity=self.get_severity(config),
|
|
81
|
+
statement_sid=statement.sid,
|
|
82
|
+
statement_index=statement_idx,
|
|
83
|
+
issue_type="not_action_allow_no_condition",
|
|
84
|
+
message=(
|
|
85
|
+
"Statement uses NotAction with Allow effect and NO conditions. "
|
|
86
|
+
f"This grants ALL AWS actions except: {', '.join(not_actions[:5])}"
|
|
87
|
+
f"{'...' if len(not_actions) > 5 else ''}. "
|
|
88
|
+
"This is equivalent to granting near-administrator access."
|
|
89
|
+
),
|
|
90
|
+
suggestion=(
|
|
91
|
+
"Replace NotAction with explicit Action list. "
|
|
92
|
+
"If NotAction is required, add strict conditions like "
|
|
93
|
+
"aws:SourceIp, aws:PrincipalArn, or aws:MultiFactorAuthPresent."
|
|
94
|
+
),
|
|
95
|
+
example='{\n "Effect": "Allow",\n "Action": ["specific:Action"],\n "Resource": "*",\n "Condition": {\n "Bool": {"aws:MultiFactorAuthPresent": "true"}\n }\n}',
|
|
96
|
+
line_number=statement.line_number,
|
|
97
|
+
field_name="action",
|
|
98
|
+
action=", ".join(not_actions[:3]) + ("..." if len(not_actions) > 3 else ""),
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Check 2: NotResource with wildcards or broad patterns
|
|
103
|
+
if not_resources and effect == "Allow":
|
|
104
|
+
# Check if NotResource is used with wildcard Resource
|
|
105
|
+
resources = statement.get_resources()
|
|
106
|
+
has_wildcard_resource = "*" in resources or any("*" in r for r in resources)
|
|
107
|
+
|
|
108
|
+
if has_wildcard_resource or not resources:
|
|
109
|
+
issues.append(
|
|
110
|
+
ValidationIssue(
|
|
111
|
+
severity=self.get_severity(config),
|
|
112
|
+
statement_sid=statement.sid,
|
|
113
|
+
statement_index=statement_idx,
|
|
114
|
+
issue_type="not_resource_broad",
|
|
115
|
+
message=(
|
|
116
|
+
"Statement uses NotResource with Allow effect and broad Resource. "
|
|
117
|
+
f"This grants access to ALL resources except: {', '.join(not_resources[:3])}"
|
|
118
|
+
f"{'...' if len(not_resources) > 3 else ''}."
|
|
119
|
+
),
|
|
120
|
+
suggestion=(
|
|
121
|
+
"Replace NotResource with explicit Resource ARNs. "
|
|
122
|
+
"Using NotResource grants access to all current and future resources "
|
|
123
|
+
"except those explicitly excluded."
|
|
124
|
+
),
|
|
125
|
+
example='{\n "Effect": "Allow",\n "Action": ["s3:GetObject"],\n "Resource": "arn:aws:s3:::my-bucket/*"\n}',
|
|
126
|
+
line_number=statement.line_number,
|
|
127
|
+
field_name="resource",
|
|
128
|
+
resource=", ".join(not_resources[:3])
|
|
129
|
+
+ ("..." if len(not_resources) > 3 else ""),
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Check 3: NotAction with Deny - less dangerous but worth noting
|
|
134
|
+
# NotAction with Deny means "deny everything except these actions"
|
|
135
|
+
# which is actually a valid deny pattern but should be reviewed
|
|
136
|
+
if not_actions and effect == "Deny":
|
|
137
|
+
resources = statement.get_resources()
|
|
138
|
+
has_wildcard_resource = "*" in resources
|
|
139
|
+
|
|
140
|
+
if has_wildcard_resource:
|
|
141
|
+
issues.append(
|
|
142
|
+
ValidationIssue(
|
|
143
|
+
severity="low",
|
|
144
|
+
statement_sid=statement.sid,
|
|
145
|
+
statement_index=statement_idx,
|
|
146
|
+
issue_type="not_action_deny_review",
|
|
147
|
+
message=(
|
|
148
|
+
"Statement uses NotAction with Deny effect on all resources. "
|
|
149
|
+
f"This denies everything except: {', '.join(not_actions[:5])}"
|
|
150
|
+
f"{'...' if len(not_actions) > 5 else ''}. "
|
|
151
|
+
"Review to ensure this is the intended behavior."
|
|
152
|
+
),
|
|
153
|
+
suggestion=(
|
|
154
|
+
"Verify that allowing only these specific actions is intended. "
|
|
155
|
+
"Consider if an explicit Allow list would be clearer."
|
|
156
|
+
),
|
|
157
|
+
line_number=statement.line_number,
|
|
158
|
+
field_name="action",
|
|
159
|
+
action=", ".join(not_actions[:3]) + ("..." if len(not_actions) > 3 else ""),
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
return issues
|