CloudFront distribution has Field Level Encryption enabled
CloudFront distributions have the default cache behavior associated with Field-Level Encryption via field_level_encryption_id, targeting specified request fields for edge encryption.
Risk
Absent field-level encryption, sensitive inputs (PII, payment data, credentials) may surface in origin paths, logs, or middleware in plaintext. This undermines confidentiality, enables data exfiltration and insider misuse, and can lead to session or account compromise if tokens are captured.
Run this check with Prowler
Run in Prowler Cloudprowler aws --checks cloudfront_distributions_field_level_encryption_enabledRecommendation
Enable Field-Level Encryption for sensitive request fields and bind it to relevant cache behaviors. Apply least privilege to decryption keys, rotate and monitor keys, and separate duties. As defense in depth, minimize data collection, avoid logging secrets, require HTTPS end-to-end, and validate inputs.
Remediation
CLI
aws cloudfront create-field-level-encryption-config --field-level-encryption-config file://fle-config.json && aws cloudfront get-distribution-config --id <DISTRIBUTION_ID> --output json > current-config.json && echo 'Manually edit current-config.json to add FieldLevelEncryptionId to DefaultCacheBehavior, then run:' && echo 'aws cloudfront update-distribution --id <DISTRIBUTION_ID> --distribution-config file://current-config.json --if-match $(aws cloudfront get-distribution-config --id <DISTRIBUTION_ID> --query "ETag" --output text)'Terraform
# Enable Field Level Encryption on Default Cache Behavior
resource "aws_cloudfront_field_level_encryption_config" "fle" {
content_type_profile_config {
forward_when_content_type_is_unknown = true
}
}
resource "aws_cloudfront_distribution" "<example_resource_name>" {
enabled = true
origin {
domain_name = "<example_resource_name>.s3.amazonaws.com"
origin_id = "<example_resource_id>"
}
default_cache_behavior {
target_origin_id = "<example_resource_id>"
viewer_protocol_policy = "redirect-to-https"
cache_policy_id = "658327ea-f89d-4fab-a63d-7e88639e58f6"
field_level_encryption_id = aws_cloudfront_field_level_encryption_config.fle.id # Critical: enables FLE
}
}NativeIaC
# CloudFormation: Enable Field Level Encryption on Default Cache Behavior
Resources:
FLEConfig:
Type: AWS::CloudFront::FieldLevelEncryptionConfig
Properties:
FieldLevelEncryptionConfig:
CallerReference: !Ref AWS::StackName
ContentTypeProfileConfig:
ForwardWhenContentTypeIsUnknown: true
ContentTypeProfiles:
Quantity: 0
<example_resource_name>:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Origins:
- DomainName: "<example_resource_name>.s3.amazonaws.com"
Id: "<example_resource_id>"
S3OriginConfig: {}
DefaultCacheBehavior:
TargetOriginId: "<example_resource_id>"
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
FieldLevelEncryptionId: !Ref FLEConfig # Critical: enables FLE on the default cache behaviorOther
Check Code
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.cloudfront.cloudfront_client import (
cloudfront_client,
)
class cloudfront_distributions_field_level_encryption_enabled(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
if (
distribution.default_cache_config
and distribution.default_cache_config.field_level_encryption_id
):
report.status = "PASS"
report.status_extended = f"CloudFront Distribution {distribution.id} has Field Level Encryption enabled."
else:
report.status = "FAIL"
report.status_extended = f"CloudFront Distribution {distribution.id} has Field Level Encryption disabled."
findings.append(report)
return findings