complio 0.1.1__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.
- CHANGELOG.md +208 -0
- README.md +343 -0
- complio/__init__.py +48 -0
- complio/cli/__init__.py +0 -0
- complio/cli/banner.py +87 -0
- complio/cli/commands/__init__.py +0 -0
- complio/cli/commands/history.py +439 -0
- complio/cli/commands/scan.py +700 -0
- complio/cli/main.py +115 -0
- complio/cli/output.py +338 -0
- complio/config/__init__.py +17 -0
- complio/config/settings.py +333 -0
- complio/connectors/__init__.py +9 -0
- complio/connectors/aws/__init__.py +0 -0
- complio/connectors/aws/client.py +342 -0
- complio/connectors/base.py +135 -0
- complio/core/__init__.py +10 -0
- complio/core/registry.py +228 -0
- complio/core/runner.py +351 -0
- complio/py.typed +0 -0
- complio/reporters/__init__.py +7 -0
- complio/reporters/generator.py +417 -0
- complio/tests_library/__init__.py +0 -0
- complio/tests_library/base.py +492 -0
- complio/tests_library/identity/__init__.py +0 -0
- complio/tests_library/identity/access_key_rotation.py +302 -0
- complio/tests_library/identity/mfa_enforcement.py +327 -0
- complio/tests_library/identity/root_account_protection.py +470 -0
- complio/tests_library/infrastructure/__init__.py +0 -0
- complio/tests_library/infrastructure/cloudtrail_encryption.py +286 -0
- complio/tests_library/infrastructure/cloudtrail_log_validation.py +274 -0
- complio/tests_library/infrastructure/cloudtrail_logging.py +400 -0
- complio/tests_library/infrastructure/ebs_encryption.py +244 -0
- complio/tests_library/infrastructure/ec2_security_groups.py +321 -0
- complio/tests_library/infrastructure/iam_password_policy.py +460 -0
- complio/tests_library/infrastructure/nacl_security.py +356 -0
- complio/tests_library/infrastructure/rds_encryption.py +252 -0
- complio/tests_library/infrastructure/s3_encryption.py +301 -0
- complio/tests_library/infrastructure/s3_public_access.py +369 -0
- complio/tests_library/infrastructure/secrets_manager_encryption.py +248 -0
- complio/tests_library/infrastructure/vpc_flow_logs.py +287 -0
- complio/tests_library/logging/__init__.py +0 -0
- complio/tests_library/logging/cloudwatch_alarms.py +354 -0
- complio/tests_library/logging/cloudwatch_logs_encryption.py +281 -0
- complio/tests_library/logging/cloudwatch_retention.py +252 -0
- complio/tests_library/logging/config_enabled.py +393 -0
- complio/tests_library/logging/eventbridge_rules.py +460 -0
- complio/tests_library/logging/guardduty_enabled.py +436 -0
- complio/tests_library/logging/security_hub_enabled.py +416 -0
- complio/tests_library/logging/sns_encryption.py +273 -0
- complio/tests_library/network/__init__.py +0 -0
- complio/tests_library/network/alb_nlb_security.py +421 -0
- complio/tests_library/network/api_gateway_security.py +452 -0
- complio/tests_library/network/cloudfront_https.py +332 -0
- complio/tests_library/network/direct_connect_security.py +343 -0
- complio/tests_library/network/nacl_configuration.py +367 -0
- complio/tests_library/network/network_firewall.py +355 -0
- complio/tests_library/network/transit_gateway_security.py +318 -0
- complio/tests_library/network/vpc_endpoints_security.py +339 -0
- complio/tests_library/network/vpn_security.py +333 -0
- complio/tests_library/network/waf_configuration.py +428 -0
- complio/tests_library/security/__init__.py +0 -0
- complio/tests_library/security/kms_key_rotation.py +314 -0
- complio/tests_library/storage/__init__.py +0 -0
- complio/tests_library/storage/backup_encryption.py +288 -0
- complio/tests_library/storage/dynamodb_encryption.py +280 -0
- complio/tests_library/storage/efs_encryption.py +257 -0
- complio/tests_library/storage/elasticache_encryption.py +370 -0
- complio/tests_library/storage/redshift_encryption.py +252 -0
- complio/tests_library/storage/s3_versioning.py +264 -0
- complio/utils/__init__.py +26 -0
- complio/utils/errors.py +179 -0
- complio/utils/exceptions.py +151 -0
- complio/utils/history.py +243 -0
- complio/utils/logger.py +391 -0
- complio-0.1.1.dist-info/METADATA +385 -0
- complio-0.1.1.dist-info/RECORD +79 -0
- complio-0.1.1.dist-info/WHEEL +4 -0
- complio-0.1.1.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AWS EventBridge security monitoring rules compliance test.
|
|
3
|
+
|
|
4
|
+
Checks that EventBridge rules are configured for critical security events.
|
|
5
|
+
|
|
6
|
+
ISO 27001 Control: A.8.16 - Monitoring activities
|
|
7
|
+
Requirement: EventBridge rules should monitor critical security events
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
>>> from complio.connectors.aws.client import AWSConnector
|
|
11
|
+
>>> from complio.tests_library.logging.eventbridge_rules import EventBridgeRulesTest
|
|
12
|
+
>>>
|
|
13
|
+
>>> connector = AWSConnector("production", "us-east-1")
|
|
14
|
+
>>> connector.connect()
|
|
15
|
+
>>>
|
|
16
|
+
>>> test = EventBridgeRulesTest(connector)
|
|
17
|
+
>>> result = test.run()
|
|
18
|
+
>>> print(f"Passed: {result.passed}, Score: {result.score}")
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from typing import Any, Dict, List
|
|
22
|
+
|
|
23
|
+
from botocore.exceptions import ClientError
|
|
24
|
+
|
|
25
|
+
from complio.connectors.aws.client import AWSConnector
|
|
26
|
+
from complio.tests_library.base import (
|
|
27
|
+
ComplianceTest,
|
|
28
|
+
Severity,
|
|
29
|
+
TestResult,
|
|
30
|
+
TestStatus,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class EventBridgeRulesTest(ComplianceTest):
|
|
35
|
+
"""Test for EventBridge security monitoring rules compliance.
|
|
36
|
+
|
|
37
|
+
Verifies that EventBridge rules are configured for critical security events:
|
|
38
|
+
- Rules for GuardDuty findings
|
|
39
|
+
- Rules for Security Hub findings
|
|
40
|
+
- Rules for AWS Config compliance changes
|
|
41
|
+
- Rules for CloudTrail security events
|
|
42
|
+
- Rules should have targets configured (SNS, Lambda, etc.)
|
|
43
|
+
- Rules should be enabled (not disabled)
|
|
44
|
+
|
|
45
|
+
Compliance Requirements:
|
|
46
|
+
- EventBridge rules for critical security services
|
|
47
|
+
- Rules have targets for notifications/remediation
|
|
48
|
+
- Rules are enabled and active
|
|
49
|
+
- Coverage for major security event sources
|
|
50
|
+
|
|
51
|
+
Scoring:
|
|
52
|
+
- Based on presence of security monitoring rules
|
|
53
|
+
- Checks for key event patterns
|
|
54
|
+
- Validates targets are configured
|
|
55
|
+
|
|
56
|
+
Example:
|
|
57
|
+
>>> test = EventBridgeRulesTest(connector)
|
|
58
|
+
>>> result = test.execute()
|
|
59
|
+
>>> for finding in result.findings:
|
|
60
|
+
... print(f"{finding.resource_id}: {finding.title}")
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# Critical security event sources to monitor
|
|
64
|
+
CRITICAL_EVENT_SOURCES = {
|
|
65
|
+
"aws.guardduty": "GuardDuty threat detection findings",
|
|
66
|
+
"aws.securityhub": "Security Hub aggregated findings",
|
|
67
|
+
"aws.config": "AWS Config compliance changes",
|
|
68
|
+
"aws.health": "AWS Health security events",
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
def __init__(self, connector: AWSConnector) -> None:
|
|
72
|
+
"""Initialize EventBridge rules test.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
connector: AWS connector instance
|
|
76
|
+
"""
|
|
77
|
+
super().__init__(
|
|
78
|
+
test_id="eventbridge_rules",
|
|
79
|
+
test_name="EventBridge Security Rules Check",
|
|
80
|
+
description="Verify EventBridge rules are configured for critical security events",
|
|
81
|
+
control_id="A.8.16",
|
|
82
|
+
connector=connector,
|
|
83
|
+
scope="regional",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def _check_rule_event_pattern(self, event_pattern: str, source: str) -> bool:
|
|
87
|
+
"""Check if event pattern matches a security event source.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
event_pattern: JSON event pattern string
|
|
91
|
+
source: Event source to check for
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
True if pattern includes the source
|
|
95
|
+
"""
|
|
96
|
+
if not event_pattern:
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
import json
|
|
101
|
+
pattern = json.loads(event_pattern)
|
|
102
|
+
|
|
103
|
+
# Check if source is in the pattern
|
|
104
|
+
pattern_sources = pattern.get("source", [])
|
|
105
|
+
if isinstance(pattern_sources, str):
|
|
106
|
+
pattern_sources = [pattern_sources]
|
|
107
|
+
|
|
108
|
+
return source in pattern_sources
|
|
109
|
+
|
|
110
|
+
except (json.JSONDecodeError, TypeError):
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
def execute(self) -> TestResult:
|
|
114
|
+
"""Execute EventBridge security rules compliance test.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
TestResult with findings for missing or misconfigured rules
|
|
118
|
+
|
|
119
|
+
Example:
|
|
120
|
+
>>> test = EventBridgeRulesTest(connector)
|
|
121
|
+
>>> result = test.execute()
|
|
122
|
+
>>> print(result.score)
|
|
123
|
+
75.0
|
|
124
|
+
"""
|
|
125
|
+
result = TestResult(
|
|
126
|
+
test_id=self.test_id,
|
|
127
|
+
test_name=self.test_name,
|
|
128
|
+
status=TestStatus.PASSED,
|
|
129
|
+
passed=True,
|
|
130
|
+
score=100.0,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
# Get EventBridge client
|
|
135
|
+
events_client = self.connector.get_client("events")
|
|
136
|
+
|
|
137
|
+
# List all EventBridge rules
|
|
138
|
+
self.logger.info("listing_eventbridge_rules")
|
|
139
|
+
rules = []
|
|
140
|
+
|
|
141
|
+
paginator = events_client.get_paginator("list_rules")
|
|
142
|
+
for page in paginator.paginate():
|
|
143
|
+
rules.extend(page.get("Rules", []))
|
|
144
|
+
|
|
145
|
+
self.logger.info("eventbridge_rules_found", count=len(rules))
|
|
146
|
+
|
|
147
|
+
# Track which critical event sources have rules
|
|
148
|
+
sources_covered = {}
|
|
149
|
+
for source in self.CRITICAL_EVENT_SOURCES.keys():
|
|
150
|
+
sources_covered[source] = {
|
|
151
|
+
"has_rule": False,
|
|
152
|
+
"rules": [],
|
|
153
|
+
"has_targets": False
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# Check each rule
|
|
157
|
+
for rule in rules:
|
|
158
|
+
rule_name = rule.get("Name", "")
|
|
159
|
+
rule_arn = rule.get("Arn", "")
|
|
160
|
+
rule_state = rule.get("State", "DISABLED")
|
|
161
|
+
event_pattern = rule.get("EventPattern", "")
|
|
162
|
+
|
|
163
|
+
result.resources_scanned += 1
|
|
164
|
+
|
|
165
|
+
# Check if rule is enabled
|
|
166
|
+
if rule_state != "ENABLED":
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
# Check if rule monitors critical security events
|
|
170
|
+
for source in self.CRITICAL_EVENT_SOURCES.keys():
|
|
171
|
+
if self._check_rule_event_pattern(event_pattern, source):
|
|
172
|
+
sources_covered[source]["has_rule"] = True
|
|
173
|
+
sources_covered[source]["rules"].append(rule_name)
|
|
174
|
+
|
|
175
|
+
# Check if rule has targets
|
|
176
|
+
try:
|
|
177
|
+
targets_response = events_client.list_targets_by_rule(Rule=rule_name)
|
|
178
|
+
targets = targets_response.get("Targets", [])
|
|
179
|
+
|
|
180
|
+
if len(targets) > 0:
|
|
181
|
+
sources_covered[source]["has_targets"] = True
|
|
182
|
+
|
|
183
|
+
except ClientError as e:
|
|
184
|
+
self.logger.warning("error_checking_targets", rule=rule_name, error=str(e))
|
|
185
|
+
|
|
186
|
+
# Analyze coverage
|
|
187
|
+
issues = []
|
|
188
|
+
severity = Severity.MEDIUM
|
|
189
|
+
score_points = 0
|
|
190
|
+
|
|
191
|
+
# Calculate score based on coverage of critical sources
|
|
192
|
+
points_per_source = 100 / len(self.CRITICAL_EVENT_SOURCES)
|
|
193
|
+
|
|
194
|
+
for source, info in sources_covered.items():
|
|
195
|
+
source_name = self.CRITICAL_EVENT_SOURCES[source]
|
|
196
|
+
|
|
197
|
+
if info["has_rule"] and info["has_targets"]:
|
|
198
|
+
# Full coverage for this source
|
|
199
|
+
score_points += points_per_source
|
|
200
|
+
self.logger.debug(
|
|
201
|
+
"event_source_covered",
|
|
202
|
+
source=source,
|
|
203
|
+
rules=info["rules"]
|
|
204
|
+
)
|
|
205
|
+
elif info["has_rule"]:
|
|
206
|
+
# Rule exists but no targets
|
|
207
|
+
score_points += points_per_source * 0.5
|
|
208
|
+
issues.append(f"{source_name} has rules but no targets configured")
|
|
209
|
+
else:
|
|
210
|
+
# No rule for this source
|
|
211
|
+
issues.append(f"No EventBridge rule for {source_name}")
|
|
212
|
+
if source in ["aws.guardduty", "aws.securityhub"]:
|
|
213
|
+
severity = Severity.HIGH
|
|
214
|
+
|
|
215
|
+
# If no rules at all, this is more serious
|
|
216
|
+
if len(rules) == 0:
|
|
217
|
+
issues.insert(0, "No EventBridge rules configured")
|
|
218
|
+
severity = Severity.HIGH
|
|
219
|
+
score_points = 0
|
|
220
|
+
|
|
221
|
+
# Create evidence
|
|
222
|
+
evidence = self.create_evidence(
|
|
223
|
+
resource_id="eventbridge-security-rules",
|
|
224
|
+
resource_type="eventbridge_rules",
|
|
225
|
+
data={
|
|
226
|
+
"total_rules": len(rules),
|
|
227
|
+
"sources_coverage": sources_covered,
|
|
228
|
+
"has_issues": len(issues) > 0,
|
|
229
|
+
"issues": issues,
|
|
230
|
+
"security_score": score_points,
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
result.add_evidence(evidence)
|
|
234
|
+
|
|
235
|
+
if len(issues) > 0:
|
|
236
|
+
# Create finding for EventBridge rules issues
|
|
237
|
+
finding = self.create_finding(
|
|
238
|
+
resource_id="eventbridge-security-rules",
|
|
239
|
+
resource_type="eventbridge_rules",
|
|
240
|
+
severity=severity,
|
|
241
|
+
title="EventBridge security monitoring rules incomplete",
|
|
242
|
+
description=f"EventBridge security monitoring rules have coverage gaps: {'; '.join(issues)}. "
|
|
243
|
+
"EventBridge rules should be configured to monitor critical security events from "
|
|
244
|
+
"GuardDuty, Security Hub, Config, and other security services for timely "
|
|
245
|
+
"detection and response. ISO 27001 A.8.16 requires monitoring and alerting for "
|
|
246
|
+
"security events.",
|
|
247
|
+
remediation=(
|
|
248
|
+
"Configure EventBridge rules for security monitoring:\n\n"
|
|
249
|
+
"1. Create rule for GuardDuty findings:\n"
|
|
250
|
+
"aws events put-rule \\\n"
|
|
251
|
+
" --name guardduty-high-severity \\\n"
|
|
252
|
+
" --description 'Alert on high severity GuardDuty findings' \\\n"
|
|
253
|
+
" --event-pattern '{\n"
|
|
254
|
+
' "source": ["aws.guardduty"],\n'
|
|
255
|
+
' "detail-type": ["GuardDuty Finding"],\n'
|
|
256
|
+
' "detail": {\n'
|
|
257
|
+
' "severity": [7, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9]\n'
|
|
258
|
+
' }\n'
|
|
259
|
+
" }' \\\n"
|
|
260
|
+
" --state ENABLED\n\n"
|
|
261
|
+
"# Add SNS target\n"
|
|
262
|
+
"aws events put-targets \\\n"
|
|
263
|
+
" --rule guardduty-high-severity \\\n"
|
|
264
|
+
" --targets Id=1,Arn=arn:aws:sns:REGION:ACCOUNT:security-alerts\n\n"
|
|
265
|
+
"2. Create rule for Security Hub findings:\n"
|
|
266
|
+
"aws events put-rule \\\n"
|
|
267
|
+
" --name securityhub-critical-findings \\\n"
|
|
268
|
+
" --description 'Alert on critical Security Hub findings' \\\n"
|
|
269
|
+
" --event-pattern '{\n"
|
|
270
|
+
' "source": ["aws.securityhub"],\n'
|
|
271
|
+
' "detail-type": ["Security Hub Findings - Imported"],\n'
|
|
272
|
+
' "detail": {\n'
|
|
273
|
+
' "findings": {\n'
|
|
274
|
+
' "Severity": {\n'
|
|
275
|
+
' "Label": ["CRITICAL", "HIGH"]\n'
|
|
276
|
+
' }\n'
|
|
277
|
+
' }\n'
|
|
278
|
+
' }\n'
|
|
279
|
+
" }' \\\n"
|
|
280
|
+
" --state ENABLED\n\n"
|
|
281
|
+
"# Add SNS target\n"
|
|
282
|
+
"aws events put-targets \\\n"
|
|
283
|
+
" --rule securityhub-critical-findings \\\n"
|
|
284
|
+
" --targets Id=1,Arn=arn:aws:sns:REGION:ACCOUNT:security-alerts\n\n"
|
|
285
|
+
"3. Create rule for Config compliance changes:\n"
|
|
286
|
+
"aws events put-rule \\\n"
|
|
287
|
+
" --name config-compliance-changes \\\n"
|
|
288
|
+
" --description 'Alert on Config compliance changes' \\\n"
|
|
289
|
+
" --event-pattern '{\n"
|
|
290
|
+
' "source": ["aws.config"],\n'
|
|
291
|
+
' "detail-type": ["Config Rules Compliance Change"],\n'
|
|
292
|
+
' "detail": {\n'
|
|
293
|
+
' "newEvaluationResult": {\n'
|
|
294
|
+
' "complianceType": ["NON_COMPLIANT"]\n'
|
|
295
|
+
' }\n'
|
|
296
|
+
' }\n'
|
|
297
|
+
" }' \\\n"
|
|
298
|
+
" --state ENABLED\n\n"
|
|
299
|
+
"# Add SNS target\n"
|
|
300
|
+
"aws events put-targets \\\n"
|
|
301
|
+
" --rule config-compliance-changes \\\n"
|
|
302
|
+
" --targets Id=1,Arn=arn:aws:sns:REGION:ACCOUNT:compliance-alerts\n\n"
|
|
303
|
+
"4. Create rule for AWS Health events:\n"
|
|
304
|
+
"aws events put-rule \\\n"
|
|
305
|
+
" --name health-security-events \\\n"
|
|
306
|
+
" --description 'Alert on AWS Health security events' \\\n"
|
|
307
|
+
" --event-pattern '{\n"
|
|
308
|
+
' "source": ["aws.health"],\n'
|
|
309
|
+
' "detail-type": ["AWS Health Event"],\n'
|
|
310
|
+
' "detail": {\n'
|
|
311
|
+
' "service": ["SECURITY"],\n'
|
|
312
|
+
' "eventTypeCategory": ["issue", "accountNotification"]\n'
|
|
313
|
+
' }\n'
|
|
314
|
+
" }' \\\n"
|
|
315
|
+
" --state ENABLED\n\n"
|
|
316
|
+
"# Add SNS target\n"
|
|
317
|
+
"aws events put-targets \\\n"
|
|
318
|
+
" --rule health-security-events \\\n"
|
|
319
|
+
" --targets Id=1,Arn=arn:aws:sns:REGION:ACCOUNT:security-alerts\n\n"
|
|
320
|
+
"Or use AWS Console:\n"
|
|
321
|
+
"1. Go to Amazon EventBridge console\n"
|
|
322
|
+
"2. Click 'Rules' → 'Create rule'\n"
|
|
323
|
+
"3. Configure rule:\n"
|
|
324
|
+
" - Name: guardduty-high-severity\n"
|
|
325
|
+
" - Event bus: default\n"
|
|
326
|
+
" - Rule type: Rule with an event pattern\n"
|
|
327
|
+
"4. Build event pattern:\n"
|
|
328
|
+
" - Event source: AWS events\n"
|
|
329
|
+
" - Service: GuardDuty\n"
|
|
330
|
+
" - Event type: GuardDuty Finding\n"
|
|
331
|
+
" - Add condition: severity >= 7.0\n"
|
|
332
|
+
"5. Select targets:\n"
|
|
333
|
+
" - SNS topic (for notifications)\n"
|
|
334
|
+
" - Lambda function (for automated response)\n"
|
|
335
|
+
" - Step Functions (for workflows)\n"
|
|
336
|
+
"6. Click 'Create'\n"
|
|
337
|
+
"7. Repeat for other security services\n\n"
|
|
338
|
+
"Recommended target types:\n"
|
|
339
|
+
"SNS Topics:\n"
|
|
340
|
+
"- Email notifications to security team\n"
|
|
341
|
+
"- SMS for critical alerts\n"
|
|
342
|
+
"- Integration with PagerDuty/Slack\n\n"
|
|
343
|
+
"Lambda Functions:\n"
|
|
344
|
+
"- Automated remediation\n"
|
|
345
|
+
"- Ticket creation in JIRA/ServiceNow\n"
|
|
346
|
+
"- Custom notification formatting\n\n"
|
|
347
|
+
"SQS Queues:\n"
|
|
348
|
+
"- Buffering for processing\n"
|
|
349
|
+
"- Integration with external systems\n\n"
|
|
350
|
+
"Step Functions:\n"
|
|
351
|
+
"- Complex remediation workflows\n"
|
|
352
|
+
"- Approval processes\n\n"
|
|
353
|
+
"Best practices:\n"
|
|
354
|
+
"- Use descriptive rule names\n"
|
|
355
|
+
"- Filter events by severity\n"
|
|
356
|
+
"- Configure multiple targets for redundancy\n"
|
|
357
|
+
"- Test rules with sample events\n"
|
|
358
|
+
"- Monitor rule invocation metrics\n"
|
|
359
|
+
"- Use dead-letter queues for failed invocations\n"
|
|
360
|
+
"- Document response procedures\n"
|
|
361
|
+
"- Regularly review and update rules\n"
|
|
362
|
+
"- Use tags for rule organization\n"
|
|
363
|
+
"- Implement rate limiting for high-volume events\n\n"
|
|
364
|
+
"Additional security event patterns:\n"
|
|
365
|
+
"Root account usage:\n"
|
|
366
|
+
'{"source": ["aws.signin"], "detail": {"userIdentity": {"type": ["Root"]}}}\n\n'
|
|
367
|
+
"Console sign-in failures:\n"
|
|
368
|
+
'{"source": ["aws.signin"], "detail": {"eventName": ["ConsoleLogin"], "errorCode": ["Failed"]}}\n\n'
|
|
369
|
+
"S3 bucket policy changes:\n"
|
|
370
|
+
'{"source": ["aws.s3"], "detail": {"eventName": ["PutBucketPolicy", "DeleteBucketPolicy"]}}\n\n'
|
|
371
|
+
"IAM policy changes:\n"
|
|
372
|
+
'{"source": ["aws.iam"], "detail": {"eventName": ["CreatePolicy", "DeletePolicy", "AttachUserPolicy"]}}\n\n'
|
|
373
|
+
"Security group changes:\n"
|
|
374
|
+
'{"source": ["aws.ec2"], "detail": {"eventName": ["AuthorizeSecurityGroupIngress", "RevokeSecurityGroupIngress"]}}'
|
|
375
|
+
),
|
|
376
|
+
evidence=evidence
|
|
377
|
+
)
|
|
378
|
+
result.add_finding(finding)
|
|
379
|
+
|
|
380
|
+
result.score = score_points
|
|
381
|
+
result.passed = score_points >= 70 # Require 70% coverage for pass
|
|
382
|
+
result.status = TestStatus.PASSED if result.passed else TestStatus.FAILED
|
|
383
|
+
|
|
384
|
+
self.logger.warning(
|
|
385
|
+
"eventbridge_rules_incomplete",
|
|
386
|
+
issues=issues,
|
|
387
|
+
score=score_points
|
|
388
|
+
)
|
|
389
|
+
else:
|
|
390
|
+
# All critical event sources have rules with targets
|
|
391
|
+
result.score = 100.0
|
|
392
|
+
result.passed = True
|
|
393
|
+
result.status = TestStatus.PASSED
|
|
394
|
+
|
|
395
|
+
self.logger.info(
|
|
396
|
+
"eventbridge_rules_complete",
|
|
397
|
+
total_rules=len(rules)
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
# Add metadata
|
|
401
|
+
result.metadata = {
|
|
402
|
+
"total_rules": len(rules),
|
|
403
|
+
"critical_sources": len(self.CRITICAL_EVENT_SOURCES),
|
|
404
|
+
"sources_covered": sum(1 for s in sources_covered.values() if s["has_rule"] and s["has_targets"]),
|
|
405
|
+
"sources_partial": sum(1 for s in sources_covered.values() if s["has_rule"] and not s["has_targets"]),
|
|
406
|
+
"sources_missing": sum(1 for s in sources_covered.values() if not s["has_rule"]),
|
|
407
|
+
"security_score": score_points,
|
|
408
|
+
"compliance_percentage": result.score,
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
self.logger.info(
|
|
412
|
+
"eventbridge_rules_test_completed",
|
|
413
|
+
total_rules=len(rules),
|
|
414
|
+
score=result.score,
|
|
415
|
+
passed=result.passed
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
except ClientError as e:
|
|
419
|
+
error_code = e.response.get("Error", {}).get("Code")
|
|
420
|
+
self.logger.error("eventbridge_rules_test_error", error_code=error_code, error=str(e))
|
|
421
|
+
result.status = TestStatus.ERROR
|
|
422
|
+
result.passed = False
|
|
423
|
+
result.score = 0.0
|
|
424
|
+
result.error_message = f"AWS API Error: {error_code} - {str(e)}"
|
|
425
|
+
|
|
426
|
+
except Exception as e:
|
|
427
|
+
self.logger.error("eventbridge_rules_test_error", error=str(e))
|
|
428
|
+
result.status = TestStatus.ERROR
|
|
429
|
+
result.passed = False
|
|
430
|
+
result.score = 0.0
|
|
431
|
+
result.error_message = str(e)
|
|
432
|
+
|
|
433
|
+
return result
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
# ============================================================================
|
|
437
|
+
# CONVENIENCE FUNCTION
|
|
438
|
+
# ============================================================================
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def run_eventbridge_rules_test(connector: AWSConnector) -> TestResult:
|
|
442
|
+
"""Run EventBridge security rules compliance test.
|
|
443
|
+
|
|
444
|
+
Convenience function for running the test.
|
|
445
|
+
|
|
446
|
+
Args:
|
|
447
|
+
connector: AWS connector
|
|
448
|
+
|
|
449
|
+
Returns:
|
|
450
|
+
TestResult
|
|
451
|
+
|
|
452
|
+
Example:
|
|
453
|
+
>>> from complio.connectors.aws.client import AWSConnector
|
|
454
|
+
>>> connector = AWSConnector("production", "us-east-1")
|
|
455
|
+
>>> connector.connect()
|
|
456
|
+
>>> result = run_eventbridge_rules_test(connector)
|
|
457
|
+
>>> print(f"Score: {result.score}%")
|
|
458
|
+
"""
|
|
459
|
+
test = EventBridgeRulesTest(connector)
|
|
460
|
+
return test.execute()
|