S3 Bucket Server Access Logging
Overview
This check verifies that your Amazon S3 buckets have server access logging enabled. When enabled, S3 records every request made to a bucket and saves detailed logs to a destination bucket you specify.
Risk
Without access logging, you have no record of who accessed your data, when, or what they did. This makes it nearly impossible to:
- Detect unauthorized access or data theft
- Investigate security incidents
- Meet compliance and audit requirements
- Understand access patterns for troubleshooting
Think of it like a building without security cameras - if something goes wrong, you have no way to see what happened.
Remediation Steps
Prerequisites
- Access to the AWS Console with permissions to modify S3 bucket settings
- A destination bucket to store your logs (can be the same account, ideally a separate bucket)
Setting up a dedicated log bucket
It is a best practice to create a dedicated bucket for storing access logs. This keeps logs organized and allows you to apply specific retention policies.
Console steps:
- Go to S3 in the AWS Console
- Click Create bucket
- Name it something like
my-s3-access-logs-bucket - Choose us-east-1 region
- Keep Block all public access enabled
- Click Create bucket
Important: The log destination bucket must be in the same AWS Region as the source bucket.
AWS Console Method
- Open the Amazon S3 Console
- Find and click on the bucket that needs logging enabled
- Go to the Properties tab
- Scroll down to Server access logging and click Edit
- Select Enable
- For Target bucket, choose your log destination bucket
- For Target prefix, enter a prefix like
logs/(this organizes logs by source bucket) - Click Save changes
That's it! AWS will now log all access requests to your bucket.
AWS CLI (optional)
Enable logging on a bucket:
aws s3api put-bucket-logging \
--bucket <your-source-bucket> \
--bucket-logging-status '{
"LoggingEnabled": {
"TargetBucket": "<your-log-bucket>",
"TargetPrefix": "logs/<your-source-bucket>/"
}
}' \
--region us-east-1
Replace:
<your-source-bucket>with the bucket you want to monitor<your-log-bucket>with the bucket that will store logs
Grant the logging service permission to write to your log bucket:
Before enabling logging, ensure your log bucket has the proper policy:
aws s3api put-bucket-policy \
--bucket <your-log-bucket> \
--policy '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3ServerAccessLogsPolicy",
"Effect": "Allow",
"Principal": {
"Service": "logging.s3.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::<your-log-bucket>/logs/*",
"Condition": {
"ArnLike": {
"aws:SourceArn": "arn:aws:s3:::<your-source-bucket>"
},
"StringEquals": {
"aws:SourceAccount": "<your-account-id>"
}
}
}
]
}' \
--region us-east-1
CloudFormation (optional)
This template creates a bucket policy that allows S3 to write access logs. Note that you must enable logging on the source bucket separately (CloudFormation cannot directly modify an existing bucket's logging configuration).
AWSTemplateFormatVersion: '2010-09-09'
Description: Enable S3 bucket server access logging
Parameters:
SourceBucketName:
Type: String
Description: Name of the S3 bucket to enable logging on
LogBucketName:
Type: String
Description: Name of the S3 bucket to store access logs
LogPrefix:
Type: String
Default: 'logs/'
Description: Prefix for log object keys
Resources:
LogBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref LogBucketName
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: S3ServerAccessLogsPolicy
Effect: Allow
Principal:
Service: logging.s3.amazonaws.com
Action: s3:PutObject
Resource: !Sub 'arn:aws:s3:::${LogBucketName}/${LogPrefix}*'
Condition:
ArnLike:
aws:SourceArn: !Sub 'arn:aws:s3:::${SourceBucketName}'
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
Outputs:
LogBucketArn:
Description: ARN of the log destination bucket
Value: !Sub 'arn:aws:s3:::${LogBucketName}'
Deploy the stack:
aws cloudformation deploy \
--template-file template.yaml \
--stack-name s3-access-logging \
--parameter-overrides \
SourceBucketName=<your-source-bucket> \
LogBucketName=<your-log-bucket> \
--region us-east-1
Terraform (optional)
# S3 Bucket Server Access Logging Configuration
variable "source_bucket_name" {
description = "Name of the S3 bucket to enable logging on"
type = string
}
variable "log_bucket_name" {
description = "Name of the S3 bucket to store access logs"
type = string
}
variable "log_prefix" {
description = "Prefix for log object keys"
type = string
default = "logs/"
}
# Data source to reference existing source bucket
data "aws_s3_bucket" "source" {
bucket = var.source_bucket_name
}
# Data source to reference existing log bucket
data "aws_s3_bucket" "logs" {
bucket = var.log_bucket_name
}
# Get current AWS account ID
data "aws_caller_identity" "current" {}
# Enable logging on the source bucket
resource "aws_s3_bucket_logging" "this" {
bucket = data.aws_s3_bucket.source.id
target_bucket = data.aws_s3_bucket.logs.id
target_prefix = var.log_prefix
}
# Bucket policy to allow S3 logging service to write logs
resource "aws_s3_bucket_policy" "log_bucket_policy" {
bucket = data.aws_s3_bucket.logs.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "S3ServerAccessLogsPolicy"
Effect = "Allow"
Principal = {
Service = "logging.s3.amazonaws.com"
}
Action = "s3:PutObject"
Resource = "${data.aws_s3_bucket.logs.arn}/${var.log_prefix}*"
Condition = {
ArnLike = {
"aws:SourceArn" = data.aws_s3_bucket.source.arn
}
StringEquals = {
"aws:SourceAccount" = data.aws_caller_identity.current.account_id
}
}
}
]
})
}
output "source_bucket_logging_enabled" {
description = "Source bucket with logging enabled"
value = aws_s3_bucket_logging.this.bucket
}
output "log_destination_bucket" {
description = "Bucket receiving access logs"
value = aws_s3_bucket_logging.this.target_bucket
}
Apply the configuration:
terraform init
terraform apply -var="source_bucket_name=<your-source-bucket>" -var="log_bucket_name=<your-log-bucket>"
Verification
After enabling logging, verify the configuration:
- Go to the S3 Console and select your bucket
- Click the Properties tab
- Scroll to Server access logging - it should show Enabled with your target bucket
Note: Logs may take a few minutes to start appearing in your destination bucket.
CLI verification
aws s3api get-bucket-logging --bucket <your-source-bucket> --region us-east-1
Expected output when logging is enabled:
{
"LoggingEnabled": {
"TargetBucket": "your-log-bucket",
"TargetPrefix": "logs/your-source-bucket/"
}
}
If logging is not enabled, the command returns an empty response.
Additional Resources
- Amazon S3 Server Access Logging
- Enabling Amazon S3 Server Access Logging
- S3 Server Access Log Format
- Best Practices for Security in Amazon S3
Notes
- Log delivery delay: Logs are delivered on a best-effort basis, typically within a few hours. They are not real-time.
- Storage costs: Access logs consume storage in your log bucket. Consider setting up lifecycle policies to manage retention and costs.
- Same-region requirement: The source bucket and log destination bucket must be in the same AWS Region.
- Directory buckets: Server access logging is not supported for S3 directory buckets (S3 Express One Zone).
- Complementary logging: For real-time, comprehensive logging, consider also enabling AWS CloudTrail data events for S3, which provides more detailed audit trails.