iam-policy-validator 1.5.0__py3-none-any.whl → 1.6.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.5.0.dist-info → iam_policy_validator-1.6.0.dist-info}/METADATA +89 -60
- {iam_policy_validator-1.5.0.dist-info → iam_policy_validator-1.6.0.dist-info}/RECORD +40 -25
- iam_validator/__version__.py +1 -1
- iam_validator/checks/__init__.py +9 -3
- iam_validator/checks/action_condition_enforcement.py +164 -2
- iam_validator/checks/action_resource_matching.py +424 -0
- iam_validator/checks/condition_key_validation.py +3 -1
- iam_validator/checks/condition_type_mismatch.py +259 -0
- iam_validator/checks/mfa_condition_check.py +112 -0
- iam_validator/checks/sensitive_action.py +78 -6
- iam_validator/checks/set_operator_validation.py +157 -0
- iam_validator/checks/utils/sensitive_action_matcher.py +35 -1
- iam_validator/commands/cache.py +1 -1
- iam_validator/commands/validate.py +44 -11
- iam_validator/core/aws_fetcher.py +89 -52
- iam_validator/core/check_registry.py +165 -21
- iam_validator/core/condition_validators.py +626 -0
- iam_validator/core/config/__init__.py +13 -15
- iam_validator/core/config/aws_global_conditions.py +160 -0
- iam_validator/core/config/category_suggestions.py +104 -0
- iam_validator/core/config/condition_requirements.py +5 -385
- iam_validator/core/{config_loader.py → config/config_loader.py} +3 -0
- iam_validator/core/config/defaults.py +187 -54
- iam_validator/core/config/sensitive_actions.py +620 -81
- iam_validator/core/models.py +14 -1
- iam_validator/core/policy_checks.py +4 -4
- iam_validator/core/pr_commenter.py +1 -1
- iam_validator/sdk/__init__.py +187 -0
- iam_validator/sdk/arn_matching.py +274 -0
- iam_validator/sdk/context.py +222 -0
- iam_validator/sdk/exceptions.py +48 -0
- iam_validator/sdk/helpers.py +177 -0
- iam_validator/sdk/policy_utils.py +425 -0
- iam_validator/sdk/shortcuts.py +283 -0
- iam_validator/utils/__init__.py +31 -0
- iam_validator/utils/cache.py +105 -0
- iam_validator/utils/regex.py +206 -0
- iam_validator/checks/action_resource_constraint.py +0 -151
- iam_validator/core/aws_global_conditions.py +0 -137
- {iam_policy_validator-1.5.0.dist-info → iam_policy_validator-1.6.0.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.5.0.dist-info → iam_policy_validator-1.6.0.dist-info}/entry_points.txt +0 -0
- {iam_policy_validator-1.5.0.dist-info → iam_policy_validator-1.6.0.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.6.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
6
|
Project-URL: Documentation, https://github.com/boogy/iam-policy-validator/tree/main/docs
|
|
@@ -58,7 +58,7 @@ Description-Content-Type: text/markdown
|
|
|
58
58
|
|
|
59
59
|
**This tool prevents these issues** by:
|
|
60
60
|
- ✅ **Validating early** - Catch errors in PRs before merge
|
|
61
|
-
- ✅ **Comprehensive checks** - AWS Access Analyzer +
|
|
61
|
+
- ✅ **Comprehensive checks** - AWS Access Analyzer + 18 built-in security checks
|
|
62
62
|
- ✅ **Smart filtering** - Auto-detects IAM policies from mixed JSON/YAML files
|
|
63
63
|
- ✅ **Developer-friendly** - Clear error messages with fix suggestions
|
|
64
64
|
- ✅ **Zero setup** - Works as a GitHub Action out of the box
|
|
@@ -67,7 +67,7 @@ Description-Content-Type: text/markdown
|
|
|
67
67
|
|
|
68
68
|
### 🔍 Multi-Layer Validation
|
|
69
69
|
- **AWS IAM Access Analyzer** - Official AWS validation (syntax, permissions, security)
|
|
70
|
-
- **
|
|
70
|
+
- **18 Built-in Security Checks** - Comprehensive validation across AWS requirements and security best practices
|
|
71
71
|
- **Policy Comparison** - Detect new permissions vs baseline (prevent scope creep)
|
|
72
72
|
- **Public Access Detection** - Check 29+ AWS resource types for public exposure
|
|
73
73
|
- **Privilege Escalation Detection** - Identify dangerous action combinations
|
|
@@ -748,7 +748,7 @@ iam-validator analyze \
|
|
|
748
748
|
- **API**: API Gateway REST API
|
|
749
749
|
- **DevOps**: CodeArtifact Domain, Backup Vault, CloudTrail
|
|
750
750
|
|
|
751
|
-
See [docs/custom-
|
|
751
|
+
See [docs/custom-checks.md](docs/custom-checks.md) for complete documentation.
|
|
752
752
|
|
|
753
753
|
### As a Python Package
|
|
754
754
|
|
|
@@ -782,70 +782,96 @@ asyncio.run(main())
|
|
|
782
782
|
|
|
783
783
|
## Validation Checks
|
|
784
784
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
785
|
+
IAM Policy Validator performs **18 built-in checks** to ensure your policies are secure and valid.
|
|
786
|
+
|
|
787
|
+
**📖 For detailed check documentation with configuration examples and pass/fail scenarios:**
|
|
788
|
+
- **[Check Reference Guide](docs/check-reference.md)** - Complete reference for all 18 checks
|
|
789
|
+
- **[Condition Requirements](docs/condition-requirements.md)** - Action condition enforcement
|
|
790
|
+
- **[Privilege Escalation Detection](docs/privilege-escalation.md)** - Detecting escalation paths
|
|
791
|
+
|
|
792
|
+
### Quick Overview
|
|
793
|
+
|
|
794
|
+
**AWS IAM Validation (12 checks)** - Ensure policies work correctly in AWS:
|
|
795
|
+
- Statement ID uniqueness and format
|
|
796
|
+
- Policy size limits
|
|
797
|
+
- Action and condition key validation
|
|
798
|
+
- Condition operator and value type checking
|
|
799
|
+
- Set operator validation
|
|
800
|
+
- MFA anti-pattern detection
|
|
801
|
+
- Resource ARN format validation
|
|
802
|
+
- Principal validation (resource policies)
|
|
803
|
+
- Policy type validation
|
|
804
|
+
- Action-resource constraint and matching
|
|
805
|
+
|
|
806
|
+
**Security Best Practices (6 checks)** - Identify security risks:
|
|
807
|
+
- Wildcard actions (`Action: "*"`)
|
|
808
|
+
- Wildcard resources (`Resource: "*"`)
|
|
809
|
+
- Full wildcard (CRITICAL: both wildcards together)
|
|
810
|
+
- Service-level wildcards (`iam:*`, `s3:*`, etc.)
|
|
811
|
+
- Sensitive actions without conditions (490 actions across 4 risk categories)
|
|
812
|
+
- Action condition enforcement (MFA, IP restrictions, tags, etc.)
|
|
813
|
+
|
|
814
|
+
### Quick Examples
|
|
815
|
+
|
|
816
|
+
**Action Validation:**
|
|
789
817
|
```json
|
|
818
|
+
// ✅ PASS: Valid S3 action
|
|
790
819
|
{
|
|
791
820
|
"Effect": "Allow",
|
|
792
|
-
"Action": "s3:GetObject",
|
|
793
|
-
"Resource": "
|
|
821
|
+
"Action": "s3:GetObject",
|
|
822
|
+
"Resource": "arn:aws:s3:::my-bucket/*"
|
|
794
823
|
}
|
|
795
|
-
```
|
|
796
824
|
|
|
797
|
-
|
|
825
|
+
// ❌ FAIL: Invalid action name
|
|
798
826
|
{
|
|
799
827
|
"Effect": "Allow",
|
|
800
|
-
"Action": "s3:InvalidAction", //
|
|
828
|
+
"Action": "s3:InvalidAction", // ERROR: Action doesn't exist
|
|
801
829
|
"Resource": "*"
|
|
802
830
|
}
|
|
803
831
|
```
|
|
804
832
|
|
|
805
|
-
|
|
833
|
+
**Full Wildcard (Critical):**
|
|
834
|
+
```json
|
|
835
|
+
// ✅ PASS: Specific actions and resources
|
|
836
|
+
{
|
|
837
|
+
"Effect": "Allow",
|
|
838
|
+
"Action": ["s3:GetObject", "s3:PutObject"],
|
|
839
|
+
"Resource": "arn:aws:s3:::my-bucket/*"
|
|
840
|
+
}
|
|
806
841
|
|
|
807
|
-
|
|
842
|
+
// ❌ FAIL: Administrative access
|
|
843
|
+
{
|
|
844
|
+
"Effect": "Allow",
|
|
845
|
+
"Action": "*", // CRITICAL: All actions
|
|
846
|
+
"Resource": "*" // CRITICAL: All resources
|
|
847
|
+
}
|
|
848
|
+
```
|
|
808
849
|
|
|
850
|
+
**Action Condition Enforcement:**
|
|
809
851
|
```json
|
|
852
|
+
// ✅ PASS: iam:PassRole with required condition
|
|
810
853
|
{
|
|
811
854
|
"Effect": "Allow",
|
|
812
|
-
"Action": "
|
|
855
|
+
"Action": "iam:PassRole",
|
|
813
856
|
"Resource": "*",
|
|
814
857
|
"Condition": {
|
|
815
858
|
"StringEquals": {
|
|
816
|
-
"
|
|
859
|
+
"iam:PassedToService": ["lambda.amazonaws.com"]
|
|
817
860
|
}
|
|
818
861
|
}
|
|
819
862
|
}
|
|
820
|
-
```
|
|
821
|
-
|
|
822
|
-
### 3. Resource ARN Validation
|
|
823
|
-
|
|
824
|
-
Ensures ARNs follow proper AWS format:
|
|
825
|
-
|
|
826
|
-
```json
|
|
827
|
-
{
|
|
828
|
-
"Effect": "Allow",
|
|
829
|
-
"Action": "s3:GetObject",
|
|
830
|
-
"Resource": "arn:aws:s3:::my-bucket/*" // ✅ Valid ARN
|
|
831
|
-
}
|
|
832
|
-
```
|
|
833
863
|
|
|
834
|
-
|
|
864
|
+
// ❌ FAIL: iam:PassRole without condition
|
|
835
865
|
{
|
|
836
866
|
"Effect": "Allow",
|
|
837
|
-
"Action": "
|
|
838
|
-
"Resource": "
|
|
867
|
+
"Action": "iam:PassRole", // HIGH: Missing iam:PassedToService condition
|
|
868
|
+
"Resource": "*"
|
|
839
869
|
}
|
|
840
870
|
```
|
|
841
871
|
|
|
842
|
-
|
|
872
|
+
**📚 For complete documentation of all 18 checks with detailed examples, see [Check Reference Guide](docs/check-reference.md)**
|
|
843
873
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
- Overly permissive wildcard usage (`*` for both Action and Resource)
|
|
847
|
-
- Sensitive actions without conditions
|
|
848
|
-
- Administrative permissions without restrictions
|
|
874
|
+
_Note: The old [CHECKS.md](docs/CHECKS.md) has been deprecated in favor of the new check-reference.md with better organization and examples._
|
|
849
875
|
|
|
850
876
|
## GitHub Integration Features
|
|
851
877
|
|
|
@@ -956,28 +982,27 @@ Result: PR always shows current state, no stale comments
|
|
|
956
982
|
|
|
957
983
|
## 📚 Documentation
|
|
958
984
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
-
|
|
963
|
-
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
- Configuration
|
|
967
|
-
-
|
|
968
|
-
-
|
|
969
|
-
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
- [GitHub Actions Workflows](examples/github-actions/)
|
|
974
|
-
- [Custom Checks](examples/custom_checks/)
|
|
975
|
-
- [Configuration Files](examples/configs/)
|
|
976
|
-
- [Test IAM Policies](examples/iam-test-policies/)
|
|
985
|
+
### Core Documentation
|
|
986
|
+
- **[📖 Complete Usage Guide (DOCS.md)](DOCS.md)** - Installation, CLI reference, GitHub Actions, configuration
|
|
987
|
+
- **[✅ Validation Checks Reference](docs/check-reference.md)** - All 18 checks with pass/fail examples
|
|
988
|
+
- **[🐍 Python SDK Guide (SDK.md)](docs/SDK.md)** - Use as a Python library in your applications
|
|
989
|
+
- **[🤝 Contributing Guide (CONTRIBUTING.md)](CONTRIBUTING.md)** - How to contribute to the project
|
|
990
|
+
|
|
991
|
+
### Examples & Resources
|
|
992
|
+
- **[Configuration Examples](examples/configs/)** - 9 configuration files for different use cases
|
|
993
|
+
- **[GitHub Actions Workflows](examples/github-actions/)** - Ready-to-use workflow examples
|
|
994
|
+
- **[Custom Checks](examples/custom_checks/)** - Example custom validation rules
|
|
995
|
+
- **[Library Usage Examples](examples/library-usage/)** - Python SDK examples
|
|
996
|
+
- **[Test IAM Policies](examples/iam-test-policies/)** - Example policies for testing
|
|
997
|
+
|
|
998
|
+
### Advanced Topics
|
|
977
999
|
- **[Roadmap](docs/ROADMAP.md)** - Planned features and improvements
|
|
978
|
-
- **[AWS Services Backup Guide](docs/aws-services-backup.md)** - Offline validation
|
|
979
|
-
- **[
|
|
980
|
-
|
|
1000
|
+
- **[AWS Services Backup Guide](docs/aws-services-backup.md)** - Offline validation setup
|
|
1001
|
+
- **[Publishing Guide](docs/development/PUBLISHING.md)** - Release process for maintainers
|
|
1002
|
+
|
|
1003
|
+
### Quick Links
|
|
1004
|
+
- **[GitHub Issues](https://github.com/boogy/iam-policy-validator/issues)** - Report bugs or request features
|
|
1005
|
+
- **[GitHub Discussions](https://github.com/boogy/iam-policy-validator/discussions)** - Ask questions and share ideas
|
|
981
1006
|
|
|
982
1007
|
## 🤝 Contributing
|
|
983
1008
|
|
|
@@ -1014,6 +1039,10 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed instructions.
|
|
|
1014
1039
|
|
|
1015
1040
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
1016
1041
|
|
|
1042
|
+
### Third-Party Code
|
|
1043
|
+
|
|
1044
|
+
Portions of the ARN pattern matching code in [`iam_validator/sdk/arn_matching.py`](iam_validator/sdk/arn_matching.py) are derived from [Parliament](https://github.com/duo-labs/parliament) (Copyright 2019 Duo Security, [BSD 3-Clause License](https://github.com/duo-labs/parliament/blob/master/LICENSE)). See file header for details.
|
|
1045
|
+
|
|
1017
1046
|
## 🆘 Support
|
|
1018
1047
|
|
|
1019
1048
|
- **Documentation**: Check the [docs/](docs/) directory
|
|
@@ -1,51 +1,56 @@
|
|
|
1
1
|
iam_validator/__init__.py,sha256=APnMR3Fu4fHhxfsHBvUM2dJIwazgvLKQbfOsSgFPidg,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=
|
|
5
|
-
iam_validator/checks/action_condition_enforcement.py,sha256=
|
|
6
|
-
iam_validator/checks/
|
|
3
|
+
iam_validator/__version__.py,sha256=U-2GASzFF5PD483Cth0LG6biXahUQLBsW4BrfQVnGhw,206
|
|
4
|
+
iam_validator/checks/__init__.py,sha256=eDiDlVon0CwWGSBnZgM-arn1i5R5ZSG89pgR-ifETxE,1782
|
|
5
|
+
iam_validator/checks/action_condition_enforcement.py,sha256=qE2ae6vzOG2LqYGrvxeDdKyXtfdtqgfCBBceTpIGqNY,36573
|
|
6
|
+
iam_validator/checks/action_resource_matching.py,sha256=KyF9GgZrfSLy-DR_iaj9J9fOTOaj8G5BvBYqHEiSnkg,16577
|
|
7
7
|
iam_validator/checks/action_validation.py,sha256=IpxtTsk58f2zEZ-xzAoyHw4QK8BCRV43OffP-8ydf9E,2578
|
|
8
|
-
iam_validator/checks/condition_key_validation.py,sha256=
|
|
8
|
+
iam_validator/checks/condition_key_validation.py,sha256=E-doe2QjvKSkyjXZO9TBp0QS7M0Fv2oYYQQ9738QNxg,3918
|
|
9
|
+
iam_validator/checks/condition_type_mismatch.py,sha256=qAbP6pP_vM1aBvIBRHji56XLH_5cQI4cDhpMQe19CHM,10588
|
|
9
10
|
iam_validator/checks/full_wildcard.py,sha256=8zkmkQo2TkflgNgbclThH73mIBRHbuiob0YO2HwQhuE,2371
|
|
11
|
+
iam_validator/checks/mfa_condition_check.py,sha256=s7K2r9hxlJI1KWk8qXl-JOWE6jLIhpxooK26Pr7acKs,4915
|
|
10
12
|
iam_validator/checks/policy_size.py,sha256=gJD8rFHa1CstKaZ2Dj9B5XEI3o0wsGv7ksqjqZXoSXI,5771
|
|
11
13
|
iam_validator/checks/policy_type_validation.py,sha256=w85W4zdZ6ZrDy0DmHxxnAXbJGfN8peRDjLfJ4Bp1dWc,15009
|
|
12
14
|
iam_validator/checks/principal_validation.py,sha256=DLmqX_QbfuV8O5XtcuocBeR_Vwa50_3RBx35XuLQob8,29837
|
|
13
15
|
iam_validator/checks/resource_validation.py,sha256=AEIoiR6AKYLuVaA8ne3QE5qy6NCMDe98_2JAiwE9-JU,4261
|
|
14
|
-
iam_validator/checks/sensitive_action.py,sha256=
|
|
16
|
+
iam_validator/checks/sensitive_action.py,sha256=gxPhxMxQzsj7xrvRfMZlfh1o67B2s1ddSLF_KQ0FKOw,9716
|
|
15
17
|
iam_validator/checks/service_wildcard.py,sha256=1O3NF8_T1LsCzpm8SFViv1KTh9NYQSqXN8-D3xx6Erw,4156
|
|
18
|
+
iam_validator/checks/set_operator_validation.py,sha256=1XjOdf-xk-m6m1bODuHsELZccriGqOJTDI-HCcuId80,7464
|
|
16
19
|
iam_validator/checks/sid_uniqueness.py,sha256=1Ux9W1hPPhzgdCzfxwxvD-nSBRo1SyrxFWlnTXDcOys,6887
|
|
17
20
|
iam_validator/checks/wildcard_action.py,sha256=KsAej_GP6qL2XpmvGnS56SIJw3Z-5xyvZ7VDfsERFrU,2045
|
|
18
21
|
iam_validator/checks/wildcard_resource.py,sha256=V5aBmb1pr8KhbVv2G4nzjBlZWz0kCOCgW6jKnb2_U60,5504
|
|
19
22
|
iam_validator/checks/utils/__init__.py,sha256=j0X4ibUB6RGx2a-kNoJnlVZwHfoEvzZsIeTmJIAoFzA,45
|
|
20
23
|
iam_validator/checks/utils/policy_level_checks.py,sha256=2V60C0zhKfsFPjQ-NMlD3EemtwA9S6-4no8nETgXdQE,5274
|
|
21
|
-
iam_validator/checks/utils/sensitive_action_matcher.py,sha256=
|
|
24
|
+
iam_validator/checks/utils/sensitive_action_matcher.py,sha256=e67RIi-zg7ssFwq6x4kt4wsTF-brNz91KaBxgV-23jg,10687
|
|
22
25
|
iam_validator/checks/utils/wildcard_expansion.py,sha256=V3V_KRpapOzPBhpUObJjGHoMhvCH90QvDxppeEHIG_U,3152
|
|
23
26
|
iam_validator/commands/__init__.py,sha256=M-5bo8w0TCWydK0cXgJyPD2fmk8bpQs-3b26YbgLzlc,565
|
|
24
27
|
iam_validator/commands/analyze.py,sha256=TWlDaZ8gVOdNv6__KQQfzeLVW36qLiL5IzlhGYfvq_g,16501
|
|
25
28
|
iam_validator/commands/base.py,sha256=5baCCMwxz7pdQ6XMpWfXFNz7i1l5dB8Qv9dKKR04Gzs,1074
|
|
26
|
-
iam_validator/commands/cache.py,sha256=
|
|
29
|
+
iam_validator/commands/cache.py,sha256=p4ucRVuh42sbK3Lk0b610L3ofAR5TnUreF00fpO6VFg,14219
|
|
27
30
|
iam_validator/commands/download_services.py,sha256=KKz3ybMLT8DQUf9aFZ0tilJ-o1b6PE8Pf1pC4K6cT8I,9175
|
|
28
31
|
iam_validator/commands/post_to_pr.py,sha256=CvUXs2xvO-UhluxdfNM6F0TCWD8hDBEOiYw60fm1Dms,2363
|
|
29
|
-
iam_validator/commands/validate.py,sha256=
|
|
32
|
+
iam_validator/commands/validate.py,sha256=vyPsEenHoQPc_ftaVv0Ek5i52OvoqHaRCpVLLjCU5As,23508
|
|
30
33
|
iam_validator/core/__init__.py,sha256=1FvJPMrbzJfS9YbRUJCshJLd5gzWwR9Fd_slS0Aq9c8,416
|
|
31
34
|
iam_validator/core/access_analyzer.py,sha256=poeT1i74jXpKr1B3UmvqiTvCTbq82zffWgZHwiFUwoo,24337
|
|
32
35
|
iam_validator/core/access_analyzer_report.py,sha256=IrQVszlhFfQ6WykYLpig7TU3hf8dnQTegPDsOvHjR5Q,24873
|
|
33
|
-
iam_validator/core/aws_fetcher.py,sha256=
|
|
34
|
-
iam_validator/core/
|
|
35
|
-
iam_validator/core/check_registry.py,sha256=-3MDcJvzN07cyMbi9UTzw_JcPJCcB-tXGl5hKX-Y2ZY,16067
|
|
36
|
+
iam_validator/core/aws_fetcher.py,sha256=NEXS7w6M5_EIXAm6OyyUEenpPU6p2Aj_a_p93aR9vAI,36147
|
|
37
|
+
iam_validator/core/check_registry.py,sha256=cMjtJROkZOLzXxl-mTdLYHdxyajNnOsaHGs-EeaSZ7k,21741
|
|
36
38
|
iam_validator/core/cli.py,sha256=PkXiZjlgrQ21QustBbspefYsdbxst4gxoClyG2_HQR8,3843
|
|
37
|
-
iam_validator/core/
|
|
38
|
-
iam_validator/core/models.py,sha256=
|
|
39
|
-
iam_validator/core/policy_checks.py,sha256=
|
|
39
|
+
iam_validator/core/condition_validators.py,sha256=7zBjlcf2xGFKGbcFrXSLvWT5tFhWxoqwzhsJqS2E8uY,21524
|
|
40
|
+
iam_validator/core/models.py,sha256=spL5USsDFNfzQ_7R6yaTo-fcoRANkKS-zCwn88XYjYQ,11544
|
|
41
|
+
iam_validator/core/policy_checks.py,sha256=Uz2yCsqRaoIja31F4ZM-39a1pHv51yZqKyWWkGUZKNY,26489
|
|
40
42
|
iam_validator/core/policy_loader.py,sha256=TR7SpzlRG3TwH4HBGEFUuhNOmxIR8Cud2SQ-AmHWBpM,14040
|
|
41
|
-
iam_validator/core/pr_commenter.py,sha256=
|
|
43
|
+
iam_validator/core/pr_commenter.py,sha256=EDE8lWsabkHYrOw2ApIUrPbjI5K3-Z_QxJkjakaVsTk,11600
|
|
42
44
|
iam_validator/core/report.py,sha256=Yeh_u9jQvTyDV3ignyPcWEQVfFcxNZNrxf4T0fjeWb4,33283
|
|
43
|
-
iam_validator/core/config/__init__.py,sha256=
|
|
45
|
+
iam_validator/core/config/__init__.py,sha256=CWSyIA7kEyzrskEenjYbs9Iih10BXRpiY9H2dHg61rU,2671
|
|
44
46
|
iam_validator/core/config/aws_api.py,sha256=HLIzOItQ0A37wxHcgWck6ZFO0wmNY8JNTiWMMK6JKYU,1248
|
|
45
|
-
iam_validator/core/config/
|
|
46
|
-
iam_validator/core/config/
|
|
47
|
+
iam_validator/core/config/aws_global_conditions.py,sha256=gdmMxXGBy95B3uYUG-J7rnM6Ixgc6L7Y9Pcd2XAMb60,7170
|
|
48
|
+
iam_validator/core/config/category_suggestions.py,sha256=QlrYi4BTkxDSTlL7NZGE9BWN-atWetZ6XjkI9F_7YzI,4370
|
|
49
|
+
iam_validator/core/config/condition_requirements.py,sha256=1PuADTB9pLqh-kNUGC7kSU6LMLtXMSc003tvI7qKeAY,5170
|
|
50
|
+
iam_validator/core/config/config_loader.py,sha256=MjO9SJ3HSXl6gnv_Qy0d906pX9iW8cONM8alOotUaKI,17749
|
|
51
|
+
iam_validator/core/config/defaults.py,sha256=w5ievxkqki3zYr7NaREoWtVx5rTfxBpZlgoNdovcILs,27112
|
|
47
52
|
iam_validator/core/config/principal_requirements.py,sha256=VCX7fBDgeDTJQyoz7_x7GI7Kf9O1Eu-sbihoHOrKv6o,15105
|
|
48
|
-
iam_validator/core/config/sensitive_actions.py,sha256=
|
|
53
|
+
iam_validator/core/config/sensitive_actions.py,sha256=uATDIp_TD3OQQlsYTZp79qd1mSK2Bf9hJ0JwcqLBr84,25344
|
|
49
54
|
iam_validator/core/config/service_principals.py,sha256=gQSROsxUWBD6P2F9qP320UZV4lHGlsyvHSkMyy0njrU,2685
|
|
50
55
|
iam_validator/core/config/wildcards.py,sha256=H_v6hb-rZ0UUz4cul9lxkVI39e6knaK4Y-MbWz2Ebpw,3228
|
|
51
56
|
iam_validator/core/formatters/__init__.py,sha256=fnCKAEBXItnOf2m4rhVs7zwMaTxbG6ESh3CF8V5j5ec,868
|
|
@@ -60,8 +65,18 @@ iam_validator/core/formatters/sarif.py,sha256=O3pn7whqFq5xxk-tuoqSb2k4Fk5ai_A2SK
|
|
|
60
65
|
iam_validator/integrations/__init__.py,sha256=7Hlor_X9j0NZaEjFuSvoXAAuSKQ-zgY19Rk-Dz3JpKo,616
|
|
61
66
|
iam_validator/integrations/github_integration.py,sha256=bKs94vNT4PmcmUPUeuY2WJFhCYpUY2SWiBP1vj-andA,25673
|
|
62
67
|
iam_validator/integrations/ms_teams.py,sha256=t2PlWuTDb6GGH-eDU1jnOKd8D1w4FCB68bahGA7MJcE,14475
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
iam_validator/sdk/__init__.py,sha256=fRDSXAclGmCU3KDft4StL8JUcpAsdzwIRf8mVj461q0,5306
|
|
69
|
+
iam_validator/sdk/arn_matching.py,sha256=we70RM2sriCcsd5GAUj7gL0iGKZt3oa0kle2VLF-X2E,8841
|
|
70
|
+
iam_validator/sdk/context.py,sha256=SBFeedu8rhCzFA-zC2cH4wLZxEJT6XOW30hIZAyXPVU,6826
|
|
71
|
+
iam_validator/sdk/exceptions.py,sha256=tm91TxIwU157U_UHN7w5qICf_OhU11agj6pV5W_YP-4,1023
|
|
72
|
+
iam_validator/sdk/helpers.py,sha256=OVBg4xrW95LT74wXCg1LQkba9kw5RfFqeCLuTqhgL-A,5697
|
|
73
|
+
iam_validator/sdk/policy_utils.py,sha256=CZS1OGSdiWsd2lsCwg0BDcUNWa61tUwgvn-P5rKqeN8,12987
|
|
74
|
+
iam_validator/sdk/shortcuts.py,sha256=EVNSYV7rv4TFH03ulsZ3mS1UVmTSp2jKpc2AXs4j1q4,8531
|
|
75
|
+
iam_validator/utils/__init__.py,sha256=V8u-SSdnL4a7NwF-yg9x0JRl5epKAXEs2f5RiwK2qPo,856
|
|
76
|
+
iam_validator/utils/cache.py,sha256=wOQKOBeoG6QqC5f0oXcHz63Cjtu_-SsSS-0pTSwyAiM,3254
|
|
77
|
+
iam_validator/utils/regex.py,sha256=PMVCYxjlVa2zLNEnIU3upQCSIhPazlXWg_sJClIiqiM,6221
|
|
78
|
+
iam_policy_validator-1.6.0.dist-info/METADATA,sha256=rghXQo_4hFarMkPFzCmWFgD_1yMW1dwtwGIId_MsBdc,36586
|
|
79
|
+
iam_policy_validator-1.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
80
|
+
iam_policy_validator-1.6.0.dist-info/entry_points.txt,sha256=8HtWd8O7mvPiPdZR5YbzY8or_qcqLM4-pKaFdhtFT8M,62
|
|
81
|
+
iam_policy_validator-1.6.0.dist-info/licenses/LICENSE,sha256=AMnbFTBDcK4_MITe2wiQBkj0vg-jjBBhsc43ydC7tt4,1098
|
|
82
|
+
iam_policy_validator-1.6.0.dist-info/RECORD,,
|
iam_validator/__version__.py
CHANGED
iam_validator/checks/__init__.py
CHANGED
|
@@ -5,32 +5,38 @@ Built-in policy checks for IAM Policy Validator.
|
|
|
5
5
|
from iam_validator.checks.action_condition_enforcement import (
|
|
6
6
|
ActionConditionEnforcementCheck,
|
|
7
7
|
)
|
|
8
|
-
from iam_validator.checks.
|
|
9
|
-
|
|
8
|
+
from iam_validator.checks.action_resource_matching import (
|
|
9
|
+
ActionResourceMatchingCheck,
|
|
10
10
|
)
|
|
11
11
|
from iam_validator.checks.action_validation import ActionValidationCheck
|
|
12
12
|
from iam_validator.checks.condition_key_validation import ConditionKeyValidationCheck
|
|
13
|
+
from iam_validator.checks.condition_type_mismatch import ConditionTypeMismatchCheck
|
|
13
14
|
from iam_validator.checks.full_wildcard import FullWildcardCheck
|
|
15
|
+
from iam_validator.checks.mfa_condition_check import MFAConditionCheck
|
|
14
16
|
from iam_validator.checks.policy_size import PolicySizeCheck
|
|
15
17
|
from iam_validator.checks.principal_validation import PrincipalValidationCheck
|
|
16
18
|
from iam_validator.checks.resource_validation import ResourceValidationCheck
|
|
17
19
|
from iam_validator.checks.sensitive_action import SensitiveActionCheck
|
|
18
20
|
from iam_validator.checks.service_wildcard import ServiceWildcardCheck
|
|
21
|
+
from iam_validator.checks.set_operator_validation import SetOperatorValidationCheck
|
|
19
22
|
from iam_validator.checks.sid_uniqueness import SidUniquenessCheck
|
|
20
23
|
from iam_validator.checks.wildcard_action import WildcardActionCheck
|
|
21
24
|
from iam_validator.checks.wildcard_resource import WildcardResourceCheck
|
|
22
25
|
|
|
23
26
|
__all__ = [
|
|
24
27
|
"ActionConditionEnforcementCheck",
|
|
25
|
-
"
|
|
28
|
+
"ActionResourceMatchingCheck",
|
|
26
29
|
"ActionValidationCheck",
|
|
27
30
|
"ConditionKeyValidationCheck",
|
|
31
|
+
"ConditionTypeMismatchCheck",
|
|
28
32
|
"FullWildcardCheck",
|
|
33
|
+
"MFAConditionCheck",
|
|
29
34
|
"PolicySizeCheck",
|
|
30
35
|
"PrincipalValidationCheck",
|
|
31
36
|
"ResourceValidationCheck",
|
|
32
37
|
"SensitiveActionCheck",
|
|
33
38
|
"ServiceWildcardCheck",
|
|
39
|
+
"SetOperatorValidationCheck",
|
|
34
40
|
"SidUniquenessCheck",
|
|
35
41
|
"WildcardActionCheck",
|
|
36
42
|
"WildcardResourceCheck",
|
|
@@ -5,6 +5,7 @@ This built-in check ensures that specific actions have required conditions.
|
|
|
5
5
|
Supports ALL types of conditions: MFA, IP, VPC, time, tags, encryption, etc.
|
|
6
6
|
|
|
7
7
|
Supports advanced "all_of" and "any_of" logic for both actions and conditions.
|
|
8
|
+
Supports both STATEMENT-LEVEL and POLICY-LEVEL enforcement.
|
|
8
9
|
|
|
9
10
|
Common use cases:
|
|
10
11
|
- iam:PassRole must have iam:PassedToService condition
|
|
@@ -12,6 +13,7 @@ Common use cases:
|
|
|
12
13
|
- Actions must have source IP restrictions
|
|
13
14
|
- Resources must have required tags
|
|
14
15
|
- Combine multiple conditions (MFA + IP + Tags)
|
|
16
|
+
- Policy-level: Ensure ALL statements granting certain actions have MFA
|
|
15
17
|
|
|
16
18
|
Configuration in iam-validator.yaml:
|
|
17
19
|
|
|
@@ -21,6 +23,7 @@ Configuration in iam-validator.yaml:
|
|
|
21
23
|
severity: error
|
|
22
24
|
description: "Enforce specific conditions for specific actions"
|
|
23
25
|
|
|
26
|
+
# STATEMENT-LEVEL: Check individual statements (default)
|
|
24
27
|
action_condition_requirements:
|
|
25
28
|
# BASIC: Simple action with required condition
|
|
26
29
|
- actions:
|
|
@@ -90,15 +93,56 @@ Configuration in iam-validator.yaml:
|
|
|
90
93
|
- "iam:*"
|
|
91
94
|
- "s3:DeleteBucket"
|
|
92
95
|
description: "These dangerous actions should never be used"
|
|
96
|
+
|
|
97
|
+
# POLICY-LEVEL: Scan entire policy and enforce conditions across all matching statements
|
|
98
|
+
policy_level_requirements:
|
|
99
|
+
# Example: If ANY statement grants privilege escalation actions,
|
|
100
|
+
# then ALL such statements must have MFA
|
|
101
|
+
- actions:
|
|
102
|
+
any_of:
|
|
103
|
+
- "iam:CreateUser"
|
|
104
|
+
- "iam:AttachUserPolicy"
|
|
105
|
+
- "iam:PutUserPolicy"
|
|
106
|
+
scope: "policy"
|
|
107
|
+
required_conditions:
|
|
108
|
+
- condition_key: "aws:MultiFactorAuthPresent"
|
|
109
|
+
expected_value: true
|
|
110
|
+
description: "Privilege escalation actions require MFA across entire policy"
|
|
111
|
+
severity: "critical"
|
|
112
|
+
|
|
113
|
+
# Example: All admin actions across the policy must have MFA
|
|
114
|
+
- actions:
|
|
115
|
+
any_of:
|
|
116
|
+
- "iam:*"
|
|
117
|
+
- "s3:*"
|
|
118
|
+
scope: "policy"
|
|
119
|
+
required_conditions:
|
|
120
|
+
all_of:
|
|
121
|
+
- condition_key: "aws:MultiFactorAuthPresent"
|
|
122
|
+
expected_value: true
|
|
123
|
+
- condition_key: "aws:SourceIp"
|
|
124
|
+
apply_to: "all_matching_statements"
|
|
125
|
+
|
|
126
|
+
# Example: Ensure no statement in the policy allows dangerous combinations
|
|
127
|
+
- actions:
|
|
128
|
+
all_of:
|
|
129
|
+
- "iam:CreateAccessKey"
|
|
130
|
+
- "iam:UpdateAccessKey"
|
|
131
|
+
scope: "policy"
|
|
132
|
+
severity: "critical"
|
|
133
|
+
description: "Dangerous combination of actions detected in policy"
|
|
93
134
|
"""
|
|
94
135
|
|
|
95
136
|
import re
|
|
96
|
-
from typing import Any
|
|
137
|
+
from typing import TYPE_CHECKING, Any
|
|
97
138
|
|
|
98
139
|
from iam_validator.core.aws_fetcher import AWSServiceFetcher
|
|
99
140
|
from iam_validator.core.check_registry import CheckConfig, PolicyCheck
|
|
100
141
|
from iam_validator.core.models import Statement, ValidationIssue
|
|
101
142
|
|
|
143
|
+
if TYPE_CHECKING:
|
|
144
|
+
from iam_validator.core.models import IAMPolicy
|
|
145
|
+
|
|
102
146
|
|
|
103
147
|
class ActionConditionEnforcementCheck(PolicyCheck):
|
|
104
148
|
"""Enforces specific condition requirements for specific actions with all_of/any_of support."""
|
|
@@ -122,7 +166,7 @@ class ActionConditionEnforcementCheck(PolicyCheck):
|
|
|
122
166
|
fetcher: AWSServiceFetcher,
|
|
123
167
|
config: CheckConfig,
|
|
124
168
|
) -> list[ValidationIssue]:
|
|
125
|
-
"""Execute condition enforcement check."""
|
|
169
|
+
"""Execute statement-level condition enforcement check."""
|
|
126
170
|
issues = []
|
|
127
171
|
|
|
128
172
|
# Only check Allow statements
|
|
@@ -186,6 +230,124 @@ class ActionConditionEnforcementCheck(PolicyCheck):
|
|
|
186
230
|
|
|
187
231
|
return issues
|
|
188
232
|
|
|
233
|
+
async def execute_policy(
|
|
234
|
+
self,
|
|
235
|
+
policy: "IAMPolicy",
|
|
236
|
+
policy_file: str,
|
|
237
|
+
fetcher: AWSServiceFetcher,
|
|
238
|
+
config: CheckConfig,
|
|
239
|
+
**kwargs,
|
|
240
|
+
) -> list[ValidationIssue]:
|
|
241
|
+
"""
|
|
242
|
+
Execute policy-level condition enforcement check.
|
|
243
|
+
|
|
244
|
+
This method scans the entire policy and enforces that ALL statements granting
|
|
245
|
+
certain actions must have specific conditions. This is useful for ensuring
|
|
246
|
+
consistent security controls across the entire policy.
|
|
247
|
+
|
|
248
|
+
Example use case:
|
|
249
|
+
- "If ANY statement in the policy grants iam:CreateUser, iam:AttachUserPolicy,
|
|
250
|
+
or iam:PutUserPolicy, then ALL such statements must have MFA condition."
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
policy: The complete IAM policy to check
|
|
254
|
+
policy_file: Path to the policy file (for context/reporting)
|
|
255
|
+
fetcher: AWS service fetcher for validation against AWS APIs
|
|
256
|
+
config: Configuration for this check instance
|
|
257
|
+
**kwargs: Additional context (policy_type, etc.)
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
List of ValidationIssue objects found by this check
|
|
261
|
+
"""
|
|
262
|
+
del policy_file, kwargs # Not used in current implementation
|
|
263
|
+
issues = []
|
|
264
|
+
|
|
265
|
+
# Get policy-level requirements from config
|
|
266
|
+
policy_level_requirements = config.config.get("policy_level_requirements", [])
|
|
267
|
+
if not policy_level_requirements:
|
|
268
|
+
return issues
|
|
269
|
+
|
|
270
|
+
# Process each policy-level requirement
|
|
271
|
+
for requirement in policy_level_requirements:
|
|
272
|
+
# Collect all statements that match the action criteria
|
|
273
|
+
matching_statements: list[tuple[int, Statement, list[str]]] = []
|
|
274
|
+
|
|
275
|
+
for idx, statement in enumerate(policy.statement):
|
|
276
|
+
# Only check Allow statements
|
|
277
|
+
if statement.effect != "Allow":
|
|
278
|
+
continue
|
|
279
|
+
|
|
280
|
+
statement_actions = statement.get_actions()
|
|
281
|
+
|
|
282
|
+
# Check if this statement matches the action requirement
|
|
283
|
+
actions_match, matching_actions = await self._check_action_match(
|
|
284
|
+
statement_actions, requirement, fetcher
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
if actions_match and matching_actions:
|
|
288
|
+
matching_statements.append((idx, statement, matching_actions))
|
|
289
|
+
|
|
290
|
+
# If no statements match, skip this requirement
|
|
291
|
+
if not matching_statements:
|
|
292
|
+
continue
|
|
293
|
+
|
|
294
|
+
# Now validate that ALL matching statements have the required conditions
|
|
295
|
+
required_conditions_config = requirement.get("required_conditions", [])
|
|
296
|
+
if not required_conditions_config:
|
|
297
|
+
# No conditions specified, just report that actions were found
|
|
298
|
+
description = requirement.get("description", "")
|
|
299
|
+
severity = requirement.get("severity", self.get_severity(config))
|
|
300
|
+
|
|
301
|
+
# Create a summary issue for all matching statements
|
|
302
|
+
all_actions = set()
|
|
303
|
+
statement_refs = []
|
|
304
|
+
for idx, stmt, actions in matching_statements:
|
|
305
|
+
all_actions.update(actions)
|
|
306
|
+
sid_info = f" (SID: {stmt.sid})" if stmt.sid else ""
|
|
307
|
+
statement_refs.append(f"Statement #{idx + 1}{sid_info}")
|
|
308
|
+
|
|
309
|
+
# Use the first matching statement's index for the issue
|
|
310
|
+
first_idx, first_stmt, _ = matching_statements[0]
|
|
311
|
+
|
|
312
|
+
issues.append(
|
|
313
|
+
ValidationIssue(
|
|
314
|
+
severity=severity,
|
|
315
|
+
statement_sid=first_stmt.sid,
|
|
316
|
+
statement_index=first_idx,
|
|
317
|
+
issue_type="policy_level_action_detected",
|
|
318
|
+
message=f"POLICY-LEVEL: Actions {sorted(all_actions)} found in {len(matching_statements)} statement(s). {description}",
|
|
319
|
+
action=", ".join(sorted(all_actions)),
|
|
320
|
+
suggestion=f"Review these statements: {', '.join(statement_refs)}. {description}",
|
|
321
|
+
line_number=first_stmt.line_number,
|
|
322
|
+
)
|
|
323
|
+
)
|
|
324
|
+
continue
|
|
325
|
+
|
|
326
|
+
# Validate conditions for each matching statement
|
|
327
|
+
for idx, statement, matching_actions in matching_statements:
|
|
328
|
+
condition_issues = self._validate_conditions(
|
|
329
|
+
statement,
|
|
330
|
+
idx,
|
|
331
|
+
required_conditions_config,
|
|
332
|
+
matching_actions,
|
|
333
|
+
config,
|
|
334
|
+
requirement,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
# Add policy-level context to each issue
|
|
338
|
+
for issue in condition_issues:
|
|
339
|
+
# Modify the message to indicate this is part of policy-level enforcement
|
|
340
|
+
issue.message = f"POLICY-LEVEL: {issue.message}"
|
|
341
|
+
issue.suggestion = (
|
|
342
|
+
f"{issue.suggestion}\n\n"
|
|
343
|
+
f"Note: This is enforced at the policy level. "
|
|
344
|
+
f"Found {len(matching_statements)} statement(s) with these actions in the policy."
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
issues.extend(condition_issues)
|
|
348
|
+
|
|
349
|
+
return issues
|
|
350
|
+
|
|
189
351
|
async def _check_action_match(
|
|
190
352
|
self, statement_actions: list[str], requirement: dict[str, Any], fetcher: AWSServiceFetcher
|
|
191
353
|
) -> tuple[bool, list[str]]:
|