mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
feat(CIS checks): Complete CIS checks (#1461)
Co-authored-by: sergargar <sergio@verica.io> Co-authored-by: Nacho Rivera <59198746+n4ch04@users.noreply.github.com> Co-authored-by: Pepe Fagoaga <pepe@verica.io>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "cloudwatch_log_metric_filter_aws_organizations_changes",
|
||||
"CheckTitle": "Ensure a log metric filter and alarm exist for AWS Organizations changes.",
|
||||
"CheckType": ["Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark"],
|
||||
"ServiceName": "cloudwatch",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:partition:cloudwatch:region:account-id:certificate/resource-id",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsCloudTrailTrail",
|
||||
"Description": "Ensure a log metric filter and alarm exist for AWS Organizations changes.",
|
||||
"Risk": "Monitoring unauthorized API calls will help reveal application errors and may reduce time to detect malicious activity.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/CloudWatchLogs/organizations-changes-alarm.html",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "It is recommended that a metric filter and alarm be established for unauthorized requests.",
|
||||
"Url": "https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudwatch-alarms-for-cloudtrail.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Logging and Monitoring",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import re
|
||||
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.cloudtrail.cloudtrail_client import cloudtrail_client
|
||||
from providers.aws.services.cloudwatch.cloudwatch_client import cloudwatch_client
|
||||
from providers.aws.services.cloudwatch.logs_client import logs_client
|
||||
|
||||
|
||||
class cloudwatch_log_metric_filter_aws_organizations_changes(Check):
|
||||
def execute(self):
|
||||
pattern = r"\$\.eventSource\s*=\s*organizations\.amazonaws\.com.+\$\.eventName\s*=\s*AcceptHandshake.+\$\.eventName\s*=\s*AttachPolicy.+\$\.eventName\s*=\s*CancelHandshake.+\$\.eventName\s*=\s*CreateAccount.+\$\.eventName\s*=\s*CreateOrganization.+\$\.eventName\s*=\s*CreateOrganizationalUnit.+\$\.eventName\s*=\s*CreatePolicy.+\$\.eventName\s*=\s*DeclineHandshake.+\$\.eventName\s*=\s*DeleteOrganization.+\$\.eventName\s*=\s*DeleteOrganizationalUnit.+\$\.eventName\s*=\s*DeletePolicy.+\$\.eventName\s*=\s*EnableAllFeatures.+\$\.eventName\s*=\s*EnablePolicyType.+\$\.eventName\s*=\s*InviteAccountToOrganization.+\$\.eventName\s*=\s*LeaveOrganization.+\$\.eventName\s*=\s*DetachPolicy.+\$\.eventName\s*=\s*DisablePolicyType.+\$\.eventName\s*=\s*MoveAccount.+\$\.eventName\s*=\s*RemoveAccountFromOrganization.+\$\.eventName\s*=\s*UpdateOrganizationalUnit.+\$\.eventName\s*=\s*UpdatePolicy"
|
||||
findings = []
|
||||
report = Check_Report(self.metadata)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
"No CloudWatch log groups found with metric filters or alarms associated."
|
||||
)
|
||||
report.region = "us-east-1"
|
||||
report.resource_id = ""
|
||||
# 1. Iterate for CloudWatch Log Group in CloudTrail trails
|
||||
log_groups = []
|
||||
for trail in cloudtrail_client.trails:
|
||||
if trail.log_group_arn:
|
||||
log_groups.append(trail.log_group_arn.split(":")[6])
|
||||
# 2. Describe metric filters for previous log groups
|
||||
for metric_filter in logs_client.metric_filters:
|
||||
if metric_filter.log_group in log_groups:
|
||||
if re.search(pattern, metric_filter.pattern):
|
||||
report.resource_id = metric_filter.log_group
|
||||
report.region = metric_filter.region
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"CloudWatch log group {metric_filter.log_group} found with metric filter {metric_filter.name} but no alarms associated."
|
||||
# 3. Check if there is an alarm for the metric
|
||||
for alarm in cloudwatch_client.metric_alarms:
|
||||
if alarm.metric == metric_filter.metric:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"CloudWatch log group {metric_filter.log_group} found with metric filter {metric_filter.name} and alarms set."
|
||||
break
|
||||
|
||||
findings.append(report)
|
||||
return findings
|
||||
@@ -0,0 +1,282 @@
|
||||
from unittest import mock
|
||||
|
||||
from boto3 import client
|
||||
from moto import mock_cloudtrail, mock_cloudwatch, mock_logs, mock_s3
|
||||
from moto.core import DEFAULT_ACCOUNT_ID
|
||||
|
||||
AWS_REGION = "us-east-1"
|
||||
|
||||
|
||||
class Test_cloudwatch_log_metric_filter_aws_organizations_changes:
|
||||
@mock_logs
|
||||
@mock_cloudtrail
|
||||
@mock_cloudwatch
|
||||
def test_cloudwatch_no_log_groups(self):
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.cloudwatch.cloudwatch_service import (
|
||||
CloudWatch,
|
||||
Logs,
|
||||
)
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
from providers.aws.services.cloudtrail.cloudtrail_client import Cloudtrail
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.logs_client",
|
||||
new=Logs(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_client",
|
||||
new=CloudWatch(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudtrail_client",
|
||||
new=Cloudtrail(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes import (
|
||||
cloudwatch_log_metric_filter_aws_organizations_changes,
|
||||
)
|
||||
|
||||
check = cloudwatch_log_metric_filter_aws_organizations_changes()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "No CloudWatch log groups found with metric filters or alarms associated."
|
||||
)
|
||||
assert result[0].resource_id == ""
|
||||
|
||||
@mock_logs
|
||||
@mock_cloudtrail
|
||||
@mock_cloudwatch
|
||||
@mock_s3
|
||||
def test_cloudwatch_trail_no_log_group(self):
|
||||
cloudtrail_client = client("cloudtrail", region_name=AWS_REGION)
|
||||
s3_client = client("s3", region_name=AWS_REGION)
|
||||
s3_client.create_bucket(Bucket="test")
|
||||
cloudtrail_client.create_trail(Name="test_trail", S3BucketName="test")
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.cloudwatch.cloudwatch_service import (
|
||||
CloudWatch,
|
||||
Logs,
|
||||
)
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
from providers.aws.services.cloudtrail.cloudtrail_client import Cloudtrail
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.logs_client",
|
||||
new=Logs(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_client",
|
||||
new=CloudWatch(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudtrail_client",
|
||||
new=Cloudtrail(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes import (
|
||||
cloudwatch_log_metric_filter_aws_organizations_changes,
|
||||
)
|
||||
|
||||
check = cloudwatch_log_metric_filter_aws_organizations_changes()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "No CloudWatch log groups found with metric filters or alarms associated."
|
||||
)
|
||||
assert result[0].resource_id == ""
|
||||
|
||||
@mock_logs
|
||||
@mock_cloudtrail
|
||||
@mock_cloudwatch
|
||||
@mock_s3
|
||||
def test_cloudwatch_trail_with_log_group(self):
|
||||
cloudtrail_client = client("cloudtrail", region_name=AWS_REGION)
|
||||
logs_client = client("logs", region_name=AWS_REGION)
|
||||
s3_client = client("s3", region_name=AWS_REGION)
|
||||
s3_client.create_bucket(Bucket="test")
|
||||
logs_client.create_log_group(logGroupName="/log-group/test")
|
||||
cloudtrail_client.create_trail(
|
||||
Name="test_trail",
|
||||
S3BucketName="test",
|
||||
CloudWatchLogsLogGroupArn=f"arn:aws:logs:{AWS_REGION}:{DEFAULT_ACCOUNT_ID}:log-group:/log-group/test:*",
|
||||
)
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.cloudwatch.cloudwatch_service import (
|
||||
CloudWatch,
|
||||
Logs,
|
||||
)
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
from providers.aws.services.cloudtrail.cloudtrail_client import Cloudtrail
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.logs_client",
|
||||
new=Logs(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_client",
|
||||
new=CloudWatch(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudtrail_client",
|
||||
new=Cloudtrail(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes import (
|
||||
cloudwatch_log_metric_filter_aws_organizations_changes,
|
||||
)
|
||||
|
||||
check = cloudwatch_log_metric_filter_aws_organizations_changes()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "No CloudWatch log groups found with metric filters or alarms associated."
|
||||
)
|
||||
assert result[0].resource_id == ""
|
||||
|
||||
@mock_logs
|
||||
@mock_cloudtrail
|
||||
@mock_cloudwatch
|
||||
@mock_s3
|
||||
def test_cloudwatch_trail_with_log_group_with_metric(self):
|
||||
cloudtrail_client = client("cloudtrail", region_name=AWS_REGION)
|
||||
logs_client = client("logs", region_name=AWS_REGION)
|
||||
s3_client = client("s3", region_name=AWS_REGION)
|
||||
s3_client.create_bucket(Bucket="test")
|
||||
logs_client.create_log_group(logGroupName="/log-group/test")
|
||||
cloudtrail_client.create_trail(
|
||||
Name="test_trail",
|
||||
S3BucketName="test",
|
||||
CloudWatchLogsLogGroupArn=f"arn:aws:logs:{AWS_REGION}:{DEFAULT_ACCOUNT_ID}:log-group:/log-group/test:*",
|
||||
)
|
||||
logs_client.put_metric_filter(
|
||||
logGroupName="/log-group/test",
|
||||
filterName="test-filter",
|
||||
filterPattern="{ ($.eventSource = organizations.amazonaws.com) && ($.eventName = AcceptHandshake) || ($.eventName = AttachPolicy) || ($.eventName = CancelHandshake) || ($.eventName = CreateAccount) || ($.eventName = CreateOrganization) || ($.eventName = CreateOrganizationalUnit) || ($.eventName = CreatePolicy) || ($.eventName = DeclineHandshake) || ($.eventName = DeleteOrganization) || ($.eventName = DeleteOrganizationalUnit) || ($.eventName = DeletePolicy) || ($.eventName = EnableAllFeatures) || ($.eventName = EnablePolicyType) || ($.eventName = InviteAccountToOrganization) || ($.eventName = LeaveOrganization) || ($.eventName = DetachPolicy) || ($.eventName = DisablePolicyType) || ($.eventName = MoveAccount) || ($.eventName = RemoveAccountFromOrganization) || ($.eventName = UpdateOrganizationalUnit) || ($.eventName = UpdatePolicy) }",
|
||||
metricTransformations=[
|
||||
{
|
||||
"metricName": "my-metric",
|
||||
"metricNamespace": "my-namespace",
|
||||
"metricValue": "$.value",
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.cloudwatch.cloudwatch_service import (
|
||||
CloudWatch,
|
||||
Logs,
|
||||
)
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
from providers.aws.services.cloudtrail.cloudtrail_client import Cloudtrail
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.logs_client",
|
||||
new=Logs(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_client",
|
||||
new=CloudWatch(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudtrail_client",
|
||||
new=Cloudtrail(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes import (
|
||||
cloudwatch_log_metric_filter_aws_organizations_changes,
|
||||
)
|
||||
|
||||
check = cloudwatch_log_metric_filter_aws_organizations_changes()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "CloudWatch log group /log-group/test found with metric filter test-filter but no alarms associated."
|
||||
)
|
||||
assert result[0].resource_id == "/log-group/test"
|
||||
|
||||
@mock_logs
|
||||
@mock_cloudtrail
|
||||
@mock_cloudwatch
|
||||
@mock_s3
|
||||
def test_cloudwatch_trail_with_log_group_with_metric_and_alarm(self):
|
||||
cloudtrail_client = client("cloudtrail", region_name=AWS_REGION)
|
||||
cloudwatch_client = client("cloudwatch", region_name=AWS_REGION)
|
||||
logs_client = client("logs", region_name=AWS_REGION)
|
||||
s3_client = client("s3", region_name=AWS_REGION)
|
||||
s3_client.create_bucket(Bucket="test")
|
||||
logs_client.create_log_group(logGroupName="/log-group/test")
|
||||
cloudtrail_client.create_trail(
|
||||
Name="test_trail",
|
||||
S3BucketName="test",
|
||||
CloudWatchLogsLogGroupArn=f"arn:aws:logs:{AWS_REGION}:{DEFAULT_ACCOUNT_ID}:log-group:/log-group/test:*",
|
||||
)
|
||||
logs_client.put_metric_filter(
|
||||
logGroupName="/log-group/test",
|
||||
filterName="test-filter",
|
||||
filterPattern="{ ($.eventSource = organizations.amazonaws.com) && ($.eventName = AcceptHandshake) || ($.eventName = AttachPolicy) || ($.eventName = CancelHandshake) || ($.eventName = CreateAccount) || ($.eventName = CreateOrganization) || ($.eventName = CreateOrganizationalUnit) || ($.eventName = CreatePolicy) || ($.eventName = DeclineHandshake) || ($.eventName = DeleteOrganization) || ($.eventName = DeleteOrganizationalUnit) || ($.eventName = DeletePolicy) || ($.eventName = EnableAllFeatures) || ($.eventName = EnablePolicyType) || ($.eventName = InviteAccountToOrganization) || ($.eventName = LeaveOrganization) || ($.eventName = DetachPolicy) || ($.eventName = DisablePolicyType) || ($.eventName = MoveAccount) || ($.eventName = RemoveAccountFromOrganization) || ($.eventName = UpdateOrganizationalUnit) || ($.eventName = UpdatePolicy) }",
|
||||
metricTransformations=[
|
||||
{
|
||||
"metricName": "my-metric",
|
||||
"metricNamespace": "my-namespace",
|
||||
"metricValue": "$.value",
|
||||
}
|
||||
],
|
||||
)
|
||||
cloudwatch_client.put_metric_alarm(
|
||||
AlarmName="test-alarm",
|
||||
MetricName="my-metric",
|
||||
Namespace="my-namespace",
|
||||
Period=10,
|
||||
EvaluationPeriods=5,
|
||||
Statistic="Average",
|
||||
Threshold=2,
|
||||
ComparisonOperator="GreaterThanThreshold",
|
||||
ActionsEnabled=True,
|
||||
)
|
||||
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.cloudwatch.cloudwatch_service import (
|
||||
CloudWatch,
|
||||
Logs,
|
||||
)
|
||||
|
||||
current_audit_info.audited_partition = "aws"
|
||||
from providers.aws.services.cloudtrail.cloudtrail_client import Cloudtrail
|
||||
|
||||
with mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.logs_client",
|
||||
new=Logs(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_client",
|
||||
new=CloudWatch(current_audit_info),
|
||||
), mock.patch(
|
||||
"providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes.cloudtrail_client",
|
||||
new=Cloudtrail(current_audit_info),
|
||||
):
|
||||
# Test Check
|
||||
from providers.aws.services.cloudwatch.cloudwatch_log_metric_filter_aws_organizations_changes.cloudwatch_log_metric_filter_aws_organizations_changes import (
|
||||
cloudwatch_log_metric_filter_aws_organizations_changes,
|
||||
)
|
||||
|
||||
check = cloudwatch_log_metric_filter_aws_organizations_changes()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "CloudWatch log group /log-group/test found with metric filter test-filter and alarms set."
|
||||
)
|
||||
assert result[0].resource_id == "/log-group/test"
|
||||
Reference in New Issue
Block a user