Back to Checks
aws

CloudTrail trail logs are encrypted at rest with a KMS key

cloudtrail_kms_encryption_enabled
Service: cloudtrailSeverity: medium
OfficialBuilt-inVerified
Categories:encryption
Resource Type:AwsCloudTrailTrail

AWS CloudTrail trails are evaluated for use of SSE-KMS with a customer-managed KMS key to encrypt delivered log files at rest in S3. Trails without a configured KMS key are identified. Applies to single-Region and multi-Region trails.

Risk

Absent a customer-managed KMS key, log protection relies only on storage permissions. Bucket misconfigurations or stolen credentials can expose audit data, aiding evasion and lateral movement. Missing key-level controls, rotation, and usage audit weaken confidentiality and forensic integrity.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks cloudtrail_kms_encryption_enabled

Recommendation

Enable SSE-KMS on every trail using a customer-managed KMS key. Apply least privilege so only authorized roles can Decrypt, and enforce separation of duties between key admins and log readers. Rotate keys and monitor key usage to provide defense in depth for CloudTrail data.

Remediation

CLI

aws cloudtrail update-trail --name <trail_name> --kms-key-id <kms_key_arn_or_id>

Terraform

# Enable KMS encryption for CloudTrail
resource "aws_cloudtrail" "<example_resource_name>" {
  name           = "<example_resource_name>"
  s3_bucket_name = "<example_resource_name>"
  kms_key_id     = "<example_resource_id>" # Critical: uses this KMS key to encrypt CloudTrail logs
}

NativeIaC

# CloudFormation: enable KMS encryption for an existing/new CloudTrail
Resources:
  <example_resource_name>:
    Type: AWS::CloudTrail::Trail
    Properties:
      S3BucketName: <example_resource_name>
      KmsKeyId: <example_resource_id>  # Critical: sets the KMS key to encrypt CloudTrail logs at rest

Other

1In the AWS Console, go to CloudTrail > Trails
2Select the trail <trail_name>, click Edit
3Under Log file encryption, choose Use a KMS key and select <cloudtrail_kms_key>
4Click Save changes

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.cloudtrail.cloudtrail_client import (
    cloudtrail_client,
)


class cloudtrail_kms_encryption_enabled(Check):
    def execute(self):
        findings = []
        if cloudtrail_client.trails is not None:
            for trail in cloudtrail_client.trails.values():
                if trail.name:
                    report = Check_Report_AWS(metadata=self.metadata(), resource=trail)
                    report.region = trail.home_region
                    report.status = "FAIL"
                    if trail.is_multiregion:
                        report.status_extended = (
                            f"Multiregion trail {trail.name} has encryption disabled."
                        )
                    else:
                        report.status_extended = (
                            f"Single region trail {trail.name} has encryption disabled."
                        )
                    if trail.kms_key:
                        report.status = "PASS"
                        if trail.is_multiregion:
                            report.status_extended = f"Multiregion trail {trail.name} has encryption enabled."
                        else:
                            report.status_extended = f"Single region trail {trail.name} has encryption enabled."
                    findings.append(report)

        return findings