Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions modules/aws-s3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,34 @@ It is flexible, production-ready, and easy to integrate into existing infrastruc
- **IAM role** for replication
- **Support for existing buckets**

## ⚠️ Important: Replication Setup Order

When setting up S3 replication between buckets, follow this order to avoid failures:

1. **Create the destination bucket first** (without any replication source configuration)
- Deploy the destination bucket without `s3_replication_source` parameter

2. **Apply replication source configuration**
- Deploy the source bucket with `s3_replication_destination` configured
- This generates the IAM role and policies needed for replication

3. **Configure destination to accept replication**
- Update the destination bucket Terraform with the `s3_replication_source` parameter
- Use the role ARN generated from step 2
- Apply the full Terraform configuration

This three-stage approach ensures that:
- IAM roles and policies are properly propagated across accounts
- The destination bucket exists before the source tries to replicate to it
- Cross-account permissions are correctly established before replication starts

## Basic Usage

### Minimal Example (S3 bucket)

```hcl
module "s3" {
source = "github.com/prefapp/tfm/modules/aws-s3"
source = "git::https://github.com/prefapp/tfm.git//modules/aws-s3?ref=aws-s3-v0.1.1"
bucket = "my-bucket"
}
```
Expand All @@ -39,12 +60,12 @@ module "s3" {

```hcl
module "s3" {
source = "github.com/prefapp/tfm/modules/aws-s3"
source = "git::https://github.com/prefapp/tfm.git//modules/aws-s3?ref=aws-s3-v0.1.1"
bucket = "my-bucket-origin"
region = "eu-west-1"
s3_bucket_versioning = "Enabled"
s3_replication_destination = {
account = "1122334455"
account = "112233445566"
bucket_arn = "arn:aws:s3:::my-bucket-destination"
storage_class = "STANDARD"
}
Expand All @@ -55,14 +76,14 @@ module "s3" {

```hcl
module "s3" {
source = "github.com/prefapp/tfm/modules/aws-s3"
source = "git::https://github.com/prefapp/tfm.git//modules/aws-s3?ref=aws-s3-v0.1.1"

bucket = "my-bucket-origin"
region = "eu-west-1"
s3_bucket_versioning = "Enabled"
s3_replication_source = {
account = "5544332211"
role_arn = "arn:aws:iam::5544332211:role/my-bucket-origin-replication"
account = "665544332211"
role_arn = "arn:aws:iam::665544332211:role/my-bucket-origin-replication"
}
}
```
Expand Down Expand Up @@ -107,7 +128,7 @@ The module is organized with the following directory and file structure:

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | ~> 6.2 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | 6.30.0 |

## Modules

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ module "s3" {
role_arn = "arn:aws:iam::1122334455:role/o-a-d-replication"
}
s3_replication_destination = {
account = "1122334455"
account = "112233445566"
bucket_arn = "arn:aws:s3:::o-a-d"
storage_class = "STANDARD"
}

}
}
2 changes: 1 addition & 1 deletion modules/aws-s3/_examples/minimal_replication/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module "s3" {
s3_bucket_versioning = "Enabled"

s3_replication_destination = {
account = "1112222333"
account = "112233445566"
bucket_arn = "arn:aws:s3:::my-destination"
storage_class = "STANDARD"
}
Expand Down
4 changes: 2 additions & 2 deletions modules/aws-s3/_examples/minimal_source/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ module "s3" {
s3_bucket_versioning = "Enabled"

s3_replication_destination = {
account = "1122334455"
account = "112233445566"
bucket_arn = "arn:aws:s3:::destination-bucket"
storage_class = "STANDARD"
}

}
}
33 changes: 27 additions & 6 deletions modules/aws-s3/docs/header.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,34 @@ It is flexible, production-ready, and easy to integrate into existing infrastruc
- **IAM role** for replication
- **Support for existing buckets**

## ⚠️ Important: Replication Setup Order

When setting up S3 replication between buckets, follow this order to avoid failures:

1. **Create the destination bucket first** (without any replication source configuration)
- Deploy the destination bucket without `s3_replication_source` parameter

2. **Apply replication source configuration**
- Deploy the source bucket with `s3_replication_destination` configured
- This generates the IAM role and policies needed for replication

3. **Configure destination to accept replication**
- Update the destination bucket Terraform with the `s3_replication_source` parameter
- Use the role ARN generated from step 2
- Apply the full Terraform configuration

This three-stage approach ensures that:
- IAM roles and policies are properly propagated across accounts
- The destination bucket exists before the source tries to replicate to it
- Cross-account permissions are correctly established before replication starts

## Basic Usage

### Minimal Example (S3 bucket)

```hcl
module "s3" {
source = "github.com/prefapp/tfm/modules/aws-s3"
source = "git::https://github.com/prefapp/tfm.git//modules/aws-s3?ref=aws-s3-v0.1.1"
bucket = "my-bucket"
}
```
Expand All @@ -38,12 +59,12 @@ module "s3" {

```hcl
module "s3" {
source = "github.com/prefapp/tfm/modules/aws-s3"
source = "git::https://github.com/prefapp/tfm.git//modules/aws-s3?ref=aws-s3-v0.1.1"
bucket = "my-bucket-origin"
region = "eu-west-1"
s3_bucket_versioning = "Enabled"
s3_replication_destination = {
account = "1122334455"
account = "112233445566"
bucket_arn = "arn:aws:s3:::my-bucket-destination"
storage_class = "STANDARD"
}
Expand All @@ -54,14 +75,14 @@ module "s3" {

```hcl
module "s3" {
source = "github.com/prefapp/tfm/modules/aws-s3"
source = "git::https://github.com/prefapp/tfm.git//modules/aws-s3?ref=aws-s3-v0.1.1"

bucket = "my-bucket-origin"
region = "eu-west-1"
s3_bucket_versioning = "Enabled"
s3_replication_source = {
account = "5544332211"
role_arn = "arn:aws:iam::5544332211:role/my-bucket-origin-replication"
account = "665544332211"
role_arn = "arn:aws:iam::665544332211:role/my-bucket-origin-replication"
}
}
```
Expand Down
13 changes: 11 additions & 2 deletions modules/aws-s3/local.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
locals {
lifecycle_rules = (var.s3_replication_destination != null || var.s3_bucket_versioning == "Enabled") ? concat(var.lifecycle_rules, var.default_lifecycle_rules) : var.lifecycle_rules
}
lifecycle_rules = (var.s3_replication_destination != null || var.s3_replication_source != null || var.s3_bucket_versioning == "Enabled") ? concat(var.lifecycle_rules, var.default_lifecycle_rules) : var.lifecycle_rules
}

check "replication_requires_enabled_versioning" {
assert {
condition = (
var.s3_replication_destination == null && var.s3_replication_source == null
) || var.s3_bucket_versioning == "Enabled"
error_message = "s3_bucket_versioning must be set to \"Enabled\" when s3_replication_destination or s3_replication_source is configured."
}
}
4 changes: 2 additions & 2 deletions modules/aws-s3/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ data "aws_iam_policy_document" "source_replication_s3_policy_with_https_policy"

## Bucket Versioning
resource "aws_s3_bucket_versioning" "this" {
count = var.create_bucket ? 1 : 0
bucket = aws_s3_bucket.this[0].id
count = (var.create_bucket || var.s3_replication_destination != null || var.s3_replication_source != null) ? 1 : 0
bucket = var.create_bucket ? aws_s3_bucket.this[0].id : data.aws_s3_bucket.this[0].id
region = var.region
versioning_configuration {
status = var.s3_bucket_versioning
Expand Down
13 changes: 8 additions & 5 deletions modules/aws-s3/replication.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@

resource "aws_s3_bucket_replication_configuration" "origin_to_destination" {
count = var.s3_replication_destination != null ? 1 : 0
depends_on = [aws_s3_bucket_versioning.this]
region = var.region
role = aws_iam_role.replication[0].arn
bucket = var.create_bucket ? aws_s3_bucket.this[0].id : data.aws_s3_bucket.this[0].id
count = var.s3_replication_destination != null ? 1 : 0
depends_on = [
aws_s3_bucket_versioning.this,
aws_iam_role_policy_attachment.replication,
]
region = var.region
role = aws_iam_role.replication[0].arn
bucket = var.create_bucket ? aws_s3_bucket.this[0].id : data.aws_s3_bucket.this[0].id

rule {
id = "origin-to-destination"
Expand Down
5 changes: 0 additions & 5 deletions modules/aws-s3/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,6 @@ variable "s3_replication_destination" {
}))
})
default = null

validation {
condition = var.s3_replication_destination == null || var.s3_bucket_versioning == "Enabled"
error_message = "When configuring s3_replication_destination, s3_bucket_versioning must be set to \"Enabled\"."
}
}
Comment on lines 183 to 185

## Replication variables
Expand Down