Skip to content

Commit

Permalink
Adding support for s3 bucket replication configuration (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
danjbh authored Oct 27, 2020
1 parent 8b82a11 commit 128d9f0
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,10 @@ Available targets:
| policy | A valid bucket policy JSON document. Note that if the policy document is not specific enough (but still valid), Terraform may view the policy as constantly changing in a terraform plan. In this case, please make sure you use the verbose/specific version of the policy | `string` | `""` | no |
| prefix | Prefix identifying one or more objects to which the rule applies | `string` | `""` | no |
| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.<br>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
| replication\_rules | Specifies the replication rules if S3 bucket replication is enabled | `list(any)` | `null` | no |
| restrict\_public\_buckets | Set to `false` to disable the restricting of making the bucket public | `bool` | `true` | no |
| s3\_replica\_bucket\_arn | The ARN of the S3 replica bucket (destination) | `string` | `""` | no |
| s3\_replication\_enabled | Set this to true and specify `s3_replica_bucket_arn` to enable replication. `versioning_enabled` must also be `true`. | `bool` | `false` | no |
| sse\_algorithm | The server-side encryption algorithm to use. Valid values are `AES256` and `aws:kms` | `string` | `"AES256"` | no |
| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
| standard\_transition\_days | Number of days to persist in the standard storage tier before moving to the infrequent access tier | `number` | `30` | no |
Expand Down
3 changes: 3 additions & 0 deletions docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@
| policy | A valid bucket policy JSON document. Note that if the policy document is not specific enough (but still valid), Terraform may view the policy as constantly changing in a terraform plan. In this case, please make sure you use the verbose/specific version of the policy | `string` | `""` | no |
| prefix | Prefix identifying one or more objects to which the rule applies | `string` | `""` | no |
| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.<br>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
| replication\_rules | Specifies the replication rules if S3 bucket replication is enabled | `list(any)` | `null` | no |
| restrict\_public\_buckets | Set to `false` to disable the restricting of making the bucket public | `bool` | `true` | no |
| s3\_replica\_bucket\_arn | The ARN of the S3 replica bucket (destination) | `string` | `""` | no |
| s3\_replication\_enabled | Set this to true and specify `s3_replica_bucket_arn` to enable replication. `versioning_enabled` must also be `true`. | `bool` | `false` | no |
| sse\_algorithm | The server-side encryption algorithm to use. Valid values are `AES256` and `aws:kms` | `string` | `"AES256"` | no |
| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
| standard\_transition\_days | Number of days to persist in the standard storage tier before moving to the infrequent access tier | `number` | `30` | no |
Expand Down
54 changes: 54 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,59 @@ resource "aws_s3_bucket" "default" {
uri = grant.value.uri
}
}

dynamic "replication_configuration" {
for_each = var.s3_replication_enabled ? [1] : []

content {
role = aws_iam_role.replication[0].arn

dynamic "rules" {
for_each = var.replication_rules == null ? [] : var.replication_rules

content {
id = rules.value.id
priority = try(rules.value.priority, 0)
prefix = try(rules.value.prefix, null)
status = try(rules.value.status, null)

destination {
bucket = var.s3_replica_bucket_arn
storage_class = try(rules.value.destination.storage_class, "STANDARD")
replica_kms_key_id = try(rules.value.destination.replica_kms_key_id, null)
account_id = try(rules.value.destination.account_id, null)

dynamic "access_control_translation" {
for_each = try(rules.value.destination.access_control_translation.owner, null) == null ? [] : [rules.value.destination.access_control_translation.owner]

content {
owner = access_control_translation.value
}
}
}

dynamic "source_selection_criteria" {
for_each = try(rules.value.source_selection_criteria.sse_kms_encrypted_objects.enabled, null) == null ? [] : [rules.value.source_selection_criteria.sse_kms_encrypted_objects.enabled]

content {
sse_kms_encrypted_objects {
enabled = source_selection_criteria.value
}
}
}

dynamic "filter" {
for_each = try(rules.value.filter, null) == null ? [] : [rules.value.filter]

content {
prefix = try(filter.value.prefix, null)
tags = try(filter.value.tags, {})
}
}
}
}
}
}
}

module "s3_user" {
Expand Down Expand Up @@ -166,3 +219,4 @@ resource "aws_s3_bucket_public_access_block" "default" {
ignore_public_acls = var.ignore_public_acls
restrict_public_buckets = var.restrict_public_buckets
}

66 changes: 66 additions & 0 deletions replication.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
resource "aws_iam_role" "replication" {
count = module.this.enabled && var.s3_replication_enabled ? 1 : 0

name = format("%s-replication", module.this.id)
assume_role_policy = data.aws_iam_policy_document.replication_sts[0].json
}

data "aws_iam_policy_document" "replication_sts" {
count = module.this.enabled && var.s3_replication_enabled ? 1 : 0

statement {
sid = "AllowPrimaryToAssumeServiceRole"
effect = "Allow"
actions = [
"sts:AssumeRole"
]

principals {
type = "Service"
identifiers = ["s3.amazonaws.com"]
}
}
}

resource "aws_iam_policy" "replication" {
count = module.this.enabled && var.s3_replication_enabled ? 1 : 0

name = format("%s-replication", module.this.id)
policy = data.aws_iam_policy_document.replication[0].json
}

data "aws_iam_policy_document" "replication" {
count = module.this.enabled && var.s3_replication_enabled ? 1 : 0

statement {
sid = "AllowPrimaryToGetReplicationConfiguration"
effect = "Allow"
actions = [
"s3:Get*",
"s3:ListBucket"
]
resources = [
aws_s3_bucket.default[0].arn,
"${aws_s3_bucket.default[0].arn}/*"
]
}

statement {
sid = "AllowPrimaryToReplicate"
effect = "Allow"
actions = [
"s3:ReplicateObject",
"s3:ReplicateDelete",
"s3:ReplicateTags",
"s3:GetObjectVersionTagging"
]

resources = ["${var.s3_replica_bucket_arn}/*"]
}
}

resource "aws_iam_role_policy_attachment" "replication" {
count = module.this.enabled && var.s3_replication_enabled ? 1 : 0
role = aws_iam_role.replication[0].name
policy_arn = aws_iam_policy.replication[0].arn
}
43 changes: 43 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,46 @@ variable "restrict_public_buckets" {
default = true
description = "Set to `false` to disable the restricting of making the bucket public"
}

variable "s3_replication_enabled" {
type = bool
default = false
description = "Set this to true and specify `s3_replica_bucket_arn` to enable replication. `versioning_enabled` must also be `true`."
}

variable "s3_replica_bucket_arn" {
type = string
default = ""
description = "The ARN of the S3 replica bucket (destination)"
}

variable "replication_rules" {
# type = list(object({
# id = string
# priority = number
# prefix = string
# status = string
# destination = object({
# storage_class = string
# replica_kms_key_id = string
# access_control_translation = object({
# owner = string
# })
# account_id = string
# })
# source_selection_criteria = object({
# sse_kms_encrypted_objects = object({
# enabled = bool
# })
# })
# filter = object({
# prefix = string
# tags = map(string)
# })
# }))

type = list(any)
default = null
description = "Specifies the replication rules if S3 bucket replication is enabled"
}

0 comments on commit 128d9f0

Please sign in to comment.