From 6570c595e73e6db756e1ba4f0a637d624a565d69 Mon Sep 17 00:00:00 2001 From: Dmitrij Nikitenko Date: Thu, 7 Mar 2024 18:52:04 +0200 Subject: [PATCH] Allow to use ECR replication (#103) * chore: enable ecr replication * Auto Format * fix: variable type and count * fix: small fixes * fix: readme * support dynamic configurations instead of dynamic rules * new readme * fix lint --------- Co-authored-by: cloudpossebot <11232728+cloudpossebot@users.noreply.github.com> Co-authored-by: Matt Gowie Co-authored-by: Kevin Mahoney Co-authored-by: Kevin Mahoney --- README.md | 2 ++ docs/terraform.md | 2 ++ examples/replication-repo/main.tf | 39 +++++++++++++++++++++++++++ examples/replication-repo/outputs.tf | 9 +++++++ examples/replication-repo/versions.tf | 9 +++++++ main.tf | 28 +++++++++++++++++++ variables.tf | 18 +++++++++++++ 7 files changed, 107 insertions(+) create mode 100644 examples/replication-repo/main.tf create mode 100644 examples/replication-repo/outputs.tf create mode 100644 examples/replication-repo/versions.tf diff --git a/README.md b/README.md index b4fb6c6..1b6f739 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ Available targets: | Name | Type | |------|------| | [aws_ecr_lifecycle_policy.name](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_lifecycle_policy) | resource | +| [aws_ecr_replication_configuration.replication_configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_replication_configuration) | resource | | [aws_ecr_repository.name](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | | [aws_ecr_repository_policy.name](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_policy) | resource | | [aws_iam_policy_document.empty](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | @@ -191,6 +192,7 @@ Available targets: | [principals\_readonly\_access](#input\_principals\_readonly\_access) | Principal ARNs to provide with readonly access to the ECR | `list(string)` | `[]` | no | | [protected\_tags](#input\_protected\_tags) | Name of image tags prefixes that should not be destroyed. Useful if you tag images with names like `dev`, `staging`, and `prod` | `set(string)` | `[]` | no | | [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| [replication\_configurations](#input\_replication\_configurations) | Replication configuration for a registry. See [Replication Configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_replication_configuration#replication-configuration). |
list(object({
rules = list(object({ # Maximum 10
destinations = list(object({ # Maximum 25
region = string
registry_id = string
}))
repository_filters = list(object({
filter = string
filter_type = string
}))
}))
}))
| `[]` | no | | [scan\_images\_on\_push](#input\_scan\_images\_on\_push) | Indicates whether images are scanned after being pushed to the repository (true) or not (false) | `bool` | `true` | no | | [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | | [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | diff --git a/docs/terraform.md b/docs/terraform.md index 1044b87..98a949d 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -23,6 +23,7 @@ | Name | Type | |------|------| | [aws_ecr_lifecycle_policy.name](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_lifecycle_policy) | resource | +| [aws_ecr_replication_configuration.replication_configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_replication_configuration) | resource | | [aws_ecr_repository.name](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | | [aws_ecr_repository_policy.name](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_policy) | resource | | [aws_iam_policy_document.empty](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | @@ -72,6 +73,7 @@ | [principals\_readonly\_access](#input\_principals\_readonly\_access) | Principal ARNs to provide with readonly access to the ECR | `list(string)` | `[]` | no | | [protected\_tags](#input\_protected\_tags) | Name of image tags prefixes that should not be destroyed. Useful if you tag images with names like `dev`, `staging`, and `prod` | `set(string)` | `[]` | no | | [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| [replication\_configurations](#input\_replication\_configurations) | Replication configuration for a registry. See [Replication Configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_replication_configuration#replication-configuration). |
list(object({
rules = list(object({ # Maximum 10
destinations = list(object({ # Maximum 25
region = string
registry_id = string
}))
repository_filters = list(object({
filter = string
filter_type = string
}))
}))
}))
| `[]` | no | | [scan\_images\_on\_push](#input\_scan\_images\_on\_push) | Indicates whether images are scanned after being pushed to the repository (true) or not (false) | `bool` | `true` | no | | [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | | [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | diff --git a/examples/replication-repo/main.tf b/examples/replication-repo/main.tf new file mode 100644 index 0000000..c800ba3 --- /dev/null +++ b/examples/replication-repo/main.tf @@ -0,0 +1,39 @@ +provider "aws" { + region = "us-east-2" +} + +data "aws_caller_identity" "current" {} + +module "ecr" { + source = "../../" + namespace = "eg" + stage = "dev" + name = "app" + use_fullname = false + image_names = ["redis"] + + replication_configurations = [ + { + rules = [ + { + destinations = [ + { + region = "us-east-1" + registry_id = data.aws_caller_identity.current.account_id + }, + { + region = "eu-west-1" + registry_id = data.aws_caller_identity.current.account_id + } + ] + repository_filters = [ + { + filter = "redis" + filter_type = "PREFIX_MATCH" + } + ] + } + ] + } + ] +} diff --git a/examples/replication-repo/outputs.tf b/examples/replication-repo/outputs.tf new file mode 100644 index 0000000..1b424ad --- /dev/null +++ b/examples/replication-repo/outputs.tf @@ -0,0 +1,9 @@ +output "repository_id_map" { + value = module.ecr.repository_arn_map + description = "Repository id map" +} + +output "repository_url_map" { + value = module.ecr.repository_url_map + description = "Repository url map" +} diff --git a/examples/replication-repo/versions.tf b/examples/replication-repo/versions.tf new file mode 100644 index 0000000..d280c3a --- /dev/null +++ b/examples/replication-repo/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.3" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.22.0" + } + } +} diff --git a/main.tf b/main.tf index d320ea5..8728f3a 100644 --- a/main.tf +++ b/main.tf @@ -342,3 +342,31 @@ resource "aws_ecr_repository_policy" "name" { repository = aws_ecr_repository.name[each.value].name policy = data.aws_iam_policy_document.resource[each.value].json } + +resource "aws_ecr_replication_configuration" "replication_configuration" { + count = module.this.enabled && length(var.replication_configurations) > 0 ? 1 : 0 + dynamic "replication_configuration" { + for_each = var.replication_configurations + content { + dynamic "rule" { + for_each = replication_configuration.value.rules + content { + dynamic "destination" { + for_each = rule.value.destinations + content { + region = destination.value.region + registry_id = destination.value.registry_id + } + } + dynamic "repository_filter" { + for_each = rule.value.repository_filters + content { + filter = repository_filter.value.filter + filter_type = repository_filter.value.filter_type + } + } + } + } + } + } +} diff --git a/variables.tf b/variables.tf index 132ad0a..4917bfa 100644 --- a/variables.tf +++ b/variables.tf @@ -84,6 +84,24 @@ variable "force_delete" { description = "Whether to delete the repository even if it contains images" default = false } + +variable "replication_configurations" { + description = "Replication configuration for a registry. See [Replication Configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_replication_configuration#replication-configuration)." + type = list(object({ + rules = list(object({ # Maximum 10 + destinations = list(object({ # Maximum 25 + region = string + registry_id = string + })) + repository_filters = list(object({ + filter = string + filter_type = string + })) + })) + })) + default = [] +} + variable "organizations_readonly_access" { type = list(string) description = "Organization IDs to provide with readonly access to the ECR."