Skip to content

Commit 58028e3

Browse files
authored
feat!: Tag Mutability Exclusion Filters and AWS Provider MSV 6 / Terraform MSV 1.5.7 (#59)
* add tag mutability exclusion filters * revert testing * update terraform msv * add region variables * revert testing * type definitions
1 parent faaf6ef commit 58028e3

File tree

17 files changed

+228
-93
lines changed

17 files changed

+228
-93
lines changed

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,14 @@ Examples codified under the [`examples`](https://github.com/terraform-aws-module
194194

195195
| Name | Version |
196196
|------|---------|
197-
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
198-
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.93 |
197+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.5.7 |
198+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 6.8 |
199199

200200
## Providers
201201

202202
| Name | Version |
203203
|------|---------|
204-
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.93 |
204+
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 6.8 |
205205

206206
## Modules
207207

@@ -236,22 +236,24 @@ No modules.
236236
| <a name="input_create_repository"></a> [create\_repository](#input\_create\_repository) | Determines whether a repository will be created | `bool` | `true` | no |
237237
| <a name="input_create_repository_policy"></a> [create\_repository\_policy](#input\_create\_repository\_policy) | Determines whether a repository policy will be created | `bool` | `true` | no |
238238
| <a name="input_manage_registry_scanning_configuration"></a> [manage\_registry\_scanning\_configuration](#input\_manage\_registry\_scanning\_configuration) | Determines whether the registry scanning configuration will be managed | `bool` | `false` | no |
239-
| <a name="input_public_repository_catalog_data"></a> [public\_repository\_catalog\_data](#input\_public\_repository\_catalog\_data) | Catalog data configuration for the repository | `any` | `{}` | no |
239+
| <a name="input_public_repository_catalog_data"></a> [public\_repository\_catalog\_data](#input\_public\_repository\_catalog\_data) | Catalog data configuration for the repository | <pre>object({<br/> about_text = optional(string)<br/> architectures = optional(list(string))<br/> description = optional(string)<br/> logo_image_blob = optional(string)<br/> operating_systems = optional(list(string))<br/> usage_text = optional(string)<br/> })</pre> | `null` | no |
240+
| <a name="input_region"></a> [region](#input\_region) | Region where this resource will be managed. Defaults to the Region set in the provider configuration. | `string` | `null` | no |
240241
| <a name="input_registry_policy"></a> [registry\_policy](#input\_registry\_policy) | The policy document. This is a JSON formatted string | `string` | `null` | no |
241-
| <a name="input_registry_pull_through_cache_rules"></a> [registry\_pull\_through\_cache\_rules](#input\_registry\_pull\_through\_cache\_rules) | List of pull through cache rules to create | `map(map(string))` | `{}` | no |
242-
| <a name="input_registry_replication_rules"></a> [registry\_replication\_rules](#input\_registry\_replication\_rules) | The replication rules for a replication configuration. A maximum of 10 are allowed | `any` | `[]` | no |
243-
| <a name="input_registry_scan_rules"></a> [registry\_scan\_rules](#input\_registry\_scan\_rules) | One or multiple blocks specifying scanning rules to determine which repository filters are used and at what frequency scanning will occur | `any` | `[]` | no |
242+
| <a name="input_registry_pull_through_cache_rules"></a> [registry\_pull\_through\_cache\_rules](#input\_registry\_pull\_through\_cache\_rules) | List of pull through cache rules to create | <pre>map(object({<br/> ecr_repository_prefix = string<br/> upstream_registry_url = string<br/> credential_arn = optional(string)<br/> custom_role_arn = optional(string)<br/> upstream_repository_prefix = optional(string)<br/> region = optional(string)<br/> }))</pre> | `{}` | no |
243+
| <a name="input_registry_replication_rules"></a> [registry\_replication\_rules](#input\_registry\_replication\_rules) | The replication rules for a replication configuration. A maximum of 10 are allowed | <pre>list(object({<br/> destinations = list(object({<br/> region = string<br/> registry_id = string<br/> }))<br/> repository_filters = optional(list(object({<br/> filter = string<br/> filter_type = string<br/> })))<br/> }))</pre> | `null` | no |
244+
| <a name="input_registry_scan_rules"></a> [registry\_scan\_rules](#input\_registry\_scan\_rules) | One or multiple blocks specifying scanning rules to determine which repository filters are used and at what frequency scanning will occur | <pre>list(object({<br/> scan_frequency = string<br/> filter = list(object({<br/> filter = string<br/> filter_type = optional(string)<br/> }))<br/> }))</pre> | `null` | no |
244245
| <a name="input_registry_scan_type"></a> [registry\_scan\_type](#input\_registry\_scan\_type) | the scanning type to set for the registry. Can be either `ENHANCED` or `BASIC` | `string` | `"ENHANCED"` | no |
245246
| <a name="input_repository_encryption_type"></a> [repository\_encryption\_type](#input\_repository\_encryption\_type) | The encryption type for the repository. Must be one of: `KMS` or `AES256`. Defaults to `AES256` | `string` | `null` | no |
246247
| <a name="input_repository_force_delete"></a> [repository\_force\_delete](#input\_repository\_force\_delete) | If `true`, will delete the repository even if it contains images. Defaults to `false` | `bool` | `null` | no |
247248
| <a name="input_repository_image_scan_on_push"></a> [repository\_image\_scan\_on\_push](#input\_repository\_image\_scan\_on\_push) | Indicates whether images are scanned after being pushed to the repository (`true`) or not scanned (`false`) | `bool` | `true` | no |
248249
| <a name="input_repository_image_tag_mutability"></a> [repository\_image\_tag\_mutability](#input\_repository\_image\_tag\_mutability) | The tag mutability setting for the repository. Must be one of: `MUTABLE` or `IMMUTABLE`. Defaults to `IMMUTABLE` | `string` | `"IMMUTABLE"` | no |
250+
| <a name="input_repository_image_tag_mutability_exclusion_filter"></a> [repository\_image\_tag\_mutability\_exclusion\_filter](#input\_repository\_image\_tag\_mutability\_exclusion\_filter) | Configuration block that defines filters to specify which image tags can override the default tag mutability setting. Only applicable when image\_tag\_mutability is set to IMMUTABLE\_WITH\_EXCLUSION or MUTABLE\_WITH\_EXCLUSION. | <pre>list(object({<br/> filter = string<br/> filter_type = string<br/> }))</pre> | `null` | no |
249251
| <a name="input_repository_kms_key"></a> [repository\_kms\_key](#input\_repository\_kms\_key) | The ARN of the KMS key to use when encryption\_type is `KMS`. If not specified, uses the default AWS managed key for ECR | `string` | `null` | no |
250252
| <a name="input_repository_lambda_read_access_arns"></a> [repository\_lambda\_read\_access\_arns](#input\_repository\_lambda\_read\_access\_arns) | The ARNs of the Lambda service roles that have read access to the repository | `list(string)` | `[]` | no |
251253
| <a name="input_repository_lifecycle_policy"></a> [repository\_lifecycle\_policy](#input\_repository\_lifecycle\_policy) | The policy document. This is a JSON formatted string. See more details about [Policy Parameters](http://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html#lifecycle_policy_parameters) in the official AWS docs | `string` | `""` | no |
252254
| <a name="input_repository_name"></a> [repository\_name](#input\_repository\_name) | The name of the repository | `string` | `""` | no |
253255
| <a name="input_repository_policy"></a> [repository\_policy](#input\_repository\_policy) | The JSON policy to apply to the repository. If not specified, uses the default policy | `string` | `null` | no |
254-
| <a name="input_repository_policy_statements"></a> [repository\_policy\_statements](#input\_repository\_policy\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage | `any` | `{}` | no |
256+
| <a name="input_repository_policy_statements"></a> [repository\_policy\_statements](#input\_repository\_policy\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage | <pre>map(object({<br/> sid = optional(string)<br/> actions = optional(list(string))<br/> not_actions = optional(list(string))<br/> effect = optional(string)<br/> resources = optional(list(string))<br/> not_resources = optional(list(string))<br/> principals = optional(list(object({<br/> type = string<br/> identifiers = list(string)<br/> })))<br/> not_principals = optional(list(object({<br/> type = string<br/> identifiers = list(string)<br/> })))<br/> conditions = optional(list(object({<br/> test = string<br/> values = list(string)<br/> variable = string<br/> })))<br/> }))</pre> | `null` | no |
255257
| <a name="input_repository_read_access_arns"></a> [repository\_read\_access\_arns](#input\_repository\_read\_access\_arns) | The ARNs of the IAM users/roles that have read access to the repository | `list(string)` | `[]` | no |
256258
| <a name="input_repository_read_write_access_arns"></a> [repository\_read\_write\_access\_arns](#input\_repository\_read\_write\_access\_arns) | The ARNs of the IAM users/roles that have read/write access to the repository | `list(string)` | `[]` | no |
257259
| <a name="input_repository_type"></a> [repository\_type](#input\_repository\_type) | The type of repository to create. Either `public` or `private` | `string` | `"private"` | no |

examples/complete/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ Note that this example may create resources which will incur monetary charges on
2727

2828
| Name | Version |
2929
|------|---------|
30-
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
31-
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.93 |
30+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.5.7 |
31+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 6.8 |
3232

3333
## Providers
3434

3535
| Name | Version |
3636
|------|---------|
37-
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.93 |
37+
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 6.8 |
3838

3939
## Modules
4040

examples/complete/main.tf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,23 @@ module "ecr" {
5454

5555
repository_force_delete = true
5656

57+
repository_image_tag_mutability = "IMMUTABLE_WITH_EXCLUSION"
58+
59+
repository_image_tag_mutability_exclusion_filter = [
60+
{
61+
filter = "latest*"
62+
filter_type = "WILDCARD"
63+
},
64+
{
65+
filter = "dev-*"
66+
filter_type = "WILDCARD"
67+
},
68+
{
69+
filter = "qa-*"
70+
filter_type = "WILDCARD"
71+
}
72+
]
73+
5774
tags = local.tags
5875
}
5976

examples/complete/versions.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
terraform {
2-
required_version = ">= 1.0"
2+
required_version = ">= 1.5.7"
33

44
required_providers {
55
aws = {
66
source = "hashicorp/aws"
7-
version = ">= 5.93"
7+
version = ">= 6.8"
88
}
99
}
1010
}

examples/repository-template/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ If you validate the example by using the pull-through cache, you will need to ma
2121

2222
| Name | Version |
2323
|------|---------|
24-
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
25-
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.93 |
24+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.5.7 |
25+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 6.8 |
2626

2727
## Providers
2828

2929
| Name | Version |
3030
|------|---------|
31-
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.93 |
31+
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 6.8 |
3232

3333
## Modules
3434

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
terraform {
2-
required_version = ">= 1.0"
2+
required_version = ">= 1.5.7"
33

44
required_providers {
55
aws = {
66
source = "hashicorp/aws"
7-
version = ">= 5.93"
7+
version = ">= 6.8"
88
}
99
}
1010
}

main.tf

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -129,18 +129,18 @@ data "aws_iam_policy_document" "repository" {
129129
}
130130

131131
dynamic "statement" {
132-
for_each = var.repository_policy_statements
132+
for_each = var.repository_policy_statements != null ? var.repository_policy_statements : {}
133133

134134
content {
135-
sid = try(statement.value.sid, null)
136-
actions = try(statement.value.actions, null)
137-
not_actions = try(statement.value.not_actions, null)
138-
effect = try(statement.value.effect, null)
139-
resources = try(statement.value.resources, null)
140-
not_resources = try(statement.value.not_resources, null)
135+
sid = statement.value.sid
136+
actions = statement.value.actions
137+
not_actions = statement.value.not_actions
138+
effect = statement.value.effect
139+
resources = statement.value.resources
140+
not_resources = statement.value.not_resources
141141

142142
dynamic "principals" {
143-
for_each = try(statement.value.principals, [])
143+
for_each = statement.value.principals != null ? statement.value.principals : []
144144

145145
content {
146146
type = principals.value.type
@@ -149,7 +149,7 @@ data "aws_iam_policy_document" "repository" {
149149
}
150150

151151
dynamic "not_principals" {
152-
for_each = try(statement.value.not_principals, [])
152+
for_each = statement.value.not_principals != null ? statement.value.not_principals : []
153153

154154
content {
155155
type = not_principals.value.type
@@ -158,7 +158,7 @@ data "aws_iam_policy_document" "repository" {
158158
}
159159

160160
dynamic "condition" {
161-
for_each = try(statement.value.conditions, [])
161+
for_each = statement.value.conditions != null ? statement.value.condition : []
162162

163163
content {
164164
test = condition.value.test
@@ -191,6 +191,16 @@ resource "aws_ecr_repository" "this" {
191191
scan_on_push = var.repository_image_scan_on_push
192192
}
193193

194+
dynamic "image_tag_mutability_exclusion_filter" {
195+
for_each = var.repository_image_tag_mutability_exclusion_filter != null ? var.repository_image_tag_mutability_exclusion_filter : []
196+
content {
197+
filter = image_tag_mutability_exclusion_filter.value.filter
198+
filter_type = image_tag_mutability_exclusion_filter.value.filter_type
199+
}
200+
}
201+
202+
region = var.region
203+
194204
tags = var.tags
195205
}
196206

@@ -203,6 +213,7 @@ resource "aws_ecr_repository_policy" "this" {
203213

204214
repository = aws_ecr_repository.this[0].name
205215
policy = var.create_repository_policy ? data.aws_iam_policy_document.repository[0].json : var.repository_policy
216+
region = var.region
206217
}
207218

208219
################################################################################
@@ -214,6 +225,7 @@ resource "aws_ecr_lifecycle_policy" "this" {
214225

215226
repository = aws_ecr_repository.this[0].name
216227
policy = var.repository_lifecycle_policy
228+
region = var.region
217229
}
218230

219231
################################################################################
@@ -226,7 +238,7 @@ resource "aws_ecrpublic_repository" "this" {
226238
repository_name = var.repository_name
227239

228240
dynamic "catalog_data" {
229-
for_each = length(var.public_repository_catalog_data) > 0 ? [var.public_repository_catalog_data] : []
241+
for_each = var.public_repository_catalog_data != null ? [var.public_repository_catalog_data] : []
230242

231243
content {
232244
about_text = try(catalog_data.value.about_text, null)
@@ -238,6 +250,8 @@ resource "aws_ecrpublic_repository" "this" {
238250
}
239251
}
240252

253+
region = var.region
254+
241255
tags = var.tags
242256
}
243257

@@ -250,6 +264,7 @@ resource "aws_ecrpublic_repository_policy" "example" {
250264

251265
repository_name = aws_ecrpublic_repository.this[0].repository_name
252266
policy = var.create_repository_policy ? data.aws_iam_policy_document.repository[0].json : var.repository_policy
267+
region = var.region
253268
}
254269

255270
################################################################################
@@ -260,6 +275,7 @@ resource "aws_ecr_registry_policy" "this" {
260275
count = var.create && var.create_registry_policy ? 1 : 0
261276

262277
policy = var.registry_policy
278+
region = var.region
263279
}
264280

265281
################################################################################
@@ -271,9 +287,10 @@ resource "aws_ecr_pull_through_cache_rule" "this" {
271287

272288
ecr_repository_prefix = each.value.ecr_repository_prefix
273289
upstream_registry_url = each.value.upstream_registry_url
274-
credential_arn = try(each.value.credential_arn, null)
275-
custom_role_arn = try(each.value.custom_role_arn, null)
276-
upstream_repository_prefix = try(each.value.upstream_repository_prefix, null)
290+
credential_arn = each.value.credential_arn
291+
custom_role_arn = each.value.custom_role_arn
292+
upstream_repository_prefix = each.value.upstream_repository_prefix
293+
region = each.value.region != null ? each.value.region : var.region
277294
}
278295

279296
################################################################################
@@ -284,9 +301,10 @@ resource "aws_ecr_registry_scanning_configuration" "this" {
284301
count = var.create && var.manage_registry_scanning_configuration ? 1 : 0
285302

286303
scan_type = var.registry_scan_type
304+
region = var.region
287305

288306
dynamic "rule" {
289-
for_each = var.registry_scan_rules
307+
for_each = var.registry_scan_rules != null ? var.registry_scan_rules : []
290308

291309
content {
292310
scan_frequency = rule.value.scan_frequency
@@ -296,7 +314,7 @@ resource "aws_ecr_registry_scanning_configuration" "this" {
296314

297315
content {
298316
filter = repository_filter.value.filter
299-
filter_type = try(repository_filter.value.filter_type, "WILDCARD")
317+
filter_type = repository_filter.value.filter_type != null ? repository_filter.value.filter_type : "WILDCARD"
300318
}
301319
}
302320
}
@@ -310,10 +328,12 @@ resource "aws_ecr_registry_scanning_configuration" "this" {
310328
resource "aws_ecr_replication_configuration" "this" {
311329
count = var.create && var.create_registry_replication_configuration ? 1 : 0
312330

331+
region = var.region
332+
313333
replication_configuration {
314334

315335
dynamic "rule" {
316-
for_each = var.registry_replication_rules
336+
for_each = var.registry_replication_rules != null ? var.registry_replication_rules : []
317337

318338
content {
319339
dynamic "destination" {
@@ -326,7 +346,7 @@ resource "aws_ecr_replication_configuration" "this" {
326346
}
327347

328348
dynamic "repository_filter" {
329-
for_each = try(rule.value.repository_filters, [])
349+
for_each = rule.value.repository_filters != null ? rule.value.repository_filters : []
330350

331351
content {
332352
filter = repository_filter.value.filter

0 commit comments

Comments
 (0)