Back to Checks
aws

Amazon Bedrock model invocation logs are encrypted in the S3 bucket and KMS-encrypted in the CloudWatch log group

bedrock_model_invocation_logs_encryption_enabled
Service: bedrockSeverity: high
OfficialBuilt-inVerified
Categories:encryptionlogginggen-ai
Resource Type:AwsS3Bucket

Bedrock model invocation logs are stored in encrypted destinations: S3 buckets with bucket encryption and CloudWatch Logs groups protected by an AWS KMS key.

This evaluates whether configured log targets enforce encryption at rest for request/response content and associated metadata.

Risk

Without encryption at rest, prompts, outputs, images, and token/usage metadata in logs can be read if S3 or CloudWatch storage or replicas are accessed by unauthorized principals.

Impacts:

  • Loss of data confidentiality
  • Secret or PII exposure enabling account abuse
  • Operational intel for lateral movement

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks bedrock_model_invocation_logs_encryption_enabled

Recommendation

Ensure all invocation logs are encrypted end to end:

  • Enable S3 default encryption, preferably SSE-KMS, and restrict key usage
  • Assign a KMS key to CloudWatch log groups
  • Enforce least privilege on keys and logs, rotate keys, and monitor access for defense in depth

Remediation

Terraform

resource "aws_s3_bucket" "example" {
  bucket = "<example_resource_name>"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
  bucket = aws_s3_bucket.example.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"  # critical: enables default encryption for the S3 bucket
    }
  }
}

resource "aws_cloudwatch_log_group" "example" {
  name       = "<example_resource_name>"
  kms_key_id = "<example_kms_key_arn>"  # critical: encrypts the log group with a KMS key
}

NativeIaC

Resources:
  EncryptedLogsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: <example_resource_name>
      BucketEncryption:  # critical: enables default encryption for the bucket (SSE-S3)
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256

  EncryptedLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: <example_resource_name>
      KmsKeyId: <example_kms_key_arn>  # critical: encrypts the CloudWatch log group with a KMS key

Other

1In the Bedrock console, go to Settings and note the S3 bucket and CloudWatch log group used for Model invocation logging.
2S3 bucket: AWS Console > S3 > Buckets > <bucket> > Properties > Default encryption > Enable > Choose SSE-S3 (AES-256) > Save.
3CloudWatch Logs: AWS Console > CloudWatch > Logs > Log groups > select <log group> > Actions > Edit > KMS encryption > select <KMS key> > Save.

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.bedrock.bedrock_client import bedrock_client
from prowler.providers.aws.services.cloudwatch.logs_client import logs_client
from prowler.providers.aws.services.s3.s3_client import s3_client


class bedrock_model_invocation_logs_encryption_enabled(Check):
    def execute(self):
        findings = []
        for region, logging in bedrock_client.logging_configurations.items():
            if logging.enabled:
                s3_encryption = True
                cloudwatch_encryption = True
                report = Check_Report_AWS(metadata=self.metadata(), resource=logging)
                report.region = region
                report.resource_id = "model-invocation-logging"
                report.resource_arn = (
                    bedrock_client._get_model_invocation_logging_arn_template(region)
                )
                report.status = "PASS"
                report.status_extended = "Bedrock Model Invocation logs are encrypted."
                if logging.s3_bucket:
                    bucket_arn = (
                        f"arn:{s3_client.audited_partition}:s3:::{logging.s3_bucket}"
                    )
                    if (
                        bucket_arn in s3_client.buckets
                        and not s3_client.buckets[bucket_arn].encryption
                    ):
                        s3_encryption = False
                if logging.cloudwatch_log_group:
                    log_group_arn = f"arn:{logs_client.audited_partition}:logs:{region}:{logs_client.audited_account}:log-group:{logging.cloudwatch_log_group}"
                    all_log_groups = getattr(logs_client, "all_log_groups", None) or {}
                    if (
                        log_group_arn in all_log_groups
                        and not all_log_groups[log_group_arn].kms_id
                    ) or (
                        log_group_arn + ":*" in all_log_groups
                        and not all_log_groups[log_group_arn + ":*"].kms_id
                    ):
                        cloudwatch_encryption = False
                if not s3_encryption and not cloudwatch_encryption:
                    report.status = "FAIL"
                    report.status_extended = f"Bedrock Model Invocation logs are not encrypted in S3 bucket: {logging.s3_bucket} and CloudWatch Log Group: {logging.cloudwatch_log_group}."
                elif not s3_encryption:
                    report.status = "FAIL"
                    report.status_extended = f"Bedrock Model Invocation logs are not encrypted in S3 bucket: {logging.s3_bucket}."
                elif not cloudwatch_encryption:
                    report.status = "FAIL"
                    report.status_extended = f"Bedrock Model Invocation logs are not encrypted in CloudWatch Log Group: {logging.cloudwatch_log_group}."

                findings.append(report)

        return findings