CloudTrail KMS Encryption Enabled
Overview
This check verifies that your AWS CloudTrail trails use SSE-KMS encryption with customer-managed keys for log files stored in S3. By default, CloudTrail encrypts logs with Amazon S3-managed keys (SSE-S3), but using your own KMS key gives you more control over who can read your audit logs.
Risk
Without customer-managed KMS encryption, your CloudTrail logs rely solely on S3 bucket permissions for protection. This creates security gaps:
- Weaker access control: Anyone with S3 read permissions can view logs, even if they should not have audit access
- No key-level auditing: You cannot track who decrypted or accessed log files through KMS
- Limited separation of duties: Bucket administrators automatically have log access
- Reduced forensic integrity: Compromised credentials or bucket misconfigurations could expose sensitive API activity
- Compliance gaps: Many frameworks (CIS, PCI-DSS, HIPAA) recommend or require customer-managed encryption keys
Remediation Steps
Prerequisites
You need:
- AWS Console access with permissions to modify CloudTrail and create/manage KMS keys
- An existing CloudTrail trail (or permission to create one)
Required IAM permissions (for administrators)
Your IAM user or role needs these permissions:
cloudtrail:UpdateTrailcloudtrail:DescribeTrailskms:CreateKeykms:CreateAliaskms:DescribeKeykms:PutKeyPolicykms:ListKeys
AWS Console Method
Step 1: Create a KMS Key (if you do not have one)
-
Open KMS in the AWS Console
- Go to KMS Console in us-east-1
-
Create a new key
- Click Customer managed keys in the left sidebar
- Click Create key
- Choose Symmetric for key type
- Choose Encrypt and decrypt for key usage
- Click Next
-
Add labels
- Enter an alias like
cloudtrail-encryption-key - Add a description like "KMS key for CloudTrail log encryption"
- Click Next
- Enter an alias like
-
Define key administrators
- Select the IAM users or roles who can manage (but not use) this key
- Click Next
-
Define key usage permissions
- Select the IAM users or roles who can use this key to encrypt/decrypt
- Click Next
-
Review and add CloudTrail permissions
- Before clicking Finish, you need to add CloudTrail service permissions to the key policy
- In the key policy JSON, add this statement to the
Statementarray:
{
"Sid": "Allow CloudTrail to encrypt logs",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": [
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringLike": {
"kms:EncryptionContext:aws:cloudtrail:arn": "arn:aws:cloudtrail:*:<your-account-id>:trail/*"
}
}
}- Replace
<your-account-id>with your 12-digit AWS account ID - Click Finish
Step 2: Enable KMS Encryption on Your Trail
-
Open CloudTrail in the AWS Console
- Go to CloudTrail Console in us-east-1
-
Select your trail
- Click Trails in the left sidebar
- Click on the trail name you want to configure
-
Edit the trail
- Click Edit in the General details section
-
Enable SSE-KMS encryption
- Scroll to Log file SSE-KMS encryption
- Check the box for Enabled
- Under Customer managed AWS KMS key, choose Existing
- Select your KMS key alias (e.g.,
cloudtrail-encryption-key)
-
Save your changes
- Click Save changes
AWS CLI (optional)
Step 1: Create a KMS key with the correct policy
Create a key policy file that grants CloudTrail permission to use the key:
cat > /tmp/cloudtrail-kms-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<your-account-id>:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow CloudTrail to encrypt logs",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": [
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringLike": {
"kms:EncryptionContext:aws:cloudtrail:arn": "arn:aws:cloudtrail:*:<your-account-id>:trail/*"
}
}
},
{
"Sid": "Allow CloudTrail to describe key",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "kms:DescribeKey",
"Resource": "*"
}
]
}
EOF
Replace <your-account-id> with your 12-digit AWS account ID.
Create the KMS key:
aws kms create-key \
--description "KMS key for CloudTrail log encryption" \
--policy file:///tmp/cloudtrail-kms-policy.json \
--region us-east-1
Note the KeyId from the output.
Create an alias for easier reference:
aws kms create-alias \
--alias-name alias/cloudtrail-encryption-key \
--target-key-id <key-id> \
--region us-east-1
Step 2: Update the CloudTrail trail
aws cloudtrail update-trail \
--name <trail-name> \
--kms-key-id alias/cloudtrail-encryption-key \
--region us-east-1
CloudFormation (optional)
This template creates a KMS key with the correct policy and a CloudTrail trail that uses it:
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudTrail with KMS encryption
Parameters:
TrailName:
Type: String
Description: Name of the CloudTrail trail
Default: my-encrypted-trail
S3BucketName:
Type: String
Description: S3 bucket for CloudTrail logs
Resources:
CloudTrailKMSKey:
Type: AWS::KMS::Key
Properties:
Description: KMS key for CloudTrail log encryption
EnableKeyRotation: true
KeyPolicy:
Version: '2012-10-17'
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action: kms:*
Resource: '*'
- Sid: Allow CloudTrail to encrypt logs
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action:
- kms:GenerateDataKey*
- kms:DescribeKey
Resource: '*'
Condition:
StringLike:
kms:EncryptionContext:aws:cloudtrail:arn: !Sub arn:aws:cloudtrail:*:${AWS::AccountId}:trail/*
CloudTrailKMSKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: alias/cloudtrail-encryption-key
TargetKeyId: !Ref CloudTrailKMSKey
CloudTrailWithKMS:
Type: AWS::CloudTrail::Trail
Properties:
TrailName: !Ref TrailName
S3BucketName: !Ref S3BucketName
IsLogging: true
KMSKeyId: !GetAtt CloudTrailKMSKey.Arn
Outputs:
KMSKeyArn:
Description: ARN of the KMS key used for CloudTrail encryption
Value: !GetAtt CloudTrailKMSKey.Arn
TrailArn:
Description: ARN of the CloudTrail trail
Value: !GetAtt CloudTrailWithKMS.Arn
Deploy with:
aws cloudformation deploy \
--template-file cloudtrail-kms.yaml \
--stack-name cloudtrail-kms-encryption \
--parameter-overrides TrailName=my-encrypted-trail S3BucketName=my-cloudtrail-bucket \
--region us-east-1
Terraform (optional)
# Variables
variable "trail_name" {
description = "Name of the CloudTrail trail"
type = string
default = "my-encrypted-trail"
}
variable "s3_bucket_name" {
description = "S3 bucket for CloudTrail logs"
type = string
}
# Data source for current account
data "aws_caller_identity" "current" {}
# KMS key for CloudTrail encryption
resource "aws_kms_key" "cloudtrail" {
description = "KMS key for CloudTrail log encryption"
deletion_window_in_days = 30
enable_key_rotation = true
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "Enable IAM User Permissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
}
Action = "kms:*"
Resource = "*"
},
{
Sid = "Allow CloudTrail to encrypt logs"
Effect = "Allow"
Principal = {
Service = "cloudtrail.amazonaws.com"
}
Action = [
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
Resource = "*"
Condition = {
StringLike = {
"kms:EncryptionContext:aws:cloudtrail:arn" = "arn:aws:cloudtrail:*:${data.aws_caller_identity.current.account_id}:trail/*"
}
}
}
]
})
}
# KMS key alias
resource "aws_kms_alias" "cloudtrail" {
name = "alias/cloudtrail-encryption-key"
target_key_id = aws_kms_key.cloudtrail.key_id
}
# CloudTrail trail with KMS encryption
resource "aws_cloudtrail" "main" {
name = var.trail_name
s3_bucket_name = var.s3_bucket_name
kms_key_id = aws_kms_key.cloudtrail.arn
}
# Outputs
output "kms_key_arn" {
description = "ARN of the KMS key used for CloudTrail encryption"
value = aws_kms_key.cloudtrail.arn
}
output "trail_arn" {
description = "ARN of the CloudTrail trail"
value = aws_cloudtrail.main.arn
}
Deploy with:
terraform init
terraform plan -var="trail_name=my-encrypted-trail" -var="s3_bucket_name=my-cloudtrail-bucket"
terraform apply -var="trail_name=my-encrypted-trail" -var="s3_bucket_name=my-cloudtrail-bucket"
Verification
After making changes, verify KMS encryption is enabled:
-
In the AWS Console:
- Go to CloudTrail > Trails and select your trail
- In the General details section, check that Log file SSE-KMS encryption shows Enabled
- Verify the correct KMS key alias or ARN is displayed
-
Check a log file:
- Go to your S3 bucket containing CloudTrail logs
- Select any log file and view its properties
- Under Server-side encryption settings, it should show AWS KMS with your key
CLI verification commands
Check trail encryption configuration:
aws cloudtrail describe-trails \
--trail-name-list <trail-name> \
--region us-east-1 \
--query 'trailList[0].{TrailName:Name,KmsKeyId:KmsKeyId}'
The output should show your KMS key ARN in the KmsKeyId field:
{
"TrailName": "my-encrypted-trail",
"KmsKeyId": "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
}
If KmsKeyId is null or missing, KMS encryption is not enabled.
Additional Resources
- AWS Documentation: Encrypting CloudTrail Log Files with AWS KMS Keys
- AWS Documentation: Creating Keys
- AWS Documentation: Key Policies in AWS KMS
- CIS AWS Foundations Benchmark - Section 3.7
Notes
- Existing logs: Enabling KMS encryption only affects new log files. Existing logs remain encrypted with their original method (SSE-S3 or existing KMS key).
- Key policy is critical: If the KMS key policy does not grant CloudTrail permission to use the key, log delivery will fail. Always include the CloudTrail service principal in your key policy.
- Cross-account trails: If your trail delivers logs to an S3 bucket in another account, the KMS key policy must also allow the CloudTrail service in the source account.
- Key rotation: Enable automatic key rotation on your KMS key for better security. AWS rotates the key material annually while keeping the key ID the same.
- Costs: Customer-managed KMS keys incur charges ($1/month per key plus usage charges). Factor this into your cost planning.
- Log readers need decrypt permission: Users who need to read CloudTrail logs must have
kms:Decryptpermission on the KMS key, in addition to S3 read access.