iam-policy-validator 1.14.7__py3-none-any.whl → 1.15.1__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.7.dist-info → iam_policy_validator-1.15.1.dist-info}/METADATA +16 -11
- {iam_policy_validator-1.14.7.dist-info → iam_policy_validator-1.15.1.dist-info}/RECORD +41 -28
- iam_policy_validator-1.15.1.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 +68 -51
- iam_validator/core/check_registry.py +100 -35
- iam_validator/core/config/aws_global_conditions.py +18 -9
- 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 +2 -0
- iam_validator/sdk/policy_utils.py +31 -5
- iam_policy_validator-1.14.7.dist-info/entry_points.txt +0 -2
- {iam_policy_validator-1.14.7.dist-info → iam_policy_validator-1.15.1.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.14.7.dist-info → iam_policy_validator-1.15.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iam-policy-validator
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.15.1
|
|
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
6
|
Project-URL: Documentation, https://boogy.github.io/iam-policy-validator
|
|
@@ -11,7 +11,7 @@ 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
|
|
@@ -44,6 +46,8 @@ Requires-Dist: mkdocs-literate-nav>=0.6.0; extra == 'docs'
|
|
|
44
46
|
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
|
|
45
47
|
Requires-Dist: mkdocs>=1.6.0; extra == 'docs'
|
|
46
48
|
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'docs'
|
|
49
|
+
Provides-Extra: mcp
|
|
50
|
+
Requires-Dist: fastmcp>=2.14.1; extra == 'mcp'
|
|
47
51
|
Description-Content-Type: text/markdown
|
|
48
52
|
|
|
49
53
|
# IAM Policy Validator
|
|
@@ -55,6 +59,8 @@ Description-Content-Type: text/markdown
|
|
|
55
59
|
[](LICENSE)
|
|
56
60
|
[](https://scorecard.dev/viewer/?uri=github.com/boogy/iam-policy-validator)
|
|
57
61
|
|
|
62
|
+
**[📖 Full Documentation](https://boogy.github.io/iam-policy-validator/)**
|
|
63
|
+
|
|
58
64
|
---
|
|
59
65
|
|
|
60
66
|
## Why This Tool Exists
|
|
@@ -434,15 +440,14 @@ Validates against official AWS IAM requirements:
|
|
|
434
440
|
|
|
435
441
|
Identifies overly permissive configurations:
|
|
436
442
|
|
|
437
|
-
| Check
|
|
438
|
-
|
|
|
439
|
-
| **Wildcard Action**
|
|
440
|
-
| **Wildcard Resource**
|
|
441
|
-
| **Full Wildcard**
|
|
442
|
-
| **Service Wildcards**
|
|
443
|
-
| **Sensitive Actions
|
|
444
|
-
| **
|
|
445
|
-
| **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 |
|
|
446
451
|
|
|
447
452
|
**Note on Sensitive Actions:** This check has two modes:
|
|
448
453
|
|
|
@@ -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=3sYnVKt3REhH-Klaa8pLaSXpDxcV1dV0Se9CjHHE4Nc,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=d2nGuy4NifbBiKbLIFHxP-wZctYDtK4qniSdq3l8-T0,21574
|
|
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=WQjR8z1Mhc8H874CnzwEMvKOz9rCifBNUltvo0oFYbM,7894
|
|
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
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.1.dist-info/METADATA,sha256=5U2vmBBtv-GXPRTflISPL-sOmq_kT9aWlDdOBsfbMnI,34808
|
|
116
|
+
iam_policy_validator-1.15.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
117
|
+
iam_policy_validator-1.15.1.dist-info/entry_points.txt,sha256=VXAcx1evo9fuxX0Gtj3J2HnzWcBHSXugiZwBtQ1BXE0,162
|
|
118
|
+
iam_policy_validator-1.15.1.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
|
|
119
|
+
iam_policy_validator-1.15.1.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.1"
|
|
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
|