iam-policy-validator 1.4.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.
- iam_policy_validator-1.4.0.dist-info/METADATA +1022 -0
- iam_policy_validator-1.4.0.dist-info/RECORD +56 -0
- iam_policy_validator-1.4.0.dist-info/WHEEL +4 -0
- iam_policy_validator-1.4.0.dist-info/entry_points.txt +2 -0
- iam_policy_validator-1.4.0.dist-info/licenses/LICENSE +21 -0
- iam_validator/__init__.py +27 -0
- iam_validator/__main__.py +11 -0
- iam_validator/__version__.py +7 -0
- iam_validator/checks/__init__.py +27 -0
- iam_validator/checks/action_condition_enforcement.py +727 -0
- iam_validator/checks/action_resource_constraint.py +151 -0
- iam_validator/checks/action_validation.py +72 -0
- iam_validator/checks/condition_key_validation.py +70 -0
- iam_validator/checks/policy_size.py +151 -0
- iam_validator/checks/policy_type_validation.py +299 -0
- iam_validator/checks/principal_validation.py +282 -0
- iam_validator/checks/resource_validation.py +108 -0
- iam_validator/checks/security_best_practices.py +536 -0
- iam_validator/checks/sid_uniqueness.py +170 -0
- iam_validator/checks/utils/__init__.py +1 -0
- iam_validator/checks/utils/policy_level_checks.py +143 -0
- iam_validator/checks/utils/sensitive_action_matcher.py +252 -0
- iam_validator/checks/utils/wildcard_expansion.py +87 -0
- iam_validator/commands/__init__.py +25 -0
- iam_validator/commands/analyze.py +434 -0
- iam_validator/commands/base.py +48 -0
- iam_validator/commands/cache.py +392 -0
- iam_validator/commands/download_services.py +260 -0
- iam_validator/commands/post_to_pr.py +86 -0
- iam_validator/commands/validate.py +539 -0
- iam_validator/core/__init__.py +14 -0
- iam_validator/core/access_analyzer.py +666 -0
- iam_validator/core/access_analyzer_report.py +643 -0
- iam_validator/core/aws_fetcher.py +880 -0
- iam_validator/core/aws_global_conditions.py +137 -0
- iam_validator/core/check_registry.py +469 -0
- iam_validator/core/cli.py +134 -0
- iam_validator/core/config_loader.py +452 -0
- iam_validator/core/defaults.py +393 -0
- iam_validator/core/formatters/__init__.py +27 -0
- iam_validator/core/formatters/base.py +147 -0
- iam_validator/core/formatters/console.py +59 -0
- iam_validator/core/formatters/csv.py +170 -0
- iam_validator/core/formatters/enhanced.py +434 -0
- iam_validator/core/formatters/html.py +672 -0
- iam_validator/core/formatters/json.py +33 -0
- iam_validator/core/formatters/markdown.py +63 -0
- iam_validator/core/formatters/sarif.py +187 -0
- iam_validator/core/models.py +298 -0
- iam_validator/core/policy_checks.py +656 -0
- iam_validator/core/policy_loader.py +396 -0
- iam_validator/core/pr_commenter.py +338 -0
- iam_validator/core/report.py +859 -0
- iam_validator/integrations/__init__.py +28 -0
- iam_validator/integrations/github_integration.py +795 -0
- iam_validator/integrations/ms_teams.py +442 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""Action resource constraint check - validates resource constraints for actions.
|
|
2
|
+
|
|
3
|
+
This check ensures that:
|
|
4
|
+
- Actions WITHOUT required resource types (empty or missing Resources field in AWS API)
|
|
5
|
+
MUST use Resource: "*" because they are account-level operations
|
|
6
|
+
|
|
7
|
+
Examples of actions without required resources:
|
|
8
|
+
- s3:ListAllMyBuckets (lists all buckets in account)
|
|
9
|
+
- iam:ListRoles (lists all roles in account)
|
|
10
|
+
- ec2:DescribeInstances (describes instances across all regions)
|
|
11
|
+
|
|
12
|
+
These actions cannot target specific resources because they operate at the account level.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from iam_validator.core.aws_fetcher import AWSServiceFetcher
|
|
16
|
+
from iam_validator.core.check_registry import CheckConfig, PolicyCheck
|
|
17
|
+
from iam_validator.core.models import Statement, ValidationIssue
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ActionResourceConstraintCheck(PolicyCheck):
|
|
21
|
+
"""Validates resource constraints based on action requirements.
|
|
22
|
+
This check ensures that actions without required resource types use Resource: "*".
|
|
23
|
+
|
|
24
|
+
Examples of such actions include s3:ListAllMyBuckets, iam:ListRoles, etc.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def check_id(self) -> str:
|
|
29
|
+
return "action_resource_constraint"
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def description(self) -> str:
|
|
33
|
+
return "Validates that actions without required resource types use Resource: '*'"
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def default_severity(self) -> str:
|
|
37
|
+
return "error"
|
|
38
|
+
|
|
39
|
+
async def execute(
|
|
40
|
+
self,
|
|
41
|
+
statement: Statement,
|
|
42
|
+
statement_idx: int,
|
|
43
|
+
fetcher: AWSServiceFetcher,
|
|
44
|
+
config: CheckConfig,
|
|
45
|
+
) -> list[ValidationIssue]:
|
|
46
|
+
"""Execute action resource constraint validation on a statement."""
|
|
47
|
+
issues = []
|
|
48
|
+
|
|
49
|
+
# Only check Allow statements
|
|
50
|
+
if statement.effect != "Allow":
|
|
51
|
+
return issues
|
|
52
|
+
|
|
53
|
+
# Get actions and resources from statement
|
|
54
|
+
actions = statement.get_actions()
|
|
55
|
+
resources = statement.get_resources()
|
|
56
|
+
statement_sid = statement.sid
|
|
57
|
+
line_number = statement.line_number
|
|
58
|
+
|
|
59
|
+
# Skip if no actions or wildcard action
|
|
60
|
+
if not actions or "*" in actions:
|
|
61
|
+
return issues
|
|
62
|
+
|
|
63
|
+
# Skip if already using wildcard resource (this is correct for these actions)
|
|
64
|
+
if "*" in resources:
|
|
65
|
+
return issues
|
|
66
|
+
|
|
67
|
+
# Check each action for resource requirements
|
|
68
|
+
actions_without_required_resources = []
|
|
69
|
+
|
|
70
|
+
for action in actions:
|
|
71
|
+
# Skip wildcard actions
|
|
72
|
+
if "*" in action:
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
# Parse action to get service and action name
|
|
77
|
+
service_prefix, action_name = fetcher.parse_action(action)
|
|
78
|
+
|
|
79
|
+
# Fetch service detail to check resource requirements
|
|
80
|
+
service_detail = await fetcher.fetch_service_by_name(service_prefix)
|
|
81
|
+
|
|
82
|
+
# Check if action exists
|
|
83
|
+
if action_name not in service_detail.actions:
|
|
84
|
+
# Action doesn't exist - skip (will be caught by action_validation_check)
|
|
85
|
+
continue
|
|
86
|
+
|
|
87
|
+
action_detail = service_detail.actions[action_name]
|
|
88
|
+
|
|
89
|
+
# Check if action has NO required resources (empty or missing Resources field)
|
|
90
|
+
has_no_required_resources = (
|
|
91
|
+
not action_detail.resources or len(action_detail.resources) == 0
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if has_no_required_resources:
|
|
95
|
+
actions_without_required_resources.append(action)
|
|
96
|
+
|
|
97
|
+
except ValueError:
|
|
98
|
+
# Invalid action format - skip (will be caught by action_validation_check)
|
|
99
|
+
continue
|
|
100
|
+
except Exception:
|
|
101
|
+
# Service not found or other error - skip
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
# If we found actions without required resources, report the issue
|
|
105
|
+
if actions_without_required_resources:
|
|
106
|
+
# Get a sample of the resources to show in error message
|
|
107
|
+
resource_sample = resources[:3] if len(resources) > 3 else resources
|
|
108
|
+
resource_display = ", ".join(f'"{r}"' for r in resource_sample)
|
|
109
|
+
if len(resources) > 3:
|
|
110
|
+
resource_display += f", ... ({len(resources) - 3} more)"
|
|
111
|
+
|
|
112
|
+
# Format action list
|
|
113
|
+
action_list = ", ".join(f'"{a}"' for a in actions_without_required_resources)
|
|
114
|
+
|
|
115
|
+
# Determine message based on how many actions are affected
|
|
116
|
+
if len(actions_without_required_resources) == 1:
|
|
117
|
+
message = (
|
|
118
|
+
f"Action {action_list} does not operate on specific resources "
|
|
119
|
+
f'and requires Resource: "*"'
|
|
120
|
+
)
|
|
121
|
+
suggestion = (
|
|
122
|
+
f"Action {action_list} is an account-level operation that cannot target "
|
|
123
|
+
'specific resources. Move this action to a separate statement with Resource: "*", '
|
|
124
|
+
"and keep resource-specific actions in another statement with their specific ARNs"
|
|
125
|
+
)
|
|
126
|
+
else:
|
|
127
|
+
message = (
|
|
128
|
+
f"Actions {action_list} do not operate on specific resources "
|
|
129
|
+
f'and require Resource: "*"'
|
|
130
|
+
)
|
|
131
|
+
suggestion = (
|
|
132
|
+
"These actions are account-level operations that cannot target "
|
|
133
|
+
'specific resources. Move these actions to a dedicated statement with Resource: "*", '
|
|
134
|
+
"and keep resource-specific actions in separate statements with their specific ARNs"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
issues.append(
|
|
138
|
+
ValidationIssue(
|
|
139
|
+
severity=self.get_severity(config),
|
|
140
|
+
statement_sid=statement_sid,
|
|
141
|
+
statement_index=statement_idx,
|
|
142
|
+
issue_type="invalid_resource_constraint",
|
|
143
|
+
message=message,
|
|
144
|
+
action=action_list,
|
|
145
|
+
resource=resource_display,
|
|
146
|
+
suggestion=suggestion,
|
|
147
|
+
line_number=line_number,
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return issues
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Action validation check - validates IAM actions against AWS service definitions.
|
|
2
|
+
|
|
3
|
+
This check ensures that all actions specified in IAM policies are valid actions
|
|
4
|
+
defined by AWS services. It helps identify typos or deprecated actions that may
|
|
5
|
+
lead to unintended access permissions.
|
|
6
|
+
|
|
7
|
+
This check is not necessary when using Access Analyzer, as it performs similar
|
|
8
|
+
validations. However, it can be useful in environments where Access Analyzer is
|
|
9
|
+
not available or for pre-deployment policy validation to catch errors early.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from iam_validator.core.aws_fetcher import AWSServiceFetcher
|
|
13
|
+
from iam_validator.core.check_registry import CheckConfig, PolicyCheck
|
|
14
|
+
from iam_validator.core.models import Statement, ValidationIssue
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ActionValidationCheck(PolicyCheck):
|
|
18
|
+
"""Validates that IAM actions exist in AWS services."""
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def check_id(self) -> str:
|
|
22
|
+
return "action_validation"
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def description(self) -> str:
|
|
26
|
+
return "Validates that actions exist in AWS service definitions"
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def default_severity(self) -> str:
|
|
30
|
+
return "error"
|
|
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 action validation on a statement.
|
|
40
|
+
|
|
41
|
+
This check ONLY validates that actions exist in AWS service definitions.
|
|
42
|
+
Wildcard security checks are handled by security_best_practices_check.
|
|
43
|
+
"""
|
|
44
|
+
issues = []
|
|
45
|
+
|
|
46
|
+
# Get actions from statement
|
|
47
|
+
actions = statement.get_actions()
|
|
48
|
+
statement_sid = statement.sid
|
|
49
|
+
line_number = statement.line_number
|
|
50
|
+
|
|
51
|
+
for action in actions:
|
|
52
|
+
# Skip wildcard actions - they're handled by security_best_practices_check
|
|
53
|
+
if action == "*" or "*" in action:
|
|
54
|
+
continue
|
|
55
|
+
|
|
56
|
+
# Validate the action exists in AWS
|
|
57
|
+
is_valid, error_msg, _is_wildcard = await fetcher.validate_action(action)
|
|
58
|
+
|
|
59
|
+
if not is_valid:
|
|
60
|
+
issues.append(
|
|
61
|
+
ValidationIssue(
|
|
62
|
+
severity=self.get_severity(config),
|
|
63
|
+
statement_sid=statement_sid,
|
|
64
|
+
statement_index=statement_idx,
|
|
65
|
+
issue_type="invalid_action",
|
|
66
|
+
message=error_msg or f"Invalid action: {action}",
|
|
67
|
+
action=action,
|
|
68
|
+
line_number=line_number,
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return issues
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Condition key validation check - validates condition keys against AWS definitions."""
|
|
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 ConditionKeyValidationCheck(PolicyCheck):
|
|
9
|
+
"""Validates condition keys against AWS service definitions and global keys."""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def check_id(self) -> str:
|
|
13
|
+
return "condition_key_validation"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def description(self) -> str:
|
|
17
|
+
return "Validates condition keys against AWS service definitions"
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def default_severity(self) -> str:
|
|
21
|
+
return "error" # Invalid condition keys are IAM policy errors
|
|
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 condition key validation on a statement."""
|
|
31
|
+
issues = []
|
|
32
|
+
|
|
33
|
+
# Get conditions from statement
|
|
34
|
+
if not statement.condition:
|
|
35
|
+
return issues
|
|
36
|
+
|
|
37
|
+
statement_sid = statement.sid
|
|
38
|
+
line_number = statement.line_number
|
|
39
|
+
actions = statement.get_actions()
|
|
40
|
+
|
|
41
|
+
# Extract all condition keys from all condition operators
|
|
42
|
+
for operator, conditions in statement.condition.items():
|
|
43
|
+
for condition_key in conditions.keys():
|
|
44
|
+
# Validate this condition key against each action in the statement
|
|
45
|
+
for action in actions:
|
|
46
|
+
# Skip wildcard actions
|
|
47
|
+
if action == "*":
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
is_valid, error_msg = await fetcher.validate_condition_key(
|
|
51
|
+
action, condition_key
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if not is_valid:
|
|
55
|
+
issues.append(
|
|
56
|
+
ValidationIssue(
|
|
57
|
+
severity=self.get_severity(config),
|
|
58
|
+
statement_sid=statement_sid,
|
|
59
|
+
statement_index=statement_idx,
|
|
60
|
+
issue_type="invalid_condition_key",
|
|
61
|
+
message=error_msg or f"Invalid condition key: {condition_key}",
|
|
62
|
+
action=action,
|
|
63
|
+
condition_key=condition_key,
|
|
64
|
+
line_number=line_number,
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
# Only report once per condition key (not per action)
|
|
68
|
+
break
|
|
69
|
+
|
|
70
|
+
return issues
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""Policy size validation check.
|
|
2
|
+
|
|
3
|
+
This check validates that IAM policies don't exceed AWS's maximum size limits.
|
|
4
|
+
AWS enforces different size limits based on policy type:
|
|
5
|
+
- Managed policies: 6,144 characters maximum
|
|
6
|
+
- Inline policies for users: 2,048 characters maximum
|
|
7
|
+
- Inline policies for groups: 5,120 characters maximum
|
|
8
|
+
- Inline policies for roles: 10,240 characters maximum
|
|
9
|
+
|
|
10
|
+
Note: AWS does not count whitespace when calculating policy size.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import re
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
from iam_validator.core.aws_fetcher import AWSServiceFetcher
|
|
18
|
+
from iam_validator.core.check_registry import CheckConfig, PolicyCheck
|
|
19
|
+
from iam_validator.core.models import Statement, ValidationIssue
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from iam_validator.core.models import IAMPolicy
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PolicySizeCheck(PolicyCheck):
|
|
26
|
+
"""Validates that IAM policies don't exceed AWS size limits."""
|
|
27
|
+
|
|
28
|
+
# AWS IAM policy size limits (in characters, excluding whitespace)
|
|
29
|
+
DEFAULT_LIMITS = {
|
|
30
|
+
"managed": 6144,
|
|
31
|
+
"inline_user": 2048,
|
|
32
|
+
"inline_group": 5120,
|
|
33
|
+
"inline_role": 10240,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def check_id(self) -> str:
|
|
38
|
+
return "policy_size"
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def description(self) -> str:
|
|
42
|
+
return "Validates that IAM policies don't exceed AWS size limits"
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def default_severity(self) -> str:
|
|
46
|
+
return "error"
|
|
47
|
+
|
|
48
|
+
async def execute(
|
|
49
|
+
self,
|
|
50
|
+
statement: Statement,
|
|
51
|
+
statement_idx: int,
|
|
52
|
+
fetcher: AWSServiceFetcher,
|
|
53
|
+
config: CheckConfig,
|
|
54
|
+
) -> list[ValidationIssue]:
|
|
55
|
+
"""Execute the policy size check at statement level.
|
|
56
|
+
|
|
57
|
+
This is a policy-level check, so statement-level execution returns empty.
|
|
58
|
+
The actual check runs in execute_policy() which has access to the full policy.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
statement: The IAM policy statement (unused)
|
|
62
|
+
statement_idx: Index of the statement in the policy (unused)
|
|
63
|
+
fetcher: AWS service fetcher (unused for this check)
|
|
64
|
+
config: Configuration for this check instance (unused)
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Empty list (actual check runs in execute_policy())
|
|
68
|
+
"""
|
|
69
|
+
del statement, statement_idx, fetcher, config # Unused
|
|
70
|
+
# This is a policy-level check - execution happens in execute_policy()
|
|
71
|
+
return []
|
|
72
|
+
|
|
73
|
+
async def execute_policy(
|
|
74
|
+
self,
|
|
75
|
+
policy: "IAMPolicy",
|
|
76
|
+
policy_file: str,
|
|
77
|
+
fetcher: AWSServiceFetcher,
|
|
78
|
+
config: CheckConfig,
|
|
79
|
+
**kwargs,
|
|
80
|
+
) -> list[ValidationIssue]:
|
|
81
|
+
"""Execute the policy size check on the entire policy.
|
|
82
|
+
|
|
83
|
+
This method calculates the policy size (excluding whitespace) and validates
|
|
84
|
+
it against AWS limits based on the configured policy type.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
policy: The complete IAM policy to validate
|
|
88
|
+
policy_file: Path to the policy file (for context/reporting)
|
|
89
|
+
fetcher: AWS service fetcher (unused for this check)
|
|
90
|
+
config: Configuration for this check instance
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
List of ValidationIssue objects if policy exceeds size limits
|
|
94
|
+
"""
|
|
95
|
+
del policy_file, fetcher # Unused
|
|
96
|
+
issues = []
|
|
97
|
+
|
|
98
|
+
# Get the policy type from config (default to managed)
|
|
99
|
+
policy_type = config.config.get("policy_type", "managed")
|
|
100
|
+
|
|
101
|
+
# Get custom limits if provided in config, otherwise use defaults
|
|
102
|
+
size_limits = config.config.get("size_limits", self.DEFAULT_LIMITS.copy())
|
|
103
|
+
|
|
104
|
+
# Determine the applicable limit
|
|
105
|
+
limit_key = policy_type
|
|
106
|
+
if limit_key not in size_limits:
|
|
107
|
+
# If custom policy_type not found, default to managed
|
|
108
|
+
limit_key = "managed"
|
|
109
|
+
|
|
110
|
+
max_size = size_limits[limit_key]
|
|
111
|
+
|
|
112
|
+
# Convert policy to JSON and calculate size (excluding whitespace)
|
|
113
|
+
policy_json = policy.model_dump(by_alias=True, exclude_none=True)
|
|
114
|
+
policy_string = json.dumps(policy_json, separators=(",", ":"))
|
|
115
|
+
|
|
116
|
+
# Remove all whitespace as AWS doesn't count it
|
|
117
|
+
policy_size = len(re.sub(r"\s+", "", policy_string))
|
|
118
|
+
|
|
119
|
+
# Check if policy exceeds the limit
|
|
120
|
+
if policy_size > max_size:
|
|
121
|
+
severity = self.get_severity(config)
|
|
122
|
+
|
|
123
|
+
# Calculate percentage over limit
|
|
124
|
+
percentage_over = ((policy_size - max_size) / max_size) * 100
|
|
125
|
+
|
|
126
|
+
# Determine policy type description
|
|
127
|
+
policy_type_desc = {
|
|
128
|
+
"managed": "managed policy",
|
|
129
|
+
"inline_user": "inline policy for users",
|
|
130
|
+
"inline_group": "inline policy for groups",
|
|
131
|
+
"inline_role": "inline policy for roles",
|
|
132
|
+
}.get(policy_type, policy_type)
|
|
133
|
+
|
|
134
|
+
issues.append(
|
|
135
|
+
ValidationIssue(
|
|
136
|
+
severity=severity,
|
|
137
|
+
statement_sid=None, # Policy-level issue
|
|
138
|
+
statement_index=-1, # -1 indicates policy-level issue
|
|
139
|
+
issue_type="policy_size_exceeded",
|
|
140
|
+
message=f"Policy size ({policy_size:,} characters) exceeds AWS limit for {policy_type_desc} ({max_size:,} characters)",
|
|
141
|
+
suggestion=f"The policy is {policy_size - max_size:,} characters over the limit ({percentage_over:.1f}% too large). Consider:\n"
|
|
142
|
+
f" 1. Splitting the policy into multiple smaller policies\n"
|
|
143
|
+
f" 2. Using more concise action/resource patterns with wildcards\n"
|
|
144
|
+
f" 3. Removing unnecessary statements or conditions\n"
|
|
145
|
+
f" 4. For inline policies, consider using managed policies instead\n"
|
|
146
|
+
f"\nNote: AWS does not count whitespace in the size calculation.",
|
|
147
|
+
line_number=None,
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return issues
|