Skip to content

S3 buckets should have cross-region replication enabled

A single-region S3 bucket is a single point of failure for data availability. Regional outages, while rare, do happen. Cross-region replication copies new object versions to a bucket in a separate region, giving you a warm standby that supports recovery time objectives measured in minutes rather than hours.

CRR can support regulatory expectations for geographically separated backups. Without it, restoring data after a regional event depends on backup and recovery mechanisms you may or may not have configured.

Retrofit consideration

Enabling CRR on existing buckets requires versioning on both source and destination buckets. If versioning was not previously enabled, you need to account for noncurrent object versions and the resulting storage cost increase. CRR only replicates objects written after the rule is created; existing objects require a separate S3 Batch Replication job.

Implementation

Choose the approach that matches how you manage Terraform.

Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.

module "s3_bucket" {
  source  = "soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "pcidss.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "hipaa.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "nist80053.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "nistcsf.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "fedrampmoderate.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "cisv80ig1.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "nist800171.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "cisacyberessentials.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "nydfs23.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "ffiec.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "eugmpannex11.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "cfrpart11.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "rbicybersecurity.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "rbiitfnbfc.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "fedramplow.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "hipaasecurity2003.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "nistcsfv11.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "nist80053rev4.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

module "s3_bucket" {
  source  = "pcidssv321.compliance.tf/terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"
}

If you use terraform-aws-modules/s3-bucket/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "s3_bucket" {
  source  = "terraform-aws-modules/s3-bucket/aws"
  version = ">=5.0.0"

  bucket = "abc123"

  replication_configuration = {
    rules[0] = {
      status = "Enabled"
    }
  }
}

Use AWS provider resources directly. See docs for the resources involved: aws_s3_bucket_replication_configuration.

resource "aws_s3_bucket" "this" {
  bucket        = "pofix-abc123"
  force_destroy = true
}

resource "aws_s3_bucket_replication_configuration" "this" {
  bucket = "example-bucket-abc123"
  role   = "arn:aws:iam::123456789012:role/example-role"

  rule {
    delete_marker_replication {
      status = "Enabled"
    }

    destination {
      bucket        = "arn:aws:s3:::example-bucket-abc123"
      storage_class = "STANDARD"
    }

    filter {
    }

    id       = "cross-region-replication"
    priority = 10
    status   = "Enabled"
  }
}

What this control checks

The policy checks that an aws_s3_bucket_replication_configuration resource is associated with each S3 bucket and that at least one replication rule is active.

To pass, three things must be in place. First, versioning must be enabled on both source and destination buckets via aws_s3_bucket_versioning with versioning_configuration { status = "Enabled" }. Second, an aws_iam_role must exist with a trust policy allowing s3.amazonaws.com to assume it and an attached policy granting s3:GetReplicationConfiguration, s3:ListBucket, s3:GetObjectVersionForReplication, s3:GetObjectVersionAcl, s3:GetObjectVersionTagging on the source and s3:ReplicateObject, s3:ReplicateDelete, s3:ReplicateTags on the destination. Third, the aws_s3_bucket_replication_configuration resource must reference the source bucket via bucket, the IAM role via role, and include at least one rule block with status = "Enabled" and a destination block pointing to a bucket ARN in a different region. A filter block (even if empty) is required in current provider versions. Buckets with no replication configuration, or with all rules set to status = "Disabled", fail.

Common pitfalls

  • Versioning must be enabled on both buckets

    CRR requires aws_s3_bucket_versioning with versioning_configuration { status = "Enabled" } on both source and destination. If either bucket has versioning suspended or not configured, the PutBucketReplication API call fails with InvalidRequest. This is a common deployment blocker when retrofitting existing buckets.

  • Existing objects are not replicated automatically

    Objects that existed before the replication rule was created are not copied. They stay source-only until you run an S3 Batch Replication job via aws_s3control_job or the console. Auditors may flag gaps if they compare object counts between source and destination and find the numbers don't line up.

  • Deprecated inline replication_configuration block

    Use the standalone aws_s3_bucket_replication_configuration resource. The inline replication_configuration block inside aws_s3_bucket was removed in provider v4, and mixing old patterns with the standalone resource causes state drift and unexpected plan diffs.

  • Delete marker replication must be configured when needed

    With V2 replication rules, delete markers are not replicated unless you explicitly set delete_marker_replication { status = "Enabled" }. Skip it and deleting an object in the source leaves the replica intact, which breaks consistency assumptions during DR testing.

  • Cross-account replication requires destination bucket policy

    When replicating to a bucket in a different AWS account, the destination bucket policy must explicitly grant s3:ReplicateObject, s3:ReplicateDelete, and s3:ObjectOwnerOverrideToBucketOwner to the source account's replication role ARN. Missing this policy causes replication failures that are typically diagnosed through S3 replication metrics and status.

Audit evidence

An auditor expects Config rule evaluation results showing s3-bucket-replication-enabled as COMPLIANT for every in-scope bucket. Supporting evidence includes the S3 console Replication tab showing active rules with a destination bucket in a different region, and replication metrics confirming objects are being replicated successfully. CloudTrail logs for PutBucketReplication calls show when CRR was configured and by whom.

For ongoing assurance, Config conformance pack reports or Security Hub findings exported to a compliance dashboard give continuous coverage. If S3 Batch Replication was used to backfill existing objects, retain the Batch Operations job completion report as well.

Framework-specific interpretation

SOC 2: The A-series Availability criteria require backup and recovery capabilities. Geographic redundancy for S3-hosted data via CRR strengthens the evidence auditors look for under those criteria.

PCI DSS v4.0: Requirement 12.10 covers incident response planning, and CRR can support resilience objectives there. It does not satisfy core PCI DSS data protection controls on its own.

HIPAA Omnibus Rule 2013: The Security Rule at 45 CFR 164.308(a)(7) covers contingency planning, including data backup and disaster recovery. CRR can provide a continuously updated copy of ePHI in S3, supporting lower recovery point objectives when a regional failure occurs.

NIST SP 800-53 Rev 5: Addresses CP-9 by keeping backup copies at a separate geographic location and supports CP-6 (Alternate Storage Site) by placing replicas in a different region. Both controls are in scope for any NIST 800-53 system using S3 for data storage.

NIST Cybersecurity Framework v2.0: S3 cross-region replication feeds into CSF 2.0 Recover (RC) objectives, specifically recovery planning and data resilience. The Protect (PR) outcomes around data management are also supported by maintaining geographically separated copies.

FedRAMP Moderate Baseline Rev 4: CP-9 and CP-10 both call for backup copies at geographically separated facilities. CRR can satisfy that requirement for objects stored in S3 by maintaining a live replica in a second region.

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: s3_bucket_cross_region_replication_enabled

  • AWS Config Managed Rule: S3_BUCKET_CROSS_REGION_REPLICATION_ENABLED

  • Checkov Check: CKV_AWS_144

  • Powerpipe Control: aws_compliance.control.s3_bucket_cross_region_replication_enabled

  • Prowler Check: s3_bucket_cross_region_replication

  • AWS Security Hub Control: S3.7

Last reviewed: 2026-03-09