AnalysisType: policy
Filename: aws_cloudtrail_enabled.py
PolicyID: "AWS.CloudTrail.Enabled"
DisplayName: "AWS CloudTrail Management Events Enabled"
Enabled: true
ResourceTypes:
- AWS.CloudTrail.Meta
Tags:
- AWS
- Security Control
- Defense Evasion:Impair Defenses
Reports:
CIS:
- 2.1
PCI:
- 10.5.4
MITRE ATT&CK:
- TA0005:T1562
Severity: High
Description: >
This policy ensures that at least one CloudTrail has
management (control plane) operations logged.
Runbook: >
https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-cloudtrail-enabled-in-all-regions
Reference: >
https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html
Tests:
- Name: Global CloudTrail Is Enabled
ExpectedResult: true
Resource:
{
"GlobalEventSelectors":
[
{
"DataResources": null,
"IncludeManagementEvents": true,
"ReadWriteType": "All",
},
{
"DataResources":
[{ "Type": "AWS::S3::Object", "Values": ["arn:aws:s3"] }],
"IncludeManagementEvents": true,
"ReadWriteType": "All",
},
],
"Trails": ["trail1"],
}
- Name: CloudTrail Enabled with ReadOnly Management Events
ExpectedResult: false
Resource:
{
"GlobalEventSelectors":
[
{
"DataResources": null,
"IncludeManagementEvents": true,
"ReadWriteType": "Read",
},
],
"Trails": ["trail1"],
}
- Name: No Global CloudTrail Enabled
ExpectedResult: false
Resource: { "GlobalEventSelectors": null, "Trails": [] }
- Name: Advanced Selector With Management
ExpectedResult: true
Resource:
{
"Trails":
["arn:aws:cloudtrail:us-east-1:123456789012:trail/write_to_bucket"],
"GlobalAdvancedEventSelectors":
[
{
"Name": "Management events selector",
"FieldSelectors":
[{ "Field": "eventCategory", "Equals": ["Management"] }],
},
{
"Name": "LambdaDataEvents",
"FieldSelectors":
[
{ "Field": "eventCategory", "Equals": ["Data"] },
{
"Field": "resources.type",
"Equals": ["AWS::Lambda::Function"],
},
],
},
{
"Name": "S3DataEvents",
"FieldSelectors":
[
{ "Field": "eventCategory", "Equals": ["Data"] },
{
"Field": "eventName",
"NotEquals": ["HeadObject", "UploadPart"],
},
{ "Field": "resources.type", "Equals": ["AWS::S3::Object"] },
],
},
],
}
- Name: Advanced Selector With Management and readOnly
ExpectedResult: false
Resource:
{
"Trails":
["arn:aws:cloudtrail:us-east-1:123456789012:trail/write_to_bucket"],
"GlobalAdvancedEventSelectors":
[
{
"Name": "Management events selector",
"FieldSelectors":
[
{ "Field": "eventCategory", "Equals": ["Management"] },
{ "Field": "readOnly", "Equals": ["true"] },
],
},
{
"Name": "LambdaDataEvents",
"FieldSelectors":
[
{ "Field": "eventCategory", "Equals": ["Data"] },
{
"Field": "resources.type",
"Equals": ["AWS::Lambda::Function"],
},
],
},
{
"Name": "S3DataEvents",
"FieldSelectors":
[
{ "Field": "eventCategory", "Equals": ["Data"] },
{
"Field": "eventName",
"NotEquals": ["HeadObject", "UploadPart"],
},
{ "Field": "resources.type", "Equals": ["AWS::S3::Object"] },
],
},
],
}
- Name: None Global Selector, Valid Advanced Selector
ExpectedResult: true
Resource:
{
"AccountId": "123456789012",
"GlobalEventSelectors": null,
"GlobalAdvancedEventSelectors":
[
{
"FieldSelectors":
[
{
"EndsWith": null,
"Equals": ["Data"],
"Field": "eventCategory",
"NotEndsWith": null,
"NotEquals": null,
"NotStartsWith": null,
"StartsWith": null,
},
{
"EndsWith": null,
"Equals": null,
"Field": "eventName",
"NotEndsWith": null,
"NotEquals": ["UploadPart", "HeadObject"],
"NotStartsWith": null,
"StartsWith": null,
},
{
"EndsWith": null,
"Equals": ["AWS::S3::Object"],
"Field": "resources.type",
"NotEndsWith": null,
"NotEquals": null,
"NotStartsWith": null,
"StartsWith": null,
},
],
"Name": "S3DataEvents",
},
{
"FieldSelectors":
[
{
"EndsWith": null,
"Equals": ["Data"],
"Field": "eventCategory",
"NotEndsWith": null,
"NotEquals": null,
"NotStartsWith": null,
"StartsWith": null,
},
{
"EndsWith": null,
"Equals": ["AWS::Lambda::Function"],
"Field": "resources.type",
"NotEndsWith": null,
"NotEquals": null,
"NotStartsWith": null,
"StartsWith": null,
},
],
"Name": "LambdaDataEvents",
},
{
"FieldSelectors":
[
{
"EndsWith": null,
"Equals": ["Management"],
"Field": "eventCategory",
"NotEndsWith": null,
"NotEquals": null,
"NotStartsWith": null,
"StartsWith": null,
},
],
"Name": "Management events selector",
},
],
"Name": "AWS.CloudTrail.Meta",
"Region": "global",
"ResourceId": "123456789012::AWS.CloudTrail.Meta",
"ResourceType": "AWS.CloudTrail.Meta",
"Trails": ["arn:aws:cloudtrail:us-east-1:123456789012/bucket"],
}
# ------ paired body: aws_cloudtrail_enabled.py ------
def policy(resource):
# pylint: disable=R1260
if not resource.get("Trails"):
return False
if not any(
[resource.get("GlobalEventSelectors"), resource.get("GlobalAdvancedEventSelectors")]
):
return False
if resource.get("GlobalEventSelectors"):
for selector in resource.get("GlobalEventSelectors", [{}]):
if selector.get("IncludeManagementEvents") and selector.get("ReadWriteType") == "All":
return True
if resource.get("GlobalAdvancedEventSelectors"):
for advanced_selector in resource.get("GlobalAdvancedEventSelectors", [{}]):
management_present = False
readonly_present = False
for field_selector in advanced_selector.get("FieldSelectors", [{}]):
if field_selector.get("Field") == "eventCategory":
event_categories = field_selector.get("Equals", [])
if "Management" in event_categories:
management_present = True
if field_selector.get("Field") == "readOnly":
readonly_present = True
if all([management_present, not readonly_present]):
return True
return False