Skip to content

Commit 215ddda

Browse files
authored
Merge pull request #65 from sparkfabrik/0000-fix-policy
refs #0000 Fix ECR policy
2 parents f492095 + 4eb57fc commit 215ddda

File tree

4 files changed

+77
-35
lines changed

4 files changed

+77
-35
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [4.6.0] - 2025-05-30
9+
10+
### Added
11+
12+
- Add variables for ECR lifecycle policy configuration and tag protection
13+
14+
### Fixed
15+
16+
- ECR Lifecycle policy rules now properly handle tag protection patterns
17+
- Fixed ECR lifecycle policy application to respect excluded repositories
18+
819
## [4.5.0] - 2025-05-16
920

1021
### Added

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ The patches will add the special toleration to the resources, allowing them to b
7171
| <a name="input_cluster_version"></a> [cluster\_version](#input\_cluster\_version) | The Kubernetes version to use for the EKS cluster. | `string` | `"1.24"` | no |
7272
| <a name="input_customer_application"></a> [customer\_application](#input\_customer\_application) | Customer application | <pre>map(object({<br> namespaces = list(string)<br> repositories = optional(list(string), [])<br> }))</pre> | n/a | yes |
7373
| <a name="input_developer_users"></a> [developer\_users](#input\_developer\_users) | n/a | `list(any)` | n/a | yes |
74+
| <a name="input_ecr_enable_lifecycle_policy"></a> [ecr\_enable\_lifecycle\_policy](#input\_ecr\_enable\_lifecycle\_policy) | Enable lifecycle policy for ECR repositories. | `bool` | `true` | no |
75+
| <a name="input_ecr_lifecycle_expiration_days"></a> [ecr\_lifecycle\_expiration\_days](#input\_ecr\_lifecycle\_expiration\_days) | Number of days after which untagged images expire. Only applies if enable\_ecr\_lifecycle\_policy is true. | `number` | `30` | no |
76+
| <a name="input_ecr_lifecycle_policy_excluded_repositories"></a> [ecr\_lifecycle\_policy\_excluded\_repositories](#input\_ecr\_lifecycle\_policy\_excluded\_repositories) | A list of ECR repository names to exclude from the default lifecycle policy. | `list(string)` | `[]` | no |
77+
| <a name="input_ecr_protected_tag_patterns"></a> [ecr\_protected\_tag\_patterns](#input\_ecr\_protected\_tag\_patterns) | List of tag patterns to keep in ECR lifecycle policy. | `list(string)` | <pre>[<br> "latest",<br> "main",<br> "master",<br> "stage",<br> "dev*",<br> "review*",<br> "0.*",<br> "1.*",<br> "2.*",<br> "3.*",<br> "4.*",<br> "5.*",<br> "6.*",<br> "7.*",<br> "8.*",<br> "9.*",<br> "v0.*",<br> "v1.*",<br> "v2.*",<br> "v3.*",<br> "v4.*",<br> "v5.*",<br> "v6.*",<br> "v7.*",<br> "v8.*",<br> "v9.*"<br>]</pre> | no |
7478
| <a name="input_eks_managed_node_groups"></a> [eks\_managed\_node\_groups](#input\_eks\_managed\_node\_groups) | Cluster node group | `any` | <pre>{<br> "core_pool": {<br> "desired_size": 2,<br> "instance_types": [<br> "t3.medium"<br> ],<br> "labels": {<br> "Pool": "core"<br> },<br> "max_size": 4,<br> "min_size": 1,<br> "tags": {<br> "Pool": "core"<br> }<br> }<br>}</pre> | no |
7579
| <a name="input_enable_aws_alb_controller"></a> [enable\_aws\_alb\_controller](#input\_enable\_aws\_alb\_controller) | Enable AWS Load Balancer Controller | `bool` | `false` | no |
7680
| <a name="input_enable_aws_ebs_csi_driver"></a> [enable\_aws\_ebs\_csi\_driver](#input\_enable\_aws\_ebs\_csi\_driver) | Enable AWS EBS CSI Driver | `bool` | `true` | no |
@@ -103,7 +107,6 @@ The patches will add the special toleration to the resources, allowing them to b
103107
| <a name="input_private_subnet_ids"></a> [private\_subnet\_ids](#input\_private\_subnet\_ids) | n/a | `list(string)` | n/a | yes |
104108
| <a name="input_project"></a> [project](#input\_project) | Project name | `string` | n/a | yes |
105109
| <a name="input_prometheus_stack_additional_values"></a> [prometheus\_stack\_additional\_values](#input\_prometheus\_stack\_additional\_values) | Additional values for Kube Prometheus Stack | `list(string)` | `[]` | no |
106-
| <a name="input_repository_expiration_days"></a> [repository\_expiration\_days](#input\_repository\_expiration\_days) | Value to set the expiration days for the application repositories, null means no expiration | `number` | `null` | no |
107110
| <a name="input_velero_bucket_expiration_days"></a> [velero\_bucket\_expiration\_days](#input\_velero\_bucket\_expiration\_days) | n/a | `number` | `90` | no |
108111
| <a name="input_velero_bucket_glacier_days"></a> [velero\_bucket\_glacier\_days](#input\_velero\_bucket\_glacier\_days) | n/a | `number` | `60` | no |
109112
| <a name="input_velero_bucket_infrequently_access_days"></a> [velero\_bucket\_infrequently\_access\_days](#input\_velero\_bucket\_infrequently\_access\_days) | n/a | `number` | `30` | no |

ecr.tf

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,39 @@ locals {
99
repo_name = repo
1010
}
1111
]]))
12+
13+
# Generate individual rules for each tag pattern.
14+
# Please note that tagPatternList is an AND condition in AWS ECR lifecycle policy
15+
tag_protection_rules = [
16+
for index, pattern in var.ecr_protected_tag_patterns : {
17+
rulePriority = index + 1
18+
description = "Keep images tagged with ${pattern}"
19+
selection = {
20+
tagStatus = "tagged"
21+
tagPatternList = [pattern]
22+
countType = "imageCountMoreThan"
23+
countNumber = 9999
24+
}
25+
action = {
26+
type = "expire"
27+
}
28+
}
29+
]
30+
31+
# Rule to clean up old images
32+
cleanup_rule = {
33+
rulePriority = length(var.ecr_protected_tag_patterns) + 1
34+
description = "Remove images older than ${var.ecr_lifecycle_expiration_days} days"
35+
selection = {
36+
tagStatus = "any"
37+
countType = "sinceImagePushed"
38+
countUnit = "days"
39+
countNumber = var.ecr_lifecycle_expiration_days
40+
}
41+
action = {
42+
type = "expire"
43+
}
44+
}
1245
}
1346

1447
## Create ECR repository
@@ -23,38 +56,14 @@ resource "aws_ecr_repository" "repository" {
2356
}
2457

2558
resource "aws_ecr_lifecycle_policy" "project_image" {
26-
for_each = var.repository_expiration_days != null ? { for entry in local.customer_application_repositories : "${entry.app_name}-${entry.repo_name}" => entry } : {}
59+
for_each = var.ecr_enable_lifecycle_policy ? {
60+
for repo_name, repo_config in aws_ecr_repository.repository : repo_name => repo_config
61+
if !contains(var.ecr_lifecycle_policy_excluded_repositories, repo_name)
62+
} : {}
2763

28-
repository = each.key
64+
repository = each.value.name
2965

3066
policy = jsonencode({
31-
rules = [
32-
{
33-
"rulePriority" : 1,
34-
"description" : "Keep image tagged with main, master, stage, dev*, review*",
35-
"selection" : {
36-
"tagStatus" : "tagged",
37-
"tagPrefixList" : ["main", "master", "stage", "dev*", "review*"],
38-
"countType" : "imageCountMoreThan",
39-
"countNumber" : 9999
40-
},
41-
"action" : {
42-
"type" : "expire"
43-
}
44-
},
45-
{
46-
"rulePriority" : 2,
47-
"description" : "Remove images older than ${var.repository_expiration_days} days",
48-
"selection" : {
49-
"tagStatus" : "any",
50-
"countType" : "sinceImagePushed",
51-
"countUnit" : "days",
52-
"countNumber" : var.repository_expiration_days
53-
},
54-
"action" : {
55-
"type" : "expire"
56-
}
57-
}
58-
]
67+
rules = concat(local.tag_protection_rules, [local.cleanup_rule])
5968
})
6069
}

variables.tf

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,12 +302,31 @@ variable "customer_application" {
302302
}))
303303
}
304304

305-
variable "repository_expiration_days" {
306-
type = number
307-
description = "Repository expiration days, used for lifecycle policy. Null to disable."
308-
default = null
305+
variable "ecr_protected_tag_patterns" {
306+
type = list(string)
307+
description = "List of tag patterns to keep in ECR lifecycle policy."
308+
default = ["latest", "main", "master", "stage", "dev*", "review*", "0.*", "1.*", "2.*", "3.*", "4.*", "5.*", "6.*", "7.*", "8.*", "9.*", "v0.*", "v1.*", "v2.*", "v3.*", "v4.*", "v5.*", "v6.*", "v7.*", "v8.*", "v9.*"]
309309
}
310310

311+
variable "ecr_enable_lifecycle_policy" {
312+
type = bool
313+
description = "Enable lifecycle policy for ECR repositories."
314+
default = true
315+
}
316+
317+
variable "ecr_lifecycle_expiration_days" {
318+
type = number
319+
description = "Number of days after which untagged images expire. Only applies if enable_ecr_lifecycle_policy is true."
320+
default = 30
321+
}
322+
323+
variable "ecr_lifecycle_policy_excluded_repositories" {
324+
description = "A list of ECR repository names to exclude from the default lifecycle policy."
325+
type = list(string)
326+
default = []
327+
}
328+
329+
311330
# Velero
312331
variable "enable_velero" {
313332
type = bool

0 commit comments

Comments
 (0)