iam-policy-validator 1.7.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.

Potentially problematic release.


This version of iam-policy-validator might be problematic. Click here for more details.

Files changed (83) hide show
  1. iam_policy_validator-1.7.0.dist-info/METADATA +1057 -0
  2. iam_policy_validator-1.7.0.dist-info/RECORD +83 -0
  3. iam_policy_validator-1.7.0.dist-info/WHEEL +4 -0
  4. iam_policy_validator-1.7.0.dist-info/entry_points.txt +2 -0
  5. iam_policy_validator-1.7.0.dist-info/licenses/LICENSE +21 -0
  6. iam_validator/__init__.py +27 -0
  7. iam_validator/__main__.py +11 -0
  8. iam_validator/__version__.py +7 -0
  9. iam_validator/checks/__init__.py +43 -0
  10. iam_validator/checks/action_condition_enforcement.py +884 -0
  11. iam_validator/checks/action_resource_matching.py +441 -0
  12. iam_validator/checks/action_validation.py +72 -0
  13. iam_validator/checks/condition_key_validation.py +92 -0
  14. iam_validator/checks/condition_type_mismatch.py +259 -0
  15. iam_validator/checks/full_wildcard.py +71 -0
  16. iam_validator/checks/mfa_condition_check.py +112 -0
  17. iam_validator/checks/policy_size.py +147 -0
  18. iam_validator/checks/policy_type_validation.py +305 -0
  19. iam_validator/checks/principal_validation.py +776 -0
  20. iam_validator/checks/resource_validation.py +138 -0
  21. iam_validator/checks/sensitive_action.py +254 -0
  22. iam_validator/checks/service_wildcard.py +107 -0
  23. iam_validator/checks/set_operator_validation.py +157 -0
  24. iam_validator/checks/sid_uniqueness.py +170 -0
  25. iam_validator/checks/utils/__init__.py +1 -0
  26. iam_validator/checks/utils/policy_level_checks.py +143 -0
  27. iam_validator/checks/utils/sensitive_action_matcher.py +294 -0
  28. iam_validator/checks/utils/wildcard_expansion.py +87 -0
  29. iam_validator/checks/wildcard_action.py +67 -0
  30. iam_validator/checks/wildcard_resource.py +135 -0
  31. iam_validator/commands/__init__.py +25 -0
  32. iam_validator/commands/analyze.py +531 -0
  33. iam_validator/commands/base.py +48 -0
  34. iam_validator/commands/cache.py +392 -0
  35. iam_validator/commands/download_services.py +255 -0
  36. iam_validator/commands/post_to_pr.py +86 -0
  37. iam_validator/commands/validate.py +600 -0
  38. iam_validator/core/__init__.py +14 -0
  39. iam_validator/core/access_analyzer.py +671 -0
  40. iam_validator/core/access_analyzer_report.py +640 -0
  41. iam_validator/core/aws_fetcher.py +940 -0
  42. iam_validator/core/check_registry.py +607 -0
  43. iam_validator/core/cli.py +134 -0
  44. iam_validator/core/condition_validators.py +626 -0
  45. iam_validator/core/config/__init__.py +81 -0
  46. iam_validator/core/config/aws_api.py +35 -0
  47. iam_validator/core/config/aws_global_conditions.py +160 -0
  48. iam_validator/core/config/category_suggestions.py +104 -0
  49. iam_validator/core/config/condition_requirements.py +155 -0
  50. iam_validator/core/config/config_loader.py +472 -0
  51. iam_validator/core/config/defaults.py +523 -0
  52. iam_validator/core/config/principal_requirements.py +421 -0
  53. iam_validator/core/config/sensitive_actions.py +672 -0
  54. iam_validator/core/config/service_principals.py +95 -0
  55. iam_validator/core/config/wildcards.py +124 -0
  56. iam_validator/core/constants.py +74 -0
  57. iam_validator/core/formatters/__init__.py +27 -0
  58. iam_validator/core/formatters/base.py +147 -0
  59. iam_validator/core/formatters/console.py +59 -0
  60. iam_validator/core/formatters/csv.py +170 -0
  61. iam_validator/core/formatters/enhanced.py +440 -0
  62. iam_validator/core/formatters/html.py +672 -0
  63. iam_validator/core/formatters/json.py +33 -0
  64. iam_validator/core/formatters/markdown.py +63 -0
  65. iam_validator/core/formatters/sarif.py +251 -0
  66. iam_validator/core/models.py +327 -0
  67. iam_validator/core/policy_checks.py +656 -0
  68. iam_validator/core/policy_loader.py +396 -0
  69. iam_validator/core/pr_commenter.py +424 -0
  70. iam_validator/core/report.py +872 -0
  71. iam_validator/integrations/__init__.py +28 -0
  72. iam_validator/integrations/github_integration.py +815 -0
  73. iam_validator/integrations/ms_teams.py +442 -0
  74. iam_validator/sdk/__init__.py +187 -0
  75. iam_validator/sdk/arn_matching.py +382 -0
  76. iam_validator/sdk/context.py +222 -0
  77. iam_validator/sdk/exceptions.py +48 -0
  78. iam_validator/sdk/helpers.py +177 -0
  79. iam_validator/sdk/policy_utils.py +425 -0
  80. iam_validator/sdk/shortcuts.py +283 -0
  81. iam_validator/utils/__init__.py +31 -0
  82. iam_validator/utils/cache.py +105 -0
  83. iam_validator/utils/regex.py +206 -0
