S3 Bucket Cross-Region Replication
Overview
This check verifies that Amazon S3 buckets have cross-region replication (CRR) configured. Cross-region replication automatically copies objects from a source bucket in one AWS Region to a destination bucket in a different Region.
Without CRR, your data exists only in a single region, making it vulnerable to regional outages or disasters.
Risk
If this check fails, your S3 data faces these risks:
- Regional outages can make your data completely inaccessible
- Longer recovery times during disasters since there is no replica to fail over to
- Data loss exposure if corruption or accidental deletion occurs without a copy elsewhere
- Service disruption for applications that depend on multi-region availability
Remediation Steps
Prerequisites
- Access to the AWS Console with permissions to modify S3 buckets and create IAM roles
- A destination bucket in a different AWS Region (you can create one during setup)
Required IAM permissions
To configure replication, your IAM user or role needs:
s3:PutReplicationConfigurationon the source buckets3:GetReplicationConfigurationon the source bucketiam:PassRoleto assign the replication roles3:CreateBucketif creating a new destination bucket
AWS Console Method
- Open the S3 Console
- Click on your source bucket name
- Go to the Properties tab
- Scroll to Bucket Versioning and click Edit
- Select Enable and click Save changes (versioning is required for replication)
- Go to the Management tab
- Scroll to Replication rules and click Create replication rule
- Enter a rule name (e.g., "Replicate to us-west-2")
- For Status, keep it set to Enabled
- Under Source bucket, choose Apply to all objects in the bucket (or filter by prefix/tags if needed)
- Under Destination:
- Choose Browse S3 and select a bucket in a different region, or create a new one
- Ensure the destination bucket also has versioning enabled
- Under IAM role, select Create new role (recommended)
- Click Save
AWS will create the necessary IAM role automatically. New objects uploaded after this point will replicate to the destination.
AWS CLI (optional)
Step 1: Enable versioning on the source bucket
aws s3api put-bucket-versioning \
--bucket <your-source-bucket> \
--versioning-configuration Status=Enabled \
--region us-east-1
Step 2: Create the replication IAM role
First, create the trust policy file:
cat > /tmp/trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
Create the role:
aws iam create-role \
--role-name S3ReplicationRole \
--assume-role-policy-document file:///tmp/trust-policy.json \
--region us-east-1
Step 3: Attach the replication policy
Create the permissions policy file (replace placeholders):
cat > /tmp/replication-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetReplicationConfiguration",
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::<your-source-bucket>"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObjectVersionForReplication",
"s3:GetObjectVersionAcl",
"s3:GetObjectVersionTagging"
],
"Resource": "arn:aws:s3:::<your-source-bucket>/*"
},
{
"Effect": "Allow",
"Action": [
"s3:ReplicateObject",
"s3:ReplicateDelete",
"s3:ReplicateTags"
],
"Resource": "arn:aws:s3:::<your-destination-bucket>/*"
}
]
}
EOF
Attach the policy:
aws iam put-role-policy \
--role-name S3ReplicationRole \
--policy-name S3ReplicationPolicy \
--policy-document file:///tmp/replication-policy.json \
--region us-east-1
Step 4: Configure replication
Create the replication configuration file:
cat > /tmp/replication-config.json << 'EOF'
{
"Role": "arn:aws:iam::<your-account-id>:role/S3ReplicationRole",
"Rules": [
{
"ID": "ReplicateAllObjects",
"Status": "Enabled",
"Priority": 1,
"Filter": {},
"Destination": {
"Bucket": "arn:aws:s3:::<your-destination-bucket>",
"StorageClass": "STANDARD"
},
"DeleteMarkerReplication": {
"Status": "Disabled"
}
}
]
}
EOF
Apply the configuration:
aws s3api put-bucket-replication \
--bucket <your-source-bucket> \
--replication-configuration file:///tmp/replication-config.json \
--region us-east-1
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: S3 bucket with cross-region replication enabled
Parameters:
SourceBucketName:
Type: String
Description: Name of the source S3 bucket
DestinationBucketArn:
Type: String
Description: ARN of the destination bucket in another region
Resources:
ReplicationRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: s3.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: S3ReplicationPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:GetReplicationConfiguration
- s3:ListBucket
Resource: !Sub 'arn:aws:s3:::${SourceBucketName}'
- Effect: Allow
Action:
- s3:GetObjectVersionForReplication
- s3:GetObjectVersionAcl
- s3:GetObjectVersionTagging
Resource: !Sub 'arn:aws:s3:::${SourceBucketName}/*'
- Effect: Allow
Action:
- s3:ReplicateObject
- s3:ReplicateDelete
- s3:ReplicateTags
Resource: !Sub '${DestinationBucketArn}/*'
SourceBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref SourceBucketName
VersioningConfiguration:
Status: Enabled
ReplicationConfiguration:
Role: !GetAtt ReplicationRole.Arn
Rules:
- Id: ReplicateAllObjects
Status: Enabled
Destination:
Bucket: !Ref DestinationBucketArn
StorageClass: STANDARD
Outputs:
SourceBucketArn:
Description: ARN of the source bucket
Value: !GetAtt SourceBucket.Arn
ReplicationRoleArn:
Description: ARN of the replication IAM role
Value: !GetAtt ReplicationRole.Arn
Deploy the stack:
aws cloudformation deploy \
--template-file template.yaml \
--stack-name s3-cross-region-replication \
--parameter-overrides \
SourceBucketName=<your-source-bucket> \
DestinationBucketArn=arn:aws:s3:::<your-destination-bucket> \
--capabilities CAPABILITY_IAM \
--region us-east-1
Terraform (optional)
variable "source_bucket_name" {
description = "Name of the source S3 bucket"
type = string
}
variable "destination_bucket_arn" {
description = "ARN of the destination bucket in another region"
type = string
}
# IAM role for S3 replication
resource "aws_iam_role" "replication" {
name = "${var.source_bucket_name}-replication-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "s3.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
}
resource "aws_iam_role_policy" "replication" {
name = "${var.source_bucket_name}-replication-policy"
role = aws_iam_role.replication.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:GetReplicationConfiguration",
"s3:ListBucket"
]
Resource = "arn:aws:s3:::${var.source_bucket_name}"
},
{
Effect = "Allow"
Action = [
"s3:GetObjectVersionForReplication",
"s3:GetObjectVersionAcl",
"s3:GetObjectVersionTagging"
]
Resource = "arn:aws:s3:::${var.source_bucket_name}/*"
},
{
Effect = "Allow"
Action = [
"s3:ReplicateObject",
"s3:ReplicateDelete",
"s3:ReplicateTags"
]
Resource = "${var.destination_bucket_arn}/*"
}
]
})
}
# Source bucket with versioning and replication
resource "aws_s3_bucket" "source" {
bucket = var.source_bucket_name
}
resource "aws_s3_bucket_versioning" "source" {
bucket = aws_s3_bucket.source.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_replication_configuration" "replication" {
depends_on = [aws_s3_bucket_versioning.source]
role = aws_iam_role.replication.arn
bucket = aws_s3_bucket.source.id
rule {
id = "replicate-all-objects"
status = "Enabled"
destination {
bucket = var.destination_bucket_arn
storage_class = "STANDARD"
}
}
}
output "source_bucket_arn" {
description = "ARN of the source bucket"
value = aws_s3_bucket.source.arn
}
output "replication_role_arn" {
description = "ARN of the replication IAM role"
value = aws_iam_role.replication.arn
}
Apply the configuration:
terraform init
terraform apply -var="source_bucket_name=<your-source-bucket>" \
-var="destination_bucket_arn=arn:aws:s3:::<your-destination-bucket>"
Verification
After enabling replication, verify it is working:
- In the S3 Console, go to your source bucket
- Click the Management tab
- Under Replication rules, confirm your rule shows Enabled
- Upload a test file to the source bucket
- Wait a few minutes, then check the destination bucket for the replicated file
CLI verification
Check the replication configuration:
aws s3api get-bucket-replication \
--bucket <your-source-bucket> \
--region us-east-1
Expected output shows your replication rules with Status: Enabled.
Re-run the Prowler check to confirm remediation:
prowler aws --checks s3_bucket_cross_region_replication
Additional Resources
- AWS S3 Replication Overview
- Setting Up Cross-Region Replication
- Replication Time Control (RTC)
- Troubleshooting Replication
Notes
- Versioning is required: Both source and destination buckets must have versioning enabled for replication to work.
- Existing objects are not replicated: Only new objects uploaded after enabling replication will be copied. Use S3 Batch Replication to replicate existing objects.
- Costs: You will incur S3 storage costs in both regions, plus data transfer costs for replication.
- Replication lag: Objects typically replicate within 15 minutes, but can take longer for large files. Consider Replication Time Control (RTC) for stricter SLAs.
- Delete markers: By default, delete markers are not replicated. Enable delete marker replication if you want deletes to sync across regions.
- KMS-encrypted objects: If your objects use KMS encryption, additional configuration is required to replicate the encryption keys.