Skip to content

feat!: Tag Mutability Exclusion Filters and AWS Provider MSV 6 / Terraform MSV 1.5.7 #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,14 @@ Examples codified under the [`examples`](https://github.com/terraform-aws-module

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

## Providers

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

## Modules

Expand Down Expand Up @@ -236,22 +236,24 @@ No modules.
| <a name="input_create_repository"></a> [create\_repository](#input\_create\_repository) | Determines whether a repository will be created | `bool` | `true` | no |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <a name="input_registry_policy"></a> [registry\_policy](#input\_registry\_policy) | The policy document. This is a JSON formatted string | `string` | `null` | no |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <a name="input_repository_name"></a> [repository\_name](#input\_repository\_name) | The name of the repository | `string` | `""` | no |
| <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 |
| <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 |
| <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 |
| <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 |
| <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 |
| <a name="input_repository_type"></a> [repository\_type](#input\_repository\_type) | The type of repository to create. Either `public` or `private` | `string` | `"private"` | no |
Expand Down
6 changes: 3 additions & 3 deletions examples/complete/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ Note that this example may create resources which will incur monetary charges on

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

## Providers

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

## Modules

Expand Down
17 changes: 17 additions & 0 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ module "ecr" {

repository_force_delete = true

repository_image_tag_mutability = "IMMUTABLE_WITH_EXCLUSION"

repository_image_tag_mutability_exclusion_filter = [
{
filter = "latest*"
filter_type = "WILDCARD"
},
{
filter = "dev-*"
filter_type = "WILDCARD"
},
{
filter = "qa-*"
filter_type = "WILDCARD"
}
]

tags = local.tags
}

Expand Down
4 changes: 2 additions & 2 deletions examples/complete/versions.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
terraform {
required_version = ">= 1.0"
required_version = ">= 1.5.7"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.93"
version = ">= 6.8"
}
}
}
6 changes: 3 additions & 3 deletions examples/repository-template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ If you validate the example by using the pull-through cache, you will need to ma

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

## Providers

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

## Modules

Expand Down
4 changes: 2 additions & 2 deletions examples/repository-template/versions.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
terraform {
required_version = ">= 1.0"
required_version = ">= 1.5.7"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.93"
version = ">= 6.8"
}
}
}
56 changes: 38 additions & 18 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -129,18 +129,18 @@ data "aws_iam_policy_document" "repository" {
}

dynamic "statement" {
for_each = var.repository_policy_statements
for_each = var.repository_policy_statements != null ? var.repository_policy_statements : {}

content {
sid = try(statement.value.sid, null)
actions = try(statement.value.actions, null)
not_actions = try(statement.value.not_actions, null)
effect = try(statement.value.effect, null)
resources = try(statement.value.resources, null)
not_resources = try(statement.value.not_resources, null)
sid = statement.value.sid
actions = statement.value.actions
not_actions = statement.value.not_actions
effect = statement.value.effect
resources = statement.value.resources
not_resources = statement.value.not_resources

dynamic "principals" {
for_each = try(statement.value.principals, [])
for_each = statement.value.principals != null ? statement.value.principals : []

content {
type = principals.value.type
Expand All @@ -149,7 +149,7 @@ data "aws_iam_policy_document" "repository" {
}

dynamic "not_principals" {
for_each = try(statement.value.not_principals, [])
for_each = statement.value.not_principals != null ? statement.value.not_principals : []

content {
type = not_principals.value.type
Expand All @@ -158,7 +158,7 @@ data "aws_iam_policy_document" "repository" {
}

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

content {
test = condition.value.test
Expand Down Expand Up @@ -191,6 +191,16 @@ resource "aws_ecr_repository" "this" {
scan_on_push = var.repository_image_scan_on_push
}

dynamic "image_tag_mutability_exclusion_filter" {
for_each = var.repository_image_tag_mutability_exclusion_filter != null ? var.repository_image_tag_mutability_exclusion_filter : []
content {
filter = image_tag_mutability_exclusion_filter.value.filter
filter_type = image_tag_mutability_exclusion_filter.value.filter_type
}
}

region = var.region

tags = var.tags
}

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

repository = aws_ecr_repository.this[0].name
policy = var.create_repository_policy ? data.aws_iam_policy_document.repository[0].json : var.repository_policy
region = var.region
}

################################################################################
Expand All @@ -214,6 +225,7 @@ resource "aws_ecr_lifecycle_policy" "this" {

repository = aws_ecr_repository.this[0].name
policy = var.repository_lifecycle_policy
region = var.region
}

################################################################################
Expand All @@ -226,7 +238,7 @@ resource "aws_ecrpublic_repository" "this" {
repository_name = var.repository_name

dynamic "catalog_data" {
for_each = length(var.public_repository_catalog_data) > 0 ? [var.public_repository_catalog_data] : []
for_each = var.public_repository_catalog_data != null ? [var.public_repository_catalog_data] : []

content {
about_text = try(catalog_data.value.about_text, null)
Expand All @@ -238,6 +250,8 @@ resource "aws_ecrpublic_repository" "this" {
}
}

region = var.region

tags = var.tags
}

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

repository_name = aws_ecrpublic_repository.this[0].repository_name
policy = var.create_repository_policy ? data.aws_iam_policy_document.repository[0].json : var.repository_policy
region = var.region
}

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

policy = var.registry_policy
region = var.region
}

################################################################################
Expand All @@ -271,9 +287,10 @@ resource "aws_ecr_pull_through_cache_rule" "this" {

ecr_repository_prefix = each.value.ecr_repository_prefix
upstream_registry_url = each.value.upstream_registry_url
credential_arn = try(each.value.credential_arn, null)
custom_role_arn = try(each.value.custom_role_arn, null)
upstream_repository_prefix = try(each.value.upstream_repository_prefix, null)
credential_arn = each.value.credential_arn
custom_role_arn = each.value.custom_role_arn
upstream_repository_prefix = each.value.upstream_repository_prefix
region = each.value.region != null ? each.value.region : var.region
}

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

scan_type = var.registry_scan_type
region = var.region

dynamic "rule" {
for_each = var.registry_scan_rules
for_each = var.registry_scan_rules != null ? var.registry_scan_rules : []

content {
scan_frequency = rule.value.scan_frequency
Expand All @@ -296,7 +314,7 @@ resource "aws_ecr_registry_scanning_configuration" "this" {

content {
filter = repository_filter.value.filter
filter_type = try(repository_filter.value.filter_type, "WILDCARD")
filter_type = repository_filter.value.filter_type != null ? repository_filter.value.filter_type : "WILDCARD"
}
}
}
Expand All @@ -310,10 +328,12 @@ resource "aws_ecr_registry_scanning_configuration" "this" {
resource "aws_ecr_replication_configuration" "this" {
count = var.create && var.create_registry_replication_configuration ? 1 : 0

region = var.region

replication_configuration {

dynamic "rule" {
for_each = var.registry_replication_rules
for_each = var.registry_replication_rules != null ? var.registry_replication_rules : []

content {
dynamic "destination" {
Expand All @@ -326,7 +346,7 @@ resource "aws_ecr_replication_configuration" "this" {
}

dynamic "repository_filter" {
for_each = try(rule.value.repository_filters, [])
for_each = rule.value.repository_filters != null ? rule.value.repository_filters : []

content {
filter = repository_filter.value.filter
Expand Down
Loading