sraverify 0.1.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.
- sraverify/__init__.py +36 -0
- sraverify/checks/__init__.py +56 -0
- sraverify/checks/accessanalyzer/SRA_IAA_1.py +188 -0
- sraverify/checks/accessanalyzer/SRA_IAA_2.py +162 -0
- sraverify/checks/accessanalyzer/SRA_IAA_3.py +260 -0
- sraverify/checks/accessanalyzer/SRA_IAA_4.py +207 -0
- sraverify/checks/accessanalyzer/__init__.py +3 -0
- sraverify/checks/cloudtrail/SRA-CT-1.py +220 -0
- sraverify/checks/cloudtrail/SRA-CT-10.py +229 -0
- sraverify/checks/cloudtrail/SRA-CT-11.py +242 -0
- sraverify/checks/cloudtrail/SRA-CT-12.py +163 -0
- sraverify/checks/cloudtrail/SRA-CT-13.py +279 -0
- sraverify/checks/cloudtrail/SRA-CT-2.py +218 -0
- sraverify/checks/cloudtrail/SRA-CT-3.py +196 -0
- sraverify/checks/cloudtrail/SRA-CT-4.py +161 -0
- sraverify/checks/cloudtrail/SRA-CT-5.py +200 -0
- sraverify/checks/cloudtrail/SRA-CT-6.py +161 -0
- sraverify/checks/cloudtrail/SRA-CT-7.py +194 -0
- sraverify/checks/cloudtrail/SRA-CT-8.py +226 -0
- sraverify/checks/cloudtrail/SRA-CT-9.py +226 -0
- sraverify/checks/cloudtrail/__init__.py +3 -0
- sraverify/checks/config/SRA-CONFIG-1.py +197 -0
- sraverify/checks/config/__init__.py +3 -0
- sraverify/core/__init__.py +3 -0
- sraverify/core/check.py +227 -0
- sraverify/core/logging.py +37 -0
- sraverify/core/session.py +47 -0
- sraverify/lib/__init__.py +4 -0
- sraverify/lib/audit_info.py +37 -0
- sraverify/lib/banner.py +42 -0
- sraverify/lib/check_loader.py +80 -0
- sraverify/lib/org_mgmt_checker.py +86 -0
- sraverify/lib/outputs.py +46 -0
- sraverify/lib/progress.py +75 -0
- sraverify/lib/regions.py +27 -0
- sraverify/lib/session.py +23 -0
- sraverify/main.py +350 -0
- sraverify/services/__init__.py +3 -0
- sraverify/services/accessanalyzer/__init__.py +15 -0
- sraverify/services/accessanalyzer/base.py +123 -0
- sraverify/services/accessanalyzer/checks/__init__.py +3 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_01.py +82 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_02.py +82 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_03.py +103 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_04.py +139 -0
- sraverify/services/accessanalyzer/client.py +123 -0
- sraverify/services/account/__init__.py +9 -0
- sraverify/services/account/base.py +56 -0
- sraverify/services/account/checks/__init__.py +1 -0
- sraverify/services/account/checks/sra_account_01.py +65 -0
- sraverify/services/account/checks/sra_account_02.py +63 -0
- sraverify/services/account/checks/sra_account_03.py +63 -0
- sraverify/services/account/client.py +51 -0
- sraverify/services/auditmanager/__init__.py +10 -0
- sraverify/services/auditmanager/base.py +72 -0
- sraverify/services/auditmanager/checks/__init__.py +1 -0
- sraverify/services/auditmanager/checks/sra_auditmanager_01.py +58 -0
- sraverify/services/auditmanager/checks/sra_auditmanager_02.py +80 -0
- sraverify/services/auditmanager/client.py +58 -0
- sraverify/services/cloudtrail/__init__.py +33 -0
- sraverify/services/cloudtrail/base.py +167 -0
- sraverify/services/cloudtrail/checks/__init__.py +1 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_01.py +83 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_02.py +99 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_03.py +94 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_04.py +92 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_05.py +106 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_06.py +93 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_07.py +96 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_08.py +145 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_09.py +167 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_10.py +162 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_11.py +178 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_12.py +77 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_13.py +120 -0
- sraverify/services/cloudtrail/client.py +118 -0
- sraverify/services/config/__init__.py +25 -0
- sraverify/services/config/base.py +249 -0
- sraverify/services/config/checks/__init__.py +1 -0
- sraverify/services/config/checks/sra_config_01.py +123 -0
- sraverify/services/config/checks/sra_config_02.py +156 -0
- sraverify/services/config/checks/sra_config_03.py +149 -0
- sraverify/services/config/checks/sra_config_04.py +104 -0
- sraverify/services/config/checks/sra_config_05.py +104 -0
- sraverify/services/config/checks/sra_config_06.py +194 -0
- sraverify/services/config/checks/sra_config_07.py +162 -0
- sraverify/services/config/checks/sra_config_08.py +185 -0
- sraverify/services/config/checks/sra_config_09.py +177 -0
- sraverify/services/config/client.py +264 -0
- sraverify/services/ec2/__init__.py +8 -0
- sraverify/services/ec2/base.py +75 -0
- sraverify/services/ec2/checks/__init__.py +1 -0
- sraverify/services/ec2/checks/sra_ec2_01.py +83 -0
- sraverify/services/ec2/client.py +63 -0
- sraverify/services/firewallmanager/__init__.py +23 -0
- sraverify/services/firewallmanager/base.py +48 -0
- sraverify/services/firewallmanager/checks/__init__.py +1 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_01.py +75 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_02.py +57 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_03.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_04.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_05.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_06.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_07.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_08.py +61 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_09.py +61 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_10.py +71 -0
- sraverify/services/firewallmanager/client.py +40 -0
- sraverify/services/guardduty/__init__.py +58 -0
- sraverify/services/guardduty/base.py +207 -0
- sraverify/services/guardduty/checks/__init__.py +3 -0
- sraverify/services/guardduty/checks/sra_guardduty_01.py +51 -0
- sraverify/services/guardduty/checks/sra_guardduty_02.py +80 -0
- sraverify/services/guardduty/checks/sra_guardduty_03.py +77 -0
- sraverify/services/guardduty/checks/sra_guardduty_04.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_05.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_06.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_07.py +85 -0
- sraverify/services/guardduty/checks/sra_guardduty_08.py +83 -0
- sraverify/services/guardduty/checks/sra_guardduty_09.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_10.py +83 -0
- sraverify/services/guardduty/checks/sra_guardduty_11.py +93 -0
- sraverify/services/guardduty/checks/sra_guardduty_12.py +83 -0
- sraverify/services/guardduty/checks/sra_guardduty_13.py +90 -0
- sraverify/services/guardduty/checks/sra_guardduty_14.py +136 -0
- sraverify/services/guardduty/checks/sra_guardduty_15.py +94 -0
- sraverify/services/guardduty/checks/sra_guardduty_16.py +94 -0
- sraverify/services/guardduty/checks/sra_guardduty_17.py +91 -0
- sraverify/services/guardduty/checks/sra_guardduty_18.py +91 -0
- sraverify/services/guardduty/checks/sra_guardduty_19.py +91 -0
- sraverify/services/guardduty/checks/sra_guardduty_20.py +111 -0
- sraverify/services/guardduty/checks/sra_guardduty_21.py +112 -0
- sraverify/services/guardduty/checks/sra_guardduty_22.py +111 -0
- sraverify/services/guardduty/checks/sra_guardduty_23.py +154 -0
- sraverify/services/guardduty/checks/sra_guardduty_24.py +111 -0
- sraverify/services/guardduty/checks/sra_guardduty_25.py +111 -0
- sraverify/services/guardduty/client.py +107 -0
- sraverify/services/inspector/__init__.py +29 -0
- sraverify/services/inspector/base.py +233 -0
- sraverify/services/inspector/checks/__init__.py +3 -0
- sraverify/services/inspector/checks/sra_inspector_01.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_02.py +68 -0
- sraverify/services/inspector/checks/sra_inspector_03.py +68 -0
- sraverify/services/inspector/checks/sra_inspector_04.py +70 -0
- sraverify/services/inspector/checks/sra_inspector_05.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_06.py +115 -0
- sraverify/services/inspector/checks/sra_inspector_07.py +109 -0
- sraverify/services/inspector/checks/sra_inspector_08.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_09.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_10.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_11.py +69 -0
- sraverify/services/inspector/client.py +99 -0
- sraverify/services/macie/__init__.py +27 -0
- sraverify/services/macie/base.py +271 -0
- sraverify/services/macie/checks/__init__.py +1 -0
- sraverify/services/macie/checks/sra_macie_01.py +100 -0
- sraverify/services/macie/checks/sra_macie_02.py +102 -0
- sraverify/services/macie/checks/sra_macie_03.py +152 -0
- sraverify/services/macie/checks/sra_macie_04.py +120 -0
- sraverify/services/macie/checks/sra_macie_05.py +85 -0
- sraverify/services/macie/checks/sra_macie_06.py +124 -0
- sraverify/services/macie/checks/sra_macie_07.py +138 -0
- sraverify/services/macie/checks/sra_macie_08.py +82 -0
- sraverify/services/macie/checks/sra_macie_09.py +103 -0
- sraverify/services/macie/checks/sra_macie_10.py +81 -0
- sraverify/services/macie/client.py +220 -0
- sraverify/services/s3/__init__.py +16 -0
- sraverify/services/s3/base.py +69 -0
- sraverify/services/s3/checks/__init__.py +1 -0
- sraverify/services/s3/checks/sra_s3_01.py +89 -0
- sraverify/services/s3/checks/sra_s3_02.py +89 -0
- sraverify/services/s3/checks/sra_s3_03.py +88 -0
- sraverify/services/s3/checks/sra_s3_04.py +88 -0
- sraverify/services/s3/client.py +52 -0
- sraverify/services/securityhub/__init__.py +27 -0
- sraverify/services/securityhub/base.py +349 -0
- sraverify/services/securityhub/checks/__init__.py +1 -0
- sraverify/services/securityhub/checks/sra_securityhub_01.py +115 -0
- sraverify/services/securityhub/checks/sra_securityhub_02.py +114 -0
- sraverify/services/securityhub/checks/sra_securityhub_03.py +136 -0
- sraverify/services/securityhub/checks/sra_securityhub_04.py +75 -0
- sraverify/services/securityhub/checks/sra_securityhub_05.py +102 -0
- sraverify/services/securityhub/checks/sra_securityhub_06.py +113 -0
- sraverify/services/securityhub/checks/sra_securityhub_07.py +121 -0
- sraverify/services/securityhub/checks/sra_securityhub_08.py +113 -0
- sraverify/services/securityhub/checks/sra_securityhub_09.py +100 -0
- sraverify/services/securityhub/checks/sra_securityhub_10.py +94 -0
- sraverify/services/securityhub/checks/sra_securityhub_11.py +73 -0
- sraverify/services/securityhub/client.py +249 -0
- sraverify/services/securityincidentresponse/__init__.py +13 -0
- sraverify/services/securityincidentresponse/base.py +95 -0
- sraverify/services/securityincidentresponse/checks/__init__.py +1 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_01.py +77 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_02.py +72 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_03.py +86 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_04.py +117 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_05.py +55 -0
- sraverify/services/securityincidentresponse/client.py +71 -0
- sraverify/services/securitylake/__init__.py +39 -0
- sraverify/services/securitylake/base.py +461 -0
- sraverify/services/securitylake/checks/__init__.py +1 -0
- sraverify/services/securitylake/checks/sra_securitylake_01.py +98 -0
- sraverify/services/securitylake/checks/sra_securitylake_02.py +133 -0
- sraverify/services/securitylake/checks/sra_securitylake_03.py +116 -0
- sraverify/services/securitylake/checks/sra_securitylake_04.py +72 -0
- sraverify/services/securitylake/checks/sra_securitylake_05.py +116 -0
- sraverify/services/securitylake/checks/sra_securitylake_06.py +104 -0
- sraverify/services/securitylake/checks/sra_securitylake_07.py +108 -0
- sraverify/services/securitylake/checks/sra_securitylake_08.py +107 -0
- sraverify/services/securitylake/checks/sra_securitylake_09.py +107 -0
- sraverify/services/securitylake/checks/sra_securitylake_10.py +106 -0
- sraverify/services/securitylake/checks/sra_securitylake_11.py +109 -0
- sraverify/services/securitylake/checks/sra_securitylake_12.py +108 -0
- sraverify/services/securitylake/checks/sra_securitylake_13.py +108 -0
- sraverify/services/securitylake/checks/sra_securitylake_14.py +72 -0
- sraverify/services/securitylake/checks/sra_securitylake_15.py +120 -0
- sraverify/services/securitylake/checks/sra_securitylake_16.py +104 -0
- sraverify/services/securitylake/checks/sra_securitylake_17.py +103 -0
- sraverify/services/securitylake/client.py +247 -0
- sraverify/services/shield/__init__.py +33 -0
- sraverify/services/shield/base.py +199 -0
- sraverify/services/shield/checks/__init__.py +1 -0
- sraverify/services/shield/checks/sra_shield_01.py +68 -0
- sraverify/services/shield/checks/sra_shield_02.py +77 -0
- sraverify/services/shield/checks/sra_shield_03.py +84 -0
- sraverify/services/shield/checks/sra_shield_04.py +84 -0
- sraverify/services/shield/checks/sra_shield_05.py +84 -0
- sraverify/services/shield/checks/sra_shield_06.py +84 -0
- sraverify/services/shield/checks/sra_shield_07.py +84 -0
- sraverify/services/shield/checks/sra_shield_08.py +69 -0
- sraverify/services/shield/checks/sra_shield_09.py +86 -0
- sraverify/services/shield/checks/sra_shield_10.py +100 -0
- sraverify/services/shield/checks/sra_shield_11.py +71 -0
- sraverify/services/shield/checks/sra_shield_12.py +130 -0
- sraverify/services/shield/checks/sra_shield_13.py +112 -0
- sraverify/services/shield/checks/sra_shield_14.py +111 -0
- sraverify/services/shield/client.py +214 -0
- sraverify/services/waf/__init__.py +21 -0
- sraverify/services/waf/base.py +100 -0
- sraverify/services/waf/checks/__init__.py +1 -0
- sraverify/services/waf/checks/sra_waf_01.py +63 -0
- sraverify/services/waf/checks/sra_waf_02.py +82 -0
- sraverify/services/waf/checks/sra_waf_03.py +123 -0
- sraverify/services/waf/checks/sra_waf_04.py +94 -0
- sraverify/services/waf/checks/sra_waf_05.py +94 -0
- sraverify/services/waf/checks/sra_waf_06.py +91 -0
- sraverify/services/waf/checks/sra_waf_07.py +94 -0
- sraverify/services/waf/checks/sra_waf_08.py +66 -0
- sraverify/services/waf/checks/sra_waf_09.py +95 -0
- sraverify/services/waf/client.py +109 -0
- sraverify/utils/__init__.py +3 -0
- sraverify/utils/banner.py +65 -0
- sraverify/utils/outputs.py +57 -0
- sraverify/utils/progress.py +97 -0
- sraverify-0.1.0.dist-info/LICENSE +175 -0
- sraverify-0.1.0.dist-info/METADATA +516 -0
- sraverify-0.1.0.dist-info/NOTICE +1 -0
- sraverify-0.1.0.dist-info/RECORD +261 -0
- sraverify-0.1.0.dist-info/WHEEL +5 -0
- sraverify-0.1.0.dist-info/entry_points.txt +2 -0
- sraverify-0.1.0.dist-info/top_level.txt +1 -0
sraverify/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
sraverify - Security Reference Architecture Verification Tool
|
|
3
|
+
|
|
4
|
+
This package provides both a command-line interface and a Python library for verifying
|
|
5
|
+
AWS Security Reference Architecture implementations.
|
|
6
|
+
|
|
7
|
+
Example usage as a library:
|
|
8
|
+
|
|
9
|
+
from sraverify import SRAVerify
|
|
10
|
+
|
|
11
|
+
# Create an instance with optional AWS profile and regions
|
|
12
|
+
sra = SRAVerify(profile='my-profile', regions=['us-east-1', 'us-west-2'])
|
|
13
|
+
|
|
14
|
+
# Get available checks and services
|
|
15
|
+
checks = sra.get_available_checks()
|
|
16
|
+
services = sra.get_available_services()
|
|
17
|
+
|
|
18
|
+
# Run checks with various filters
|
|
19
|
+
findings = sra.run_checks(
|
|
20
|
+
account_type='application', # or 'audit', 'log-archive', 'management', 'all'
|
|
21
|
+
service='GuardDuty', # optional service filter
|
|
22
|
+
check_id='SRA-GD-1', # optional specific check
|
|
23
|
+
audit_accounts=['123456789012'], # optional audit account IDs
|
|
24
|
+
log_archive_accounts=['987654321098'] # optional log archive account IDs
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Process findings
|
|
28
|
+
for finding in findings:
|
|
29
|
+
print(f"{finding['CheckId']}: {finding['Status']} - {finding['Title']}")
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
__version__ = "0.1.0"
|
|
33
|
+
|
|
34
|
+
from sraverify.main import SRAVerify
|
|
35
|
+
|
|
36
|
+
__all__ = ['SRAVerify']
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# sraverify/checks/__init__.py
|
|
2
|
+
"""
|
|
3
|
+
Base classes for security checks
|
|
4
|
+
"""
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
import boto3
|
|
7
|
+
from sraverify.lib.org_mgmt_checker import OrgMgmtChecker
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SecurityCheck:
|
|
11
|
+
"""Base class for all security checks"""
|
|
12
|
+
def __init__(self, check_type="account"):
|
|
13
|
+
self.check_type = check_type
|
|
14
|
+
self.check_id = None
|
|
15
|
+
self.title = None
|
|
16
|
+
self.description = None
|
|
17
|
+
self.rationale = None
|
|
18
|
+
self.remediation = None
|
|
19
|
+
self.impact = "Unknown"
|
|
20
|
+
self.findings = []
|
|
21
|
+
self._regions = None
|
|
22
|
+
self.org_checker = OrgMgmtChecker()
|
|
23
|
+
|
|
24
|
+
def initialize(self, regions: Optional[List[str]] = None):
|
|
25
|
+
"""Initialize check with optional regions"""
|
|
26
|
+
if self.check_type == "account":
|
|
27
|
+
self._regions = regions if regions else self._get_enabled_regions()
|
|
28
|
+
# Organization checks don't use regions, so we don't set them
|
|
29
|
+
|
|
30
|
+
def _get_enabled_regions(self) -> List[str]:
|
|
31
|
+
"""Get all enabled regions in the AWS account"""
|
|
32
|
+
try:
|
|
33
|
+
session = boto3.Session()
|
|
34
|
+
ec2_client = session.client('ec2', region_name='us-east-1')
|
|
35
|
+
response = ec2_client.describe_regions(AllRegions=False)
|
|
36
|
+
return [region['RegionName'] for region in response['Regions']]
|
|
37
|
+
except Exception as e:
|
|
38
|
+
raise Exception(f"Failed to get enabled regions: {str(e)}")
|
|
39
|
+
|
|
40
|
+
def validate_regions(self, regions: List[str]) -> bool:
|
|
41
|
+
"""Validate if specified regions are valid and enabled"""
|
|
42
|
+
enabled_regions = set(self._get_enabled_regions())
|
|
43
|
+
return all(region in enabled_regions for region in regions)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def regions(self) -> List[str]:
|
|
47
|
+
"""Get regions for this check"""
|
|
48
|
+
return self._regions if self._regions else []
|
|
49
|
+
|
|
50
|
+
def run(self, session):
|
|
51
|
+
"""Run the security check"""
|
|
52
|
+
raise NotImplementedError("Subclasses must implement run()")
|
|
53
|
+
|
|
54
|
+
def get_findings(self):
|
|
55
|
+
"""Return findings from the check"""
|
|
56
|
+
return self.findings
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# sraverify/checks/accessanalyzer/SRA_IAA_1.py
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Any, Optional
|
|
4
|
+
from botocore.exceptions import ClientError
|
|
5
|
+
import boto3
|
|
6
|
+
from sraverify.lib.check_loader import SecurityCheck
|
|
7
|
+
|
|
8
|
+
class SRAIAA1(SecurityCheck):
|
|
9
|
+
"""SRA-IAA-1: IAM Access Analyzer External Access"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, check_type="account"):
|
|
12
|
+
"""Initialize the check with account type"""
|
|
13
|
+
super().__init__(check_type=check_type)
|
|
14
|
+
self.check_type = check_type
|
|
15
|
+
self.check_id = "SRA-IAA-1"
|
|
16
|
+
self.check_type = "account"
|
|
17
|
+
self.check_name = "IAM Access Analyzer External Access"
|
|
18
|
+
self.severity = 'HIGH'
|
|
19
|
+
self.description = ('This check verifies whether IAA external access analyzer is configured with a zone of trust '
|
|
20
|
+
'of AWS account. IAM Access Analyzer generates a finding for each instance of a resource-based '
|
|
21
|
+
'policy that grants access to a resource within your zone of trust to a principal that is not '
|
|
22
|
+
'within your zone of trust.')
|
|
23
|
+
self.check_logic = ('1. Check for active analyzer within account with account zone of trust | '
|
|
24
|
+
'2. Verify archive rules configuration for findings management | '
|
|
25
|
+
'3. Verify analyzer status and configuration | '
|
|
26
|
+
'4. Check passes if account-level analyzer is active with proper configuration')
|
|
27
|
+
self.service = 'IAM'
|
|
28
|
+
self.findings = []
|
|
29
|
+
self._regions = None
|
|
30
|
+
|
|
31
|
+
def initialize(self, regions: Optional[List[str]] = None):
|
|
32
|
+
"""Initialize check with optional regions"""
|
|
33
|
+
self._regions = regions
|
|
34
|
+
|
|
35
|
+
def get_findings(self):
|
|
36
|
+
"""Return the findings"""
|
|
37
|
+
return self.findings
|
|
38
|
+
|
|
39
|
+
def _create_finding(self, status: str, region: str, account_id: str,
|
|
40
|
+
resource_id: str, actual_value: str,
|
|
41
|
+
remediation: str) -> Dict[str, Any]:
|
|
42
|
+
"""Create a standardized finding"""
|
|
43
|
+
return {
|
|
44
|
+
'CheckId': self.check_id,
|
|
45
|
+
'Status': status,
|
|
46
|
+
'Region': region,
|
|
47
|
+
"Severity": self.severity,
|
|
48
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
49
|
+
'Description': self.description,
|
|
50
|
+
'ResourceId': resource_id,
|
|
51
|
+
'ResourceType': 'AWS::AccessAnalyzer::Analyzer',
|
|
52
|
+
'AccountId': account_id,
|
|
53
|
+
'CheckedValue': 'Access Analyzer Configuration',
|
|
54
|
+
'ActualValue': actual_value,
|
|
55
|
+
'Remediation': remediation,
|
|
56
|
+
'Service': self.service,
|
|
57
|
+
'CheckLogic': self.check_logic,
|
|
58
|
+
'CheckType': self.check_type
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
def _check_region(self, session: boto3.Session, region: str) -> Optional[Dict[str, Any]]:
|
|
62
|
+
"""Check Access Analyzer configuration in a specific region"""
|
|
63
|
+
try:
|
|
64
|
+
account_id = session.client('sts').get_caller_identity()['Account']
|
|
65
|
+
analyzer_client = session.client('accessanalyzer', region_name=region)
|
|
66
|
+
|
|
67
|
+
# Step 1: Check for account-level analyzer
|
|
68
|
+
try:
|
|
69
|
+
analyzers = analyzer_client.list_analyzers()['analyzers']
|
|
70
|
+
account_analyzer = None
|
|
71
|
+
|
|
72
|
+
for analyzer in analyzers:
|
|
73
|
+
if (analyzer['status'] == 'ACTIVE' and
|
|
74
|
+
analyzer['type'] == 'ACCOUNT'):
|
|
75
|
+
account_analyzer = analyzer
|
|
76
|
+
break
|
|
77
|
+
|
|
78
|
+
if not account_analyzer:
|
|
79
|
+
return self._create_finding(
|
|
80
|
+
status='FAIL',
|
|
81
|
+
region=region,
|
|
82
|
+
account_id=account_id,
|
|
83
|
+
resource_id=account_id,
|
|
84
|
+
actual_value='No active account-level analyzer found',
|
|
85
|
+
remediation='Create an account-level IAM Access Analyzer'
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Step 2: Check archive rules configuration
|
|
89
|
+
try:
|
|
90
|
+
archive_rules = analyzer_client.list_archive_rules(
|
|
91
|
+
analyzerName=account_analyzer['name']
|
|
92
|
+
)['archiveRules']
|
|
93
|
+
|
|
94
|
+
# Step 3: Verify analyzer configuration
|
|
95
|
+
try:
|
|
96
|
+
analyzer_details = analyzer_client.get_analyzer(
|
|
97
|
+
analyzerName=account_analyzer['name']
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Step 4: All checks passed
|
|
101
|
+
return self._create_finding(
|
|
102
|
+
status='PASS',
|
|
103
|
+
region=region,
|
|
104
|
+
account_id=account_id,
|
|
105
|
+
resource_id=account_analyzer['arn'],
|
|
106
|
+
actual_value=(f"Active account analyzer: {account_analyzer['name']}, "
|
|
107
|
+
f"Archive Rules: {len(archive_rules)}"),
|
|
108
|
+
remediation='None required'
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
except ClientError as e:
|
|
112
|
+
return self._create_finding(
|
|
113
|
+
status='ERROR',
|
|
114
|
+
region=region,
|
|
115
|
+
account_id=account_id,
|
|
116
|
+
resource_id=account_analyzer['arn'],
|
|
117
|
+
actual_value=f'Error checking analyzer configuration: {str(e)}',
|
|
118
|
+
remediation='Verify IAM Access Analyzer permissions'
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
except ClientError as e:
|
|
122
|
+
return self._create_finding(
|
|
123
|
+
status='ERROR',
|
|
124
|
+
region=region,
|
|
125
|
+
account_id=account_id,
|
|
126
|
+
resource_id=account_analyzer['arn'],
|
|
127
|
+
actual_value=f'Error checking archive rules: {str(e)}',
|
|
128
|
+
remediation='Verify IAM Access Analyzer permissions'
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
except ClientError as e:
|
|
132
|
+
return self._create_finding(
|
|
133
|
+
status='ERROR',
|
|
134
|
+
region=region,
|
|
135
|
+
account_id=account_id,
|
|
136
|
+
resource_id=account_id,
|
|
137
|
+
actual_value=f'Error accessing Access Analyzer: {str(e)}',
|
|
138
|
+
remediation='Verify IAM Access Analyzer permissions'
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
except Exception as e:
|
|
142
|
+
return self._create_finding(
|
|
143
|
+
status='ERROR',
|
|
144
|
+
region=region,
|
|
145
|
+
account_id='Unknown',
|
|
146
|
+
resource_id='Unknown',
|
|
147
|
+
actual_value=f'Error: {str(e)}',
|
|
148
|
+
remediation='Check logs for more details'
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
def run(self, session: boto3.Session):
|
|
152
|
+
"""Run the security check"""
|
|
153
|
+
try:
|
|
154
|
+
# Get regions to check
|
|
155
|
+
regions_to_check = self._regions if self._regions else [session.region_name]
|
|
156
|
+
|
|
157
|
+
# Check each region
|
|
158
|
+
for region in regions_to_check:
|
|
159
|
+
try:
|
|
160
|
+
finding = self._check_region(session, region)
|
|
161
|
+
if finding:
|
|
162
|
+
self.findings.append(finding)
|
|
163
|
+
except Exception as e:
|
|
164
|
+
self.findings.append(
|
|
165
|
+
self._create_finding(
|
|
166
|
+
status='ERROR',
|
|
167
|
+
region=region,
|
|
168
|
+
account_id='Unknown',
|
|
169
|
+
resource_id='Unknown',
|
|
170
|
+
actual_value=f'Region check failed: {str(e)}',
|
|
171
|
+
remediation='Check regional access and permissions'
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
except Exception as e:
|
|
176
|
+
# Handle any unexpected errors during check execution
|
|
177
|
+
self.findings.append(
|
|
178
|
+
self._create_finding(
|
|
179
|
+
status='ERROR',
|
|
180
|
+
region='Unknown',
|
|
181
|
+
account_id='Unknown',
|
|
182
|
+
resource_id='Unknown',
|
|
183
|
+
actual_value=f'Check execution failed: {str(e)}',
|
|
184
|
+
remediation='Check logs for more details'
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return self.findings
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
from typing import Dict, List, Any
|
|
2
|
+
from sraverify.checks import SecurityCheck
|
|
3
|
+
from botocore.exceptions import ClientError
|
|
4
|
+
|
|
5
|
+
class SRAIAA2(SecurityCheck):
|
|
6
|
+
"""SRA-IAA-2: IAM Access Analyzer Delegated Administration"""
|
|
7
|
+
|
|
8
|
+
def __init__(self, check_type="organization"):
|
|
9
|
+
# Ensure parent class is initialized first
|
|
10
|
+
super().__init__(check_type=check_type)
|
|
11
|
+
self.check_id = "SRA-IAA-2"
|
|
12
|
+
self.check_name = "IAM Access Analyzer Delegated Administration"
|
|
13
|
+
self.severity = "HIGH"
|
|
14
|
+
self.description = ('This check verifies whether IAA service administration for your AWS Organization is '
|
|
15
|
+
'delegated out of your AWS Organization management account. The delegated administrator '
|
|
16
|
+
'has permissions to create and manage analyzers with the AWS organization as the zone of trust.')
|
|
17
|
+
self.check_logic = ('1. Verify execution from Organization Management account | '
|
|
18
|
+
'2. Check for delegated administrator for IAA service | '
|
|
19
|
+
'3. Confirm that delegated administrator is not management account | '
|
|
20
|
+
'4. Check passes if IAA delegated administrator is not in management account')
|
|
21
|
+
self.service = 'IAM'
|
|
22
|
+
|
|
23
|
+
def run(self, session):
|
|
24
|
+
"""Run the security check"""
|
|
25
|
+
try:
|
|
26
|
+
region = session.region_name
|
|
27
|
+
account_id = session.client('sts').get_caller_identity()['Account']
|
|
28
|
+
|
|
29
|
+
# Step 1: Verify we're in management account using org_mgmt_checker
|
|
30
|
+
is_management, error_message = self.org_checker.verify_org_management()
|
|
31
|
+
if not is_management:
|
|
32
|
+
finding = {
|
|
33
|
+
'CheckId': self.check_id,
|
|
34
|
+
'Status': 'ERROR',
|
|
35
|
+
'Region': region,
|
|
36
|
+
"Severity": self.severity,
|
|
37
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
38
|
+
'Description': self.description,
|
|
39
|
+
'ResourceId': account_id,
|
|
40
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
41
|
+
'AccountId': account_id,
|
|
42
|
+
'CheckedValue': 'Management Account Access',
|
|
43
|
+
'ActualValue': error_message if error_message else 'Not running from management account',
|
|
44
|
+
'Remediation': 'Run this check from the Organization Management Account',
|
|
45
|
+
'Service': self.service,
|
|
46
|
+
'CheckLogic': self.check_logic,
|
|
47
|
+
'CheckType': self.check_type
|
|
48
|
+
}
|
|
49
|
+
self.findings.append(finding)
|
|
50
|
+
return self.findings
|
|
51
|
+
|
|
52
|
+
# Step 2: Check for delegated administrator
|
|
53
|
+
try:
|
|
54
|
+
org_client = session.client('organizations')
|
|
55
|
+
delegated_admins = org_client.list_delegated_administrators(
|
|
56
|
+
ServicePrincipal='access-analyzer.amazonaws.com'
|
|
57
|
+
).get('DelegatedAdministrators', [])
|
|
58
|
+
|
|
59
|
+
if not delegated_admins:
|
|
60
|
+
finding = {
|
|
61
|
+
'CheckId': self.check_id,
|
|
62
|
+
'Status': 'FAIL',
|
|
63
|
+
'Region': region,
|
|
64
|
+
"Severity": self.severity,
|
|
65
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
66
|
+
'Description': self.description,
|
|
67
|
+
'ResourceId': account_id,
|
|
68
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
69
|
+
'AccountId': account_id,
|
|
70
|
+
'CheckedValue': 'IAA Delegated Administrator',
|
|
71
|
+
'ActualValue': 'No delegated administrator configured',
|
|
72
|
+
'Remediation': 'Configure a member account as IAA delegated administrator',
|
|
73
|
+
'Service': self.service,
|
|
74
|
+
'CheckLogic': self.check_logic,
|
|
75
|
+
'CheckType': self.check_type
|
|
76
|
+
}
|
|
77
|
+
self.findings.append(finding)
|
|
78
|
+
return self.findings
|
|
79
|
+
|
|
80
|
+
# Step 3: Confirm delegated administrator is not management account
|
|
81
|
+
delegated_admin = delegated_admins[0]
|
|
82
|
+
if delegated_admin['Id'] == account_id:
|
|
83
|
+
finding = {
|
|
84
|
+
'CheckId': self.check_id,
|
|
85
|
+
'Status': 'FAIL',
|
|
86
|
+
'Region': region,
|
|
87
|
+
"Severity": self.severity,
|
|
88
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
89
|
+
'Description': self.description,
|
|
90
|
+
'ResourceId': account_id,
|
|
91
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
92
|
+
'AccountId': account_id,
|
|
93
|
+
'CheckedValue': 'IAA Delegated Administrator Configuration',
|
|
94
|
+
'ActualValue': f'Delegated administrator is management account: {account_id}',
|
|
95
|
+
'Remediation': 'Configure a member account (not management account) as IAA delegated administrator',
|
|
96
|
+
'Service': self.service,
|
|
97
|
+
'CheckLogic': self.check_logic,
|
|
98
|
+
'CheckType': self.check_type
|
|
99
|
+
}
|
|
100
|
+
self.findings.append(finding)
|
|
101
|
+
else:
|
|
102
|
+
# Step 4: Check passes if delegated administrator is not management account
|
|
103
|
+
finding = {
|
|
104
|
+
'CheckId': self.check_id,
|
|
105
|
+
'Status': 'PASS',
|
|
106
|
+
'Region': region,
|
|
107
|
+
"Severity": self.severity,
|
|
108
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
109
|
+
'Description': self.description,
|
|
110
|
+
'ResourceId': delegated_admin['Id'],
|
|
111
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
112
|
+
'AccountId': account_id,
|
|
113
|
+
'CheckedValue': 'IAA Delegated Administrator Configuration',
|
|
114
|
+
'ActualValue': f'Delegated administrator account: {delegated_admin["Id"]}',
|
|
115
|
+
'Remediation': 'None required',
|
|
116
|
+
'Service': self.service,
|
|
117
|
+
'CheckLogic': self.check_logic,
|
|
118
|
+
'CheckType': self.check_type
|
|
119
|
+
}
|
|
120
|
+
self.findings.append(finding)
|
|
121
|
+
|
|
122
|
+
except ClientError as e:
|
|
123
|
+
finding = {
|
|
124
|
+
'CheckId': self.check_id,
|
|
125
|
+
'Status': 'ERROR',
|
|
126
|
+
'Region': region,
|
|
127
|
+
"Severity": self.severity,
|
|
128
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
129
|
+
'Description': self.description,
|
|
130
|
+
'ResourceId': account_id,
|
|
131
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
132
|
+
'AccountId': account_id,
|
|
133
|
+
'CheckedValue': 'Delegated Administrator Access',
|
|
134
|
+
'ActualValue': f'Error checking delegated administrator: {str(e)}',
|
|
135
|
+
'Remediation': 'Verify Organizations permissions',
|
|
136
|
+
'Service': self.service,
|
|
137
|
+
'CheckLogic': self.check_logic,
|
|
138
|
+
'CheckType': self.check_type
|
|
139
|
+
}
|
|
140
|
+
self.findings.append(finding)
|
|
141
|
+
|
|
142
|
+
except Exception as e:
|
|
143
|
+
finding = {
|
|
144
|
+
'CheckId': self.check_id,
|
|
145
|
+
'Status': 'ERROR',
|
|
146
|
+
'Region': region,
|
|
147
|
+
"Severity": self.severity,
|
|
148
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
149
|
+
'Description': self.description,
|
|
150
|
+
'ResourceId': account_id,
|
|
151
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
152
|
+
'AccountId': account_id,
|
|
153
|
+
'CheckedValue': 'Check Execution',
|
|
154
|
+
'ActualValue': f'Error: {str(e)}',
|
|
155
|
+
'Remediation': 'Check logs for more details',
|
|
156
|
+
'Service': self.service,
|
|
157
|
+
'CheckLogic': self.check_logic,
|
|
158
|
+
'CheckType': self.check_type
|
|
159
|
+
}
|
|
160
|
+
self.findings.append(finding)
|
|
161
|
+
|
|
162
|
+
return self.findings
|