Skip to content

Commit 92102d5

Browse files
authored
Reusable S3 multiregion bucket (#2)
* multiregion S3 module setup * Also output bucket ID * Fix
1 parent c1a2d3a commit 92102d5

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed

multiregion-s3/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Multiregion S3 bucket
2+
Creates a bi-directionally replicated S3 bucket between 2 regions with the same suffix.

multiregion-s3/main.tf

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# S3 Buckets
2+
resource "aws_s3_bucket" "buckets" {
3+
for_each = toset([var.Region1, var.Region2])
4+
region = each.value
5+
bucket = "${var.BucketPrefix}-${each.value}"
6+
}
7+
8+
# Enable versioning (required for replication)
9+
resource "aws_s3_bucket_versioning" "versioning" {
10+
for_each = toset([var.Region1, var.Region2])
11+
region = each.value
12+
bucket = aws_s3_bucket.buckets[each.value].id
13+
14+
versioning_configuration {
15+
status = "Enabled"
16+
}
17+
}
18+
19+
resource "aws_iam_role" "replication" {
20+
name = "${var.BucketPrefix}-replication-role"
21+
assume_role_policy = jsonencode({
22+
Version = "2012-10-17"
23+
Statement = [
24+
{
25+
Action = "sts:AssumeRole"
26+
Effect = "Allow"
27+
Principal = {
28+
Service = "s3.amazonaws.com"
29+
}
30+
}
31+
]
32+
})
33+
}
34+
35+
resource "aws_iam_policy" "replication" {
36+
name = "${var.BucketPrefix}-replication-policy"
37+
38+
policy = jsonencode({
39+
Version = "2012-10-17"
40+
Statement = [
41+
{
42+
Action = [
43+
"s3:GetReplicationConfiguration",
44+
"s3:ListBucket"
45+
]
46+
Effect = "Allow"
47+
Resource = [
48+
for bucket in aws_s3_bucket.buckets : bucket.arn
49+
]
50+
},
51+
{
52+
Action = [
53+
"s3:GetObjectVersionForReplication",
54+
"s3:GetObjectVersionAcl",
55+
"s3:GetObjectVersionTagging"
56+
]
57+
Effect = "Allow"
58+
Resource = [
59+
for bucket in aws_s3_bucket.buckets : "${bucket.arn}/*"
60+
]
61+
},
62+
{
63+
Action = [
64+
"s3:ReplicateObject",
65+
"s3:ReplicateDelete",
66+
"s3:ReplicateTags"
67+
]
68+
Effect = "Allow"
69+
Resource = [
70+
for bucket in aws_s3_bucket.buckets : "${bucket.arn}/*"
71+
]
72+
}
73+
]
74+
})
75+
}
76+
77+
resource "aws_iam_role_policy_attachment" "replication" {
78+
role = aws_iam_role.replication.name
79+
policy_arn = aws_iam_policy.replication.arn
80+
}
81+
82+
# Replication configuration: Region1 -> Region2
83+
resource "aws_s3_bucket_replication_configuration" "region1_to_region2" {
84+
region = var.Region1
85+
role = aws_iam_role.replication.arn
86+
bucket = aws_s3_bucket.buckets[var.Region1].id
87+
88+
rule {
89+
id = "replicate-to-${var.Region2}"
90+
status = "Enabled"
91+
priority = 1
92+
93+
filter {}
94+
95+
destination {
96+
bucket = aws_s3_bucket.buckets[var.Region2].arn
97+
storage_class = "STANDARD"
98+
}
99+
100+
delete_marker_replication {
101+
status = "Enabled"
102+
}
103+
}
104+
105+
depends_on = [aws_s3_bucket_versioning.versioning]
106+
}
107+
108+
# Replication configuration: Region2 -> Region1
109+
resource "aws_s3_bucket_replication_configuration" "region2_to_region1" {
110+
region = var.Region2
111+
role = aws_iam_role.replication.arn
112+
bucket = aws_s3_bucket.buckets[var.Region2].id
113+
114+
rule {
115+
id = "replicate-to-${var.Region1}"
116+
status = "Enabled"
117+
priority = 1
118+
119+
filter {}
120+
121+
destination {
122+
bucket = aws_s3_bucket.buckets[var.Region1].arn
123+
storage_class = "STANDARD"
124+
}
125+
126+
delete_marker_replication {
127+
status = "Enabled"
128+
}
129+
}
130+
131+
depends_on = [aws_s3_bucket_versioning.versioning]
132+
}
133+
134+
output "buckets_info" {
135+
description = "Map of bucket information by region"
136+
value = {
137+
for region, bucket in aws_s3_bucket.buckets : region => {
138+
arn = bucket.arn
139+
bucket_regional_domain_name = bucket.bucket_regional_domain_name
140+
bucket_domain_name = bucket.bucket_domain_name
141+
id = bucket.id
142+
}
143+
}
144+
}

multiregion-s3/variables.tf

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
data "aws_regions" "current" {
2+
all_regions = true
3+
}
4+
5+
variable "Region1" {
6+
type = string
7+
description = "Region for bucket 1"
8+
9+
validation {
10+
condition = contains(data.aws_regions.current.names, var.Region1)
11+
error_message = "Region1 must be a valid AWS region. Available regions: ${join(", ", data.aws_regions.current.names)}"
12+
}
13+
}
14+
15+
variable "Region2" {
16+
type = string
17+
description = "Region for bucket 2"
18+
19+
validation {
20+
condition = contains(data.aws_regions.current.names, var.Region2)
21+
error_message = "Region1 must be a valid AWS region. Available regions: ${join(", ", data.aws_regions.current.names)}"
22+
}
23+
}
24+
25+
variable "BucketPrefix" {
26+
type = string
27+
description = "Prefix for the bucket. The created bucket names will be in the form of BucketPrefix-Region."
28+
}

0 commit comments

Comments
 (0)