iam-policy-validator 1.4.0__py3-none-any.whl → 1.5.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.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/METADATA +18 -19
- {iam_policy_validator-1.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/RECORD +31 -20
- iam_validator/__version__.py +1 -1
- iam_validator/checks/__init__.py +13 -3
- iam_validator/checks/action_condition_enforcement.py +1 -6
- iam_validator/checks/condition_key_validation.py +21 -1
- iam_validator/checks/full_wildcard.py +67 -0
- iam_validator/checks/principal_validation.py +497 -3
- iam_validator/checks/sensitive_action.py +178 -0
- iam_validator/checks/service_wildcard.py +105 -0
- iam_validator/checks/utils/sensitive_action_matcher.py +39 -31
- iam_validator/checks/wildcard_action.py +62 -0
- iam_validator/checks/wildcard_resource.py +131 -0
- iam_validator/commands/download_services.py +3 -8
- iam_validator/commands/validate.py +28 -2
- iam_validator/core/aws_fetcher.py +25 -12
- iam_validator/core/check_registry.py +15 -21
- iam_validator/core/config/__init__.py +83 -0
- iam_validator/core/config/aws_api.py +35 -0
- iam_validator/core/config/condition_requirements.py +535 -0
- iam_validator/core/config/defaults.py +390 -0
- iam_validator/core/config/principal_requirements.py +421 -0
- iam_validator/core/config/sensitive_actions.py +133 -0
- iam_validator/core/config/service_principals.py +95 -0
- iam_validator/core/config/wildcards.py +124 -0
- iam_validator/core/config_loader.py +29 -9
- iam_validator/core/formatters/enhanced.py +11 -5
- iam_validator/core/formatters/sarif.py +78 -14
- iam_validator/checks/security_best_practices.py +0 -536
- iam_validator/core/defaults.py +0 -393
- {iam_policy_validator-1.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/WHEEL +0 -0
- {iam_policy_validator-1.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/entry_points.txt +0 -0
- {iam_policy_validator-1.4.0.dist-info → iam_policy_validator-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -33,6 +33,7 @@ from typing import Any
|
|
|
33
33
|
|
|
34
34
|
import httpx
|
|
35
35
|
|
|
36
|
+
from iam_validator.core.config import AWS_SERVICE_REFERENCE_BASE_URL
|
|
36
37
|
from iam_validator.core.models import ServiceDetail, ServiceInfo
|
|
37
38
|
|
|
38
39
|
logger = logging.getLogger(__name__)
|
|
@@ -121,7 +122,7 @@ class CompiledPatterns:
|
|
|
121
122
|
class AWSServiceFetcher:
|
|
122
123
|
"""Fetches AWS service information from the AWS service reference API with enhanced performance features."""
|
|
123
124
|
|
|
124
|
-
BASE_URL =
|
|
125
|
+
BASE_URL = AWS_SERVICE_REFERENCE_BASE_URL
|
|
125
126
|
|
|
126
127
|
# Common AWS services to pre-fetch
|
|
127
128
|
# All other services will be fetched on-demand (lazy loading if found in policies)
|
|
@@ -797,8 +798,15 @@ class AWSServiceFetcher:
|
|
|
797
798
|
|
|
798
799
|
async def validate_condition_key(
|
|
799
800
|
self, action: str, condition_key: str
|
|
800
|
-
) -> tuple[bool, str | None]:
|
|
801
|
-
"""Validate condition key with optimized caching.
|
|
801
|
+
) -> tuple[bool, str | None, str | None]:
|
|
802
|
+
"""Validate condition key with optimized caching.
|
|
803
|
+
|
|
804
|
+
Returns:
|
|
805
|
+
Tuple of (is_valid, error_message, warning_message)
|
|
806
|
+
- is_valid: True if key is valid (even with warning)
|
|
807
|
+
- error_message: Error message if invalid (is_valid=False)
|
|
808
|
+
- warning_message: Warning message if valid but not recommended
|
|
809
|
+
"""
|
|
802
810
|
try:
|
|
803
811
|
from iam_validator.core.aws_global_conditions import get_global_conditions
|
|
804
812
|
|
|
@@ -814,6 +822,7 @@ class AWSServiceFetcher:
|
|
|
814
822
|
return (
|
|
815
823
|
False,
|
|
816
824
|
f"Invalid AWS global condition key: '{condition_key}'.",
|
|
825
|
+
None,
|
|
817
826
|
)
|
|
818
827
|
|
|
819
828
|
# Fetch service detail (cached)
|
|
@@ -821,7 +830,7 @@ class AWSServiceFetcher:
|
|
|
821
830
|
|
|
822
831
|
# Check service-specific condition keys
|
|
823
832
|
if condition_key in service_detail.condition_keys:
|
|
824
|
-
return True, None
|
|
833
|
+
return True, None, None
|
|
825
834
|
|
|
826
835
|
# Check action-specific condition keys
|
|
827
836
|
if action_name in service_detail.actions:
|
|
@@ -830,29 +839,33 @@ class AWSServiceFetcher:
|
|
|
830
839
|
action_detail.action_condition_keys
|
|
831
840
|
and condition_key in action_detail.action_condition_keys
|
|
832
841
|
):
|
|
833
|
-
return True, None
|
|
842
|
+
return True, None, None
|
|
834
843
|
|
|
835
844
|
# If it's a global key but the action has specific condition keys defined,
|
|
836
|
-
#
|
|
845
|
+
# AWS allows it but the key may not be available in every request context
|
|
837
846
|
if is_global_key and action_detail.action_condition_keys is not None:
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
f"
|
|
841
|
-
f"
|
|
847
|
+
warning_msg = (
|
|
848
|
+
f"Global condition key '{condition_key}' is used with action '{action}'. "
|
|
849
|
+
f"While global condition keys can be used across all AWS services, "
|
|
850
|
+
f"the key may not be available in every request context. "
|
|
851
|
+
f"Verify that '{condition_key}' is available for this specific action's request context. "
|
|
852
|
+
f"Consider using '*IfExists' operators (e.g., StringEqualsIfExists) if the key might be missing."
|
|
842
853
|
)
|
|
854
|
+
return True, None, warning_msg
|
|
843
855
|
|
|
844
856
|
# If it's a global key and action doesn't define specific keys, allow it
|
|
845
857
|
if is_global_key:
|
|
846
|
-
return True, None
|
|
858
|
+
return True, None, None
|
|
847
859
|
|
|
848
860
|
return (
|
|
849
861
|
False,
|
|
850
862
|
f"Condition key '{condition_key}' is not valid for action '{action}'",
|
|
863
|
+
None,
|
|
851
864
|
)
|
|
852
865
|
|
|
853
866
|
except Exception as e:
|
|
854
867
|
logger.error(f"Error validating condition key {condition_key} for {action}: {e}")
|
|
855
|
-
return False, f"Failed to validate condition key: {str(e)}"
|
|
868
|
+
return False, f"Failed to validate condition key: {str(e)}", None
|
|
856
869
|
|
|
857
870
|
async def clear_caches(self) -> None:
|
|
858
871
|
"""Clear all caches (memory and disk)."""
|
|
@@ -440,27 +440,21 @@ def create_default_registry(
|
|
|
440
440
|
|
|
441
441
|
if include_builtin_checks:
|
|
442
442
|
# Import and register built-in checks
|
|
443
|
-
from iam_validator
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
)
|
|
454
|
-
|
|
455
|
-
registry.register(
|
|
456
|
-
registry.register(
|
|
457
|
-
registry.register(
|
|
458
|
-
registry.register(SecurityBestPracticesCheck())
|
|
459
|
-
registry.register(ActionConditionEnforcementCheck())
|
|
460
|
-
registry.register(ActionResourceConstraintCheck())
|
|
461
|
-
registry.register(SidUniquenessCheck())
|
|
462
|
-
registry.register(PolicySizeCheck())
|
|
463
|
-
registry.register(PrincipalValidationCheck())
|
|
443
|
+
from iam_validator import checks
|
|
444
|
+
|
|
445
|
+
registry.register(checks.ActionValidationCheck())
|
|
446
|
+
registry.register(checks.ConditionKeyValidationCheck())
|
|
447
|
+
registry.register(checks.ResourceValidationCheck())
|
|
448
|
+
registry.register(checks.WildcardActionCheck())
|
|
449
|
+
registry.register(checks.WildcardResourceCheck())
|
|
450
|
+
registry.register(checks.FullWildcardCheck())
|
|
451
|
+
registry.register(checks.ServiceWildcardCheck())
|
|
452
|
+
registry.register(checks.SensitiveActionCheck())
|
|
453
|
+
registry.register(checks.ActionConditionEnforcementCheck())
|
|
454
|
+
registry.register(checks.ActionResourceConstraintCheck())
|
|
455
|
+
registry.register(checks.SidUniquenessCheck())
|
|
456
|
+
registry.register(checks.PolicySizeCheck())
|
|
457
|
+
registry.register(checks.PrincipalValidationCheck())
|
|
464
458
|
|
|
465
459
|
# Note: SID uniqueness check is registered above but its actual execution
|
|
466
460
|
# happens at the policy level in _validate_policy_with_registry() since it
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core configuration modules for IAM Policy Validator.
|
|
3
|
+
|
|
4
|
+
This package contains default configuration data used by validators, organized into
|
|
5
|
+
logical modules for better maintainability and performance.
|
|
6
|
+
|
|
7
|
+
All configuration is defined as Python code (not YAML/JSON) for:
|
|
8
|
+
- Faster loading (no parsing overhead)
|
|
9
|
+
- Better PyPI packaging (no data files to manage)
|
|
10
|
+
- Type hints and IDE support
|
|
11
|
+
- Compiled to .pyc for even faster imports
|
|
12
|
+
|
|
13
|
+
Performance benefits:
|
|
14
|
+
- 5-10x faster than YAML parsing
|
|
15
|
+
- Zero runtime parsing overhead
|
|
16
|
+
- Lazy loading support
|
|
17
|
+
- O(1) frozenset lookups
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from iam_validator.core.config.aws_api import (
|
|
21
|
+
AWS_SERVICE_REFERENCE_BASE_URL,
|
|
22
|
+
get_service_reference_url,
|
|
23
|
+
)
|
|
24
|
+
from iam_validator.core.config.condition_requirements import (
|
|
25
|
+
ALL_CONDITION_REQUIREMENTS,
|
|
26
|
+
DEFAULT_CONDITION_REQUIREMENTS,
|
|
27
|
+
get_all_requirement_names,
|
|
28
|
+
get_default_requirements,
|
|
29
|
+
get_requirement,
|
|
30
|
+
get_requirements_by_names,
|
|
31
|
+
get_requirements_by_severity,
|
|
32
|
+
)
|
|
33
|
+
from iam_validator.core.config.defaults import DEFAULT_CONFIG
|
|
34
|
+
from iam_validator.core.config.principal_requirements import (
|
|
35
|
+
ALL_PRINCIPAL_REQUIREMENTS,
|
|
36
|
+
DEFAULT_ENABLED_REQUIREMENTS,
|
|
37
|
+
get_all_principal_requirement_names,
|
|
38
|
+
get_default_principal_requirements,
|
|
39
|
+
get_principal_requirement,
|
|
40
|
+
get_principal_requirements_by_names,
|
|
41
|
+
get_principal_requirements_by_severity,
|
|
42
|
+
)
|
|
43
|
+
from iam_validator.core.config.sensitive_actions import (
|
|
44
|
+
DEFAULT_SENSITIVE_ACTIONS,
|
|
45
|
+
get_sensitive_actions,
|
|
46
|
+
)
|
|
47
|
+
from iam_validator.core.config.service_principals import DEFAULT_SERVICE_PRINCIPALS
|
|
48
|
+
from iam_validator.core.config.wildcards import (
|
|
49
|
+
DEFAULT_ALLOWED_WILDCARDS,
|
|
50
|
+
DEFAULT_SERVICE_WILDCARDS,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
# Default configuration
|
|
55
|
+
"DEFAULT_CONFIG",
|
|
56
|
+
# AWS API endpoints
|
|
57
|
+
"AWS_SERVICE_REFERENCE_BASE_URL",
|
|
58
|
+
"get_service_reference_url",
|
|
59
|
+
# Sensitive actions
|
|
60
|
+
"DEFAULT_SENSITIVE_ACTIONS",
|
|
61
|
+
"get_sensitive_actions",
|
|
62
|
+
# Condition requirements (for actions)
|
|
63
|
+
"DEFAULT_CONDITION_REQUIREMENTS",
|
|
64
|
+
"ALL_CONDITION_REQUIREMENTS",
|
|
65
|
+
"get_default_requirements",
|
|
66
|
+
"get_requirement",
|
|
67
|
+
"get_all_requirement_names",
|
|
68
|
+
"get_requirements_by_names",
|
|
69
|
+
"get_requirements_by_severity",
|
|
70
|
+
# Principal requirements (for principals)
|
|
71
|
+
"ALL_PRINCIPAL_REQUIREMENTS",
|
|
72
|
+
"DEFAULT_ENABLED_REQUIREMENTS",
|
|
73
|
+
"get_default_principal_requirements",
|
|
74
|
+
"get_principal_requirement",
|
|
75
|
+
"get_all_principal_requirement_names",
|
|
76
|
+
"get_principal_requirements_by_names",
|
|
77
|
+
"get_principal_requirements_by_severity",
|
|
78
|
+
# Wildcards
|
|
79
|
+
"DEFAULT_ALLOWED_WILDCARDS",
|
|
80
|
+
"DEFAULT_SERVICE_WILDCARDS",
|
|
81
|
+
# Service principals
|
|
82
|
+
"DEFAULT_SERVICE_PRINCIPALS",
|
|
83
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AWS API configuration constants.
|
|
3
|
+
|
|
4
|
+
This module centralizes AWS API endpoints and related configuration
|
|
5
|
+
used throughout the IAM Policy Validator.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# AWS Service Reference API base URL
|
|
9
|
+
# This is the official AWS service reference that provides action, resource, and condition key metadata
|
|
10
|
+
AWS_SERVICE_REFERENCE_BASE_URL = "https://servicereference.us-east-1.amazonaws.com/"
|
|
11
|
+
|
|
12
|
+
# Alternative endpoints for different regions (currently not used, but available for future expansion)
|
|
13
|
+
AWS_SERVICE_REFERENCE_ENDPOINTS = {
|
|
14
|
+
"us-east-1": "https://servicereference.us-east-1.amazonaws.com/",
|
|
15
|
+
# Add other regional endpoints if they become available
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_service_reference_url(region: str = "us-east-1") -> str:
|
|
20
|
+
"""
|
|
21
|
+
Get the AWS Service Reference API URL for a specific region.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
region: AWS region (default: us-east-1)
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
The service reference base URL for the specified region
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
>>> get_service_reference_url()
|
|
31
|
+
'https://servicereference.us-east-1.amazonaws.com/'
|
|
32
|
+
>>> get_service_reference_url("us-east-1")
|
|
33
|
+
'https://servicereference.us-east-1.amazonaws.com/'
|
|
34
|
+
"""
|
|
35
|
+
return AWS_SERVICE_REFERENCE_ENDPOINTS.get(region, AWS_SERVICE_REFERENCE_BASE_URL)
|