@@ -0,0 +1,67 @@
1
+ """Wildcard action check - detects Action: '*' in IAM policies."""
2
+
3
+ from iam_validator.core.aws_fetcher import AWSServiceFetcher
4
+ from iam_validator.core.check_registry import CheckConfig, PolicyCheck
5
+ from iam_validator.core.models import Statement, ValidationIssue
6
+
7
+
8
+ class WildcardActionCheck(PolicyCheck):
9
+ """Checks for wildcard actions (Action: '*') which grant all permissions."""
10
+
11
+ @property
12
+ def check_id(self) -> str:
13
+ return "wildcard_action"
14
+
15
+ @property
16
+ def description(self) -> str:
17
+ return "Checks for wildcard actions (*)"
18
+
19
+ @property
20
+ def default_severity(self) -> str:
21
+ return "medium"
22
+
23
+ async def execute(
24
+ self,
25
+ statement: Statement,
26
+ statement_idx: int,
27
+ fetcher: AWSServiceFetcher,
28
+ config: CheckConfig,
29
+ ) -> list[ValidationIssue]:
30
+ """Execute wildcard action check on a statement."""
31
+ issues = []
32
+
33
+ # Only check Allow statements
34
+ if statement.effect != "Allow":
35
+ return issues
36
+
37
+ actions = statement.get_actions()
38
+
39
+ # Check for wildcard action (Action: "*")
40
+ if "*" in actions:
41
+ message = config.config.get("message", "Statement allows all actions (*)")
42
+ suggestion_text = config.config.get(
43
+ "suggestion",
44
+ "Replace wildcard with specific actions needed for your use case",
45
+ )
46
+ example = config.config.get("example", "")
47
+
48
+ # Combine suggestion + example
49
+ suggestion = (
50
+ f"{suggestion_text}\nExample:\n```json\n{example}\n```"
51
+ if example
52
+ else suggestion_text
53
+ )
54
+
55
+ issues.append(
56
+ ValidationIssue(
57
+ severity=self.get_severity(config),
58
+ statement_sid=statement.sid,
59
+ statement_index=statement_idx,
60
+ issue_type="overly_permissive",
61
+ message=message,
62
+ suggestion=suggestion,
63
+ line_number=statement.line_number,
64
+ )
65
+ )
66
+
67
+ return issues
@@ -0,0 +1,135 @@
1
+ """Wildcard resource check - detects Resource: '*' in IAM policies."""
2
+
3
+ from iam_validator.checks.utils.wildcard_expansion import expand_wildcard_actions
4
+ from iam_validator.core.aws_fetcher import AWSServiceFetcher
5
+ from iam_validator.core.check_registry import CheckConfig, PolicyCheck
6
+ from iam_validator.core.models import Statement, ValidationIssue
7
+
8
+
9
+ class WildcardResourceCheck(PolicyCheck):
10
+ """Checks for wildcard resources (Resource: '*') which grant access to all resources."""
11
+
12
+ @property
13
+ def check_id(self) -> str:
14
+ return "wildcard_resource"
15
+
16
+ @property
17
+ def description(self) -> str:
18
+ return "Checks for wildcard resources (*)"
19
+
20
+ @property
21
+ def default_severity(self) -> str:
22
+ return "medium"
23
+
24
+ async def execute(
25
+ self,
26
+ statement: Statement,
27
+ statement_idx: int,
28
+ fetcher: AWSServiceFetcher,
29
+ config: CheckConfig,
30
+ ) -> list[ValidationIssue]:
31
+ """Execute wildcard resource check on a statement."""
32
+ issues = []
33
+
34
+ # Only check Allow statements
35
+ if statement.effect != "Allow":
36
+ return issues
37
+
38
+ actions = statement.get_actions()
39
+ resources = statement.get_resources()
40
+
41
+ # Check for wildcard resource (Resource: "*")
42
+ if "*" in resources:
43
+ # Check if all actions are in the allowed_wildcards list
44
+ # allowed_wildcards works by expanding wildcard patterns (like "ec2:Describe*")
45
+ # to all matching AWS actions using the AWS API, then checking if the policy's
46
+ # actions are in that expanded list. This ensures only validated AWS actions
47
+ # are allowed with Resource: "*".
48
+ allowed_wildcards_expanded = await self._get_expanded_allowed_wildcards(config, fetcher)
49
+
50
+ # Check if ALL actions (excluding full wildcard "*") are in the expanded list
51
+ non_wildcard_actions = [a for a in actions if a != "*"]
52
+
53
+ if allowed_wildcards_expanded and non_wildcard_actions:
54
+ # Check if all actions are in the expanded allowed list (exact match)
55
+ all_actions_allowed = all(
56
+ action in allowed_wildcards_expanded for action in non_wildcard_actions
57
+ )
58
+
59
+ # If all actions are in the expanded list, skip the wildcard resource warning
60
+ if all_actions_allowed:
61
+ # All actions are safe, Resource: "*" is acceptable
62
+ return issues
63
+
64
+ # Flag the issue if actions are not all allowed or no allowed_wildcards configured
65
+ message = config.config.get("message", "Statement applies to all resources (*)")
66
+ suggestion_text = config.config.get(
67
+ "suggestion", "Replace wildcard with specific resource ARNs"
68
+ )
69
+ example = config.config.get("example", "")
70
+
71
+ # Combine suggestion + example
72
+ suggestion = (
73
+ f"{suggestion_text}\nExample:\n```json\n{example}\n```"
74
+ if example
75
+ else suggestion_text
76
+ )
77
+
78
+ issues.append(
79
+ ValidationIssue(
80
+ severity=self.get_severity(config),
81
+ statement_sid=statement.sid,
82
+ statement_index=statement_idx,
83
+ issue_type="overly_permissive",
84
+ message=message,
85
+ suggestion=suggestion,
86
+ line_number=statement.line_number,
87
+ )
88
+ )
89
+
90
+ return issues
91
+
92
+ async def _get_expanded_allowed_wildcards(
93
+ self, config: CheckConfig, fetcher: AWSServiceFetcher
94
+ ) -> frozenset[str]:
95
+ """Get and expand allowed_wildcards configuration.
96
+
97
+ This method retrieves wildcard patterns from the allowed_wildcards config
98
+ and expands them using the AWS API to get all matching actual AWS actions.
99
+
100
+ How it works:
101
+ 1. Retrieves patterns from config (e.g., ["ec2:Describe*", "s3:List*"])
102
+ 2. Expands each pattern using AWS API:
103
+ - "ec2:Describe*" → ["ec2:DescribeInstances", "ec2:DescribeImages", ...]
104
+ - "s3:List*" → ["s3:ListBucket", "s3:ListObjects", ...]
105
+ 3. Returns a set of all expanded actions
106
+
107
+ This allows you to:
108
+ - Specify patterns like "ec2:Describe*" in config
109
+ - Have the validator allow specific actions like "ec2:DescribeInstances" with Resource: "*"
110
+ - Ensure only real AWS actions (validated via API) are allowed
111
+
112
+ Example:
113
+ Config: allowed_wildcards: ["ec2:Describe*"]
114
+ Expands to: ["ec2:DescribeInstances", "ec2:DescribeImages", ...]
115
+ Policy: "Action": ["ec2:DescribeInstances"], "Resource": "*"
116
+ Result: ✅ Allowed (ec2:DescribeInstances is in expanded list)
117
+
118
+ Args:
119
+ config: The check configuration
120
+ fetcher: AWS service fetcher for expanding wildcards via AWS API
121
+
122
+ Returns:
123
+ A frozenset of all expanded action names from the configured patterns
124
+ """
125
+ patterns_to_expand = config.config.get("allowed_wildcards", [])
126
+
127
+ # If no patterns configured, return empty set
128
+ if not patterns_to_expand or not isinstance(patterns_to_expand, list):
129
+ return frozenset()
130
+
131
+ # Expand the wildcard patterns using the AWS API
132
+ # This converts patterns like "ec2:Describe*" to actual AWS actions
133
+ expanded_actions = await expand_wildcard_actions(patterns_to_expand, fetcher)
134
+
135
+ return frozenset(expanded_actions)
@@ -0,0 +1,25 @@
1
+ """CLI commands for IAM Policy Validator."""
2
+
3
+ from .analyze import AnalyzeCommand
4
+ from .cache import CacheCommand
5
+ from .download_services import DownloadServicesCommand
6
+ from .post_to_pr import PostToPRCommand
7
+ from .validate import ValidateCommand
8
+
9
+ # All available commands
10
+ ALL_COMMANDS = [
11
+ ValidateCommand(),
12
+ PostToPRCommand(),
13
+ AnalyzeCommand(),
14
+ CacheCommand(),
15
+ DownloadServicesCommand(),
16
+ ]
17
+
18
+ __all__ = [
19
+ "ValidateCommand",
20
+ "PostToPRCommand",
21
+ "AnalyzeCommand",
22
+ "CacheCommand",
23
+ "DownloadServicesCommand",
24
+ "ALL_COMMANDS",
25
+ ]