AWS CloudTrail Management Events Enabled


Description

This policy ensures that at least one CloudTrail has management (control plane) operations logged.

Query · python

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

Analyst notes

https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-cloudtrail-enabled-in-all-regions

Raw source AWS CloudTrail Management Events Enabled · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
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

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.