Skip to content

Commit

Permalink
feat!: Support multiple replication rules. Use `replication_configura…
Browse files Browse the repository at this point in the history
…tion` map instead of previous variables.
  • Loading branch information
baolsen committed Mar 10, 2023
1 parent 922eb99 commit 30fcb54
Show file tree
Hide file tree
Showing 17 changed files with 514 additions and 221 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.formatting.provider": "black"
}
8 changes: 1 addition & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,8 @@ See [`CONTRIBUTING.md`](./.github/CONTRIBUTING.md) for further information.
|------|-------------|------|---------|:--------:|
| <a name="input_aws_iam_role_permissions_boundary"></a> [aws\_iam\_role\_permissions\_boundary](#input\_aws\_iam\_role\_permissions\_boundary) | AWS IAM Role permissions boundary. | `string` | `null` | no |
| <a name="input_create_iam_resources"></a> [create\_iam\_resources](#input\_create\_iam\_resources) | Whether to create IAM resources. | `bool` | `true` | no |
| <a name="input_destination_aws_account_id"></a> [destination\_aws\_account\_id](#input\_destination\_aws\_account\_id) | Destination AWS Account ID. Only use for cross-account replication. When specified, replica object ownership will be set to this account. | `string` | `null` | no |
| <a name="input_destination_bucket_kms_key_arn"></a> [destination\_bucket\_kms\_key\_arn](#input\_destination\_bucket\_kms\_key\_arn) | Destination S3 bucket KMS Key ARN | `string` | `null` | no |
| <a name="input_destination_bucket_name"></a> [destination\_bucket\_name](#input\_destination\_bucket\_name) | Destination S3 bucket name | `string` | n/a | yes |
| <a name="input_destination_bucket_region"></a> [destination\_bucket\_region](#input\_destination\_bucket\_region) | Destination S3 bucket region. If unspecified, then the provider region is used. | `string` | `null` | no |
| <a name="input_enable_delete_marker_replication"></a> [enable\_delete\_marker\_replication](#input\_enable\_delete\_marker\_replication) | Whether delete markers are replicated. | `bool` | `true` | no |
| <a name="input_enable_replication_time_control_and_metrics"></a> [enable\_replication\_time\_control\_and\_metrics](#input\_enable\_replication\_time\_control\_and\_metrics) | Whether to enable S3 Replication Time Control (S3 RTC) and Replication Metrics. | `bool` | `false` | no |
| <a name="input_name_for_created_iam_resources"></a> [name\_for\_created\_iam\_resources](#input\_name\_for\_created\_iam\_resources) | Name for created IAM resources. | `string` | n/a | yes |
| <a name="input_prefix"></a> [prefix](#input\_prefix) | S3 bucket prefix to replicate. | `string` | `""` | no |
| <a name="input_replication_configuration"></a> [replication\_configuration](#input\_replication\_configuration) | Replication configuration, in priority order. See the comments in `variables.tf` for usage. | <pre>list(object({<br><br> destination_bucket_name = string<br><br> # S3 bucket prefix to replicate.<br> prefix = optional(string, "")<br><br> # Destination S3 bucket KMS Key ARN if applicable.<br> destination_bucket_kms_key_arn = optional(string, null)<br><br> # Destination AWS Account ID. Only use for cross-account replication. When specified, replica object ownership will be set to this account.<br> destination_aws_account_id = optional(string, null)<br><br> # Destination S3 bucket region. If unspecified, then the provider region is used.<br> destination_bucket_region = optional(string, null)<br><br> # Whether delete markers are replicated.<br> enable_delete_marker_replication = optional(bool, true)<br><br> # Whether to enable S3 Replication Time Control (S3 RTC) and Replication Metrics.<br> enable_replication_time_control_and_metrics = optional(bool, false)<br> })<br> )</pre> | n/a | yes |
| <a name="input_replication_role_arn"></a> [replication\_role\_arn](#input\_replication\_role\_arn) | IAM Role ARN for replication role. | `string` | `null` | no |
| <a name="input_source_bucket_kms_key_arn"></a> [source\_bucket\_kms\_key\_arn](#input\_source\_bucket\_kms\_key\_arn) | Source S3 bucket KMS Key ARN | `string` | `null` | no |
| <a name="input_source_bucket_name"></a> [source\_bucket\_name](#input\_source\_bucket\_name) | Source S3 bucket name | `string` | n/a | yes |
Expand Down
135 changes: 28 additions & 107 deletions data.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ data "aws_iam_policy_document" "replication_role_policy_document" {
"s3:GetObjectRetention",
"s3:GetObjectLegalHold"
]
resources = [
local.source_bucket_arn,
local.destination_bucket_arn,
"${local.destination_bucket_arn}/*",
"${local.source_bucket_arn}/*"
]
resources = concat(
[local.source_bucket_arn],
["${local.source_bucket_arn}/*"],
[for c in var.replication_configuration : "arn:aws:s3:::${c.destination_bucket_name}"],
[for c in var.replication_configuration : "arn:aws:s3:::${c.destination_bucket_name}/*"]
)
}

statement {
Expand All @@ -42,33 +42,29 @@ data "aws_iam_policy_document" "replication_role_policy_document" {
"s3:ReplicateTags",
"s3:GetObjectVersionTagging"
]
resources = [
"${local.destination_bucket_arn}/*",
"${local.source_bucket_arn}/*"
]
resources = concat(
["${local.source_bucket_arn}/*"],
[for c in var.replication_configuration : "arn:aws:s3:::${c.destination_bucket_name}/*"],
)
}

dynamic "statement" {
for_each = var.destination_aws_account_id != null ? toset([1]) : toset([])
for_each = toset(var.replication_configuration)
content {
actions = ["s3:ObjectOwnerOverrideToBucketOwner"]
resources = ["${local.destination_bucket_arn}/*"]
resources = ["arn:aws:s3:::${statement.value.destination_bucket_name}/*"]
}
}

dynamic "statement" {
for_each = var.source_bucket_kms_key_arn != null ? toset([1]) : toset([])
content {
actions = [
"kms:Decrypt"
]
actions = ["kms:Decrypt"]
resources = [var.source_bucket_kms_key_arn]
condition {
test = "StringLike"
variable = "kms:ViaService"
values = [
"s3.${local.source_region}.amazonaws.com"
]
values = ["s3.${local.source_region}.amazonaws.com"]
}
condition {
test = "StringLike"
Expand All @@ -84,108 +80,33 @@ data "aws_iam_policy_document" "replication_role_policy_document" {
}

dynamic "statement" {
for_each = var.destination_bucket_kms_key_arn != null ? toset([1]) : toset([])
for_each = toset([
for c in toset(var.replication_configuration) :
c if c.destination_bucket_kms_key_arn != null
])

content {
actions = [
"kms:Encrypt"
]
resources = [var.destination_bucket_kms_key_arn]
actions = ["kms:Encrypt"]
resources = [statement.value.destination_bucket_kms_key_arn]
condition {
test = "StringLike"
variable = "kms:ViaService"
values = [
"s3.${local.destination_region}.amazonaws.com"
]
values = (
statement.value.destination_bucket_region != null
? ["s3.${statement.value.destination_bucket_region}.amazonaws.com"]
: ["s3.${data.aws_region.current.name}.amazonaws.com"]
)
}
condition {
test = "StringLike"
variable = "kms:EncryptionContext:aws:s3:arn"
values = [
# When bucket_key_enabled
local.destination_bucket_arn,
"arn:aws:s3:::${statement.value.destination_bucket_name}",
# When NOT bucket_key_enabled
"${local.destination_bucket_arn}/*"
"arn:aws:s3:::${statement.value.destination_bucket_name}/*"
]
}
}
}
}

#--------------------------------------------------------------------------------------
# Destination bucket policy document
#--------------------------------------------------------------------------------------
/*
Doesnt make sense to create dest resources in the same module
They only apply in cross-account scenarios and need input of the IAM role ARN.
data "aws_iam_policy_document" "destination_bucket_policy" {
count = var.create_destination_resources ? 1 : 0
statement {
actions = [
"s3:List*",
"s3:GetBucketVersioning",
"s3:PutBucketVersioning"
]
principals {
type = "AWS"
identifiers = [aws_iam_role.this[0].arn]
}
resources = [local.destination_bucket_arn]
}
statement {
actions = [
"s3:ReplicateObject",
"s3:ReplicateDelete"
]
principals {
type = "AWS"
identifiers = [aws_iam_role.this[0].arn]
}
resources = ["${local.destination_bucket_arn}/*"]
}
dynamic "statement" {
for_each = var.destination_aws_account_id != null ? toset([1]) : toset([])
content {
principals {
type = "AWS"
identifiers = [aws_iam_role.this[0].arn]
}
actions = ["s3:ObjectOwnerOverrideToBucketOwner"]
resources = ["${local.destination_bucket_arn}/*"]
}
}
}
#--------------------------------------------------------------------------------------
# Destination kms_key policy document
#--------------------------------------------------------------------------------------
data "aws_iam_policy_document" "destination_kms_key_policy" {
count = var.create_destination_resources ? 1 : 0
statement {
actions = [
"kms:Encrypt"
]
resources = [var.destination_bucket_kms_key_arn]
condition {
test = "StringLike"
variable = "kms:ViaService"
values = [
"s3.${local.destination_region}.amazonaws.com"
]
}
condition {
test = "StringLike"
variable = "kms:EncryptionContext:aws:s3:arn"
values = [
# When bucket_key_enabled
local.destination_bucket_arn,
# When NOT bucket_key_enabled
"${local.destination_bucket_arn}/*"
]
}
}
}
*/
11 changes: 9 additions & 2 deletions examples/basic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,17 @@ module "example" {
source_bucket_name = module.s3_bucket_source.bucket
source_bucket_kms_key_arn = aws_kms_key.source.arn
destination_bucket_name = module.s3_bucket_destination.bucket
destination_bucket_kms_key_arn = aws_kms_key.destination.arn
replication_configuration = [
{
destination_bucket_name = module.s3_bucket_destination.bucket
destination_bucket_kms_key_arn = aws_kms_key.destination.arn
enable_replication_time_control_and_metrics = true
}
]
tags = {}
depends_on = [
module.s3_bucket_source, module.s3_bucket_destination
]
Expand Down
11 changes: 9 additions & 2 deletions examples/basic/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,17 @@ module "example" {
source_bucket_name = module.s3_bucket_source.bucket
source_bucket_kms_key_arn = aws_kms_key.source.arn

destination_bucket_name = module.s3_bucket_destination.bucket
destination_bucket_kms_key_arn = aws_kms_key.destination.arn
replication_configuration = [
{
destination_bucket_name = module.s3_bucket_destination.bucket
destination_bucket_kms_key_arn = aws_kms_key.destination.arn

enable_replication_time_control_and_metrics = true
}
]

tags = {}

depends_on = [
module.s3_bucket_source, module.s3_bucket_destination
]
Expand Down
14 changes: 9 additions & 5 deletions examples/cross-region/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,15 @@ module "example" {
source_bucket_name = module.s3_bucket_source.bucket
source_bucket_kms_key_arn = aws_kms_key.source.arn
destination_bucket_name = module.s3_bucket_destination.bucket
destination_bucket_kms_key_arn = aws_kms_key.destination.arn
destination_bucket_region = "eu-west-1"
enable_replication_time_control_and_metrics = true
replication_configuration = [
{
destination_bucket_name = module.s3_bucket_destination.bucket
destination_bucket_kms_key_arn = aws_kms_key.destination.arn
destination_bucket_region = "eu-west-1"
enable_replication_time_control_and_metrics = true
}
]
tags = {}
Expand Down
14 changes: 9 additions & 5 deletions examples/cross-region/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,15 @@ module "example" {
source_bucket_name = module.s3_bucket_source.bucket
source_bucket_kms_key_arn = aws_kms_key.source.arn

destination_bucket_name = module.s3_bucket_destination.bucket
destination_bucket_kms_key_arn = aws_kms_key.destination.arn
destination_bucket_region = "eu-west-1"

enable_replication_time_control_and_metrics = true
replication_configuration = [
{
destination_bucket_name = module.s3_bucket_destination.bucket
destination_bucket_kms_key_arn = aws_kms_key.destination.arn
destination_bucket_region = "eu-west-1"

enable_replication_time_control_and_metrics = true
}
]

tags = {}

Expand Down
Loading

0 comments on commit 30fcb54

Please sign in to comment.