Skip to content

Commit 97dab31

Browse files
authored
feat(logging): add ECR logging configuration with CloudWatch integration (#30)
1 parent 8615681 commit 97dab31

File tree

6 files changed

+177
-2
lines changed

6 files changed

+177
-2
lines changed

README.md

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ Check the [examples](examples/) for the **simple** and the **complete** snippet
1010
### Simple example
1111
This example creates an ECR registry using few parameters
1212

13-
```
13+
```hcl
1414
module "ecr" {
15-
1615
source = "lgallard/ecr/aws"
1716
1817
name = "ecr-repo-dev"
@@ -23,10 +22,56 @@ module "ecr" {
2322
Environment = "dev"
2423
Terraform = true
2524
}
25+
}
26+
```
27+
28+
### Complete example with logging
29+
In this example, the registry is defined in detail including CloudWatch logging:
30+
31+
```hcl
32+
module "ecr" {
33+
source = "lgallard/ecr/aws"
34+
35+
name = "ecr-repo-dev"
36+
scan_on_push = true
37+
timeouts_delete = "60m"
38+
image_tag_mutability = "IMMUTABLE"
39+
encryption_type = "KMS"
40+
41+
# Enable CloudWatch logging
42+
enable_logging = true
43+
log_retention_days = 14
44+
45+
// ...rest of configuration...
46+
}
47+
```
48+
49+
### CloudWatch Logging
50+
51+
The module supports sending ECR API actions and image push/pull events to CloudWatch Logs. When enabled:
52+
53+
- Creates a CloudWatch Log Group `/aws/ecr/{repository-name}`
54+
- Sets up necessary IAM roles and policies for ECR to write logs
55+
- Configurable log retention period (default: 30 days)
2656

57+
To enable logging:
58+
59+
```hcl
60+
module "ecr" {
61+
source = "lgallard/ecr/aws"
62+
63+
name = "ecr-repo-dev"
64+
enable_logging = true
65+
66+
# Optional: customize retention period (in days)
67+
log_retention_days = 14 # Valid values: 0,1,3,5,7,14,30,60,90,120,150,180,365,400,545,731,1827,3653
2768
}
2869
```
2970

71+
The module outputs logging-related ARNs:
72+
- `cloudwatch_log_group_arn` - The ARN of the CloudWatch Log Group
73+
- `logging_role_arn` - The ARN of the IAM role used for logging
74+
3075
### Complete example
3176
In this example the register is defined in detailed.
3277

@@ -192,6 +237,8 @@ No modules.
192237
| <a name="input_tags"></a> [tags](#input\_tags) | A map of tags to assign to all resources created by this module.<br/>Tags are key-value pairs that help you manage, identify, organize, search for and filter resources.<br/>Example: { Environment = "Production", Owner = "Team" } | `map(string)` | `{}` | no |
193238
| <a name="input_timeouts"></a> [timeouts](#input\_timeouts) | Timeout configuration for repository operations.<br/>Specify as an object with a 'delete' key containing a duration string (e.g. "20m").<br/>Example: { delete = "20m" } | <pre>object({<br/> delete = optional(string)<br/> })</pre> | `{}` | no |
194239
| <a name="input_timeouts_delete"></a> [timeouts\_delete](#input\_timeouts\_delete) | Deprecated: Use timeouts = { delete = "duration" } instead.<br/>How long to wait for a repository to be deleted.<br/>Specify as a duration string, e.g. "20m" for 20 minutes. | `string` | `null` | no |
240+
| <a name="input_enable_logging"></a> [enable\_logging](#input\_enable\_logging) | Whether to enable CloudWatch logging for the repository.<br/>When set to true, logs for ECR API actions and image push/pull events will be sent to CloudWatch Logs.<br/>Defaults to false to disable logging. | `bool` | `false` | no |
241+
| <a name="input_log_retention_days"></a> [log\_retention\_days](#input\_log\_retention\_days) | The number of days to retain logs in the CloudWatch Log Group.<br/>Valid values: 0,1,3,5,7,14,30,60,90,120,150,180,365,400,545,731,1827,3653.<br/>Defaults to 30 days. | `number` | `30` | no |
195242

196243
## Outputs
197244

@@ -202,4 +249,6 @@ No modules.
202249
| <a name="output_repository_arn"></a> [repository\_arn](#output\_repository\_arn) | ARN of the ECR repository |
203250
| <a name="output_repository_name"></a> [repository\_name](#output\_repository\_name) | Name of the ECR repository |
204251
| <a name="output_repository_url"></a> [repository\_url](#output\_repository\_url) | URL of the ECR repository |
252+
| <a name="output_cloudwatch_log_group_arn"></a> [cloudwatch\_log\_group\_arn](#output\_cloudwatch\_log\_group\_arn) | The ARN of the CloudWatch Log Group created for logging. |
253+
| <a name="output_logging_role_arn"></a> [logging\_role\_arn](#output\_logging\_role\_arn) | The ARN of the IAM role used for logging. |
205254
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

examples/complete/main.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ module "ecr" {
99
image_tag_mutability = "IMMUTABLE"
1010
force_delete = true
1111
encryption_type = "KMS"
12+
13+
# Enable logging configuration
14+
enable_logging = true
15+
log_retention_days = 14
1216

1317
image_scanning_configuration = {
1418
scan_on_push = true

examples/complete/outputs.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ output "registry_id" {
1919
value = module.ecr.registry_id
2020
}
2121

22+
# Logging outputs
23+
output "ecr_log_group_arn" {
24+
description = "ARN of the CloudWatch Log Group for ECR logs"
25+
value = module.ecr.cloudwatch_log_group_arn
26+
}
27+
28+
output "ecr_logging_role_arn" {
29+
description = "ARN of the IAM role used for ECR logging"
30+
value = module.ecr.logging_role_arn
31+
}
32+
2233
# Protected repository outputs
2334
output "protected_repository_url" {
2435
description = "URL of the protected ECR repository"

main.tf

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,72 @@ resource "aws_kms_alias" "kms_key_alias" {
207207
}
208208
}
209209

210+
# CloudWatch Log Group for ECR logs
211+
resource "aws_cloudwatch_log_group" "ecr_logs" {
212+
count = var.enable_logging ? 1 : 0
213+
name = "/aws/ecr/${var.name}"
214+
retention_in_days = var.log_retention_days
215+
216+
tags = merge(
217+
{
218+
Name = "${var.name}-logs"
219+
ManagedBy = "Terraform"
220+
},
221+
var.tags
222+
)
223+
}
224+
225+
# IAM Role for ECR logging
226+
resource "aws_iam_role" "ecr_logging" {
227+
count = var.enable_logging ? 1 : 0
228+
name = "ecr-logging-${var.name}"
229+
230+
assume_role_policy = jsonencode({
231+
Version = "2012-10-17"
232+
Statement = [
233+
{
234+
Action = "sts:AssumeRole"
235+
Effect = "Allow"
236+
Principal = {
237+
Service = "ecr.amazonaws.com"
238+
}
239+
}
240+
]
241+
})
242+
243+
tags = merge(
244+
{
245+
Name = "${var.name}-logging-role"
246+
ManagedBy = "Terraform"
247+
},
248+
var.tags
249+
)
250+
}
251+
252+
# IAM Policy for ECR logging
253+
resource "aws_iam_role_policy" "ecr_logging" {
254+
count = var.enable_logging ? 1 : 0
255+
name = "ecr-logging-${var.name}"
256+
role = aws_iam_role.ecr_logging[0].id
257+
258+
policy = jsonencode({
259+
Version = "2012-10-17"
260+
Statement = [
261+
{
262+
Effect = "Allow"
263+
Action = [
264+
"logs:CreateLogStream",
265+
"logs:PutLogEvents",
266+
"logs:CreateLogGroup"
267+
]
268+
Resource = [
269+
"${aws_cloudwatch_log_group.ecr_logs[0].arn}:*"
270+
]
271+
}
272+
]
273+
})
274+
}
275+
210276
locals {
211277
# Determine if we need to create a new KMS key
212278
should_create_kms_key = var.encryption_type == "KMS" && var.kms_key == null
@@ -235,4 +301,10 @@ locals {
235301
}] : []
236302
)
237303
)
304+
305+
# Logging configuration
306+
logging_configuration = var.enable_logging ? {
307+
log_group_arn = aws_cloudwatch_log_group.ecr_logs[0].arn
308+
role_arn = aws_iam_role.ecr_logging[0].arn
309+
} : null
238310
}

outputs.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,14 @@ output "kms_key_arn" {
2323
value = local.should_create_kms_key ? aws_kms_key.kms_key[0].arn : var.kms_key
2424
description = "The ARN of the KMS key used for repository encryption."
2525
}
26+
27+
# Logging outputs
28+
output "cloudwatch_log_group_arn" {
29+
description = "The ARN of the CloudWatch Log Group used for ECR logs (if logging is enabled)"
30+
value = try(aws_cloudwatch_log_group.ecr_logs[0].arn, null)
31+
}
32+
33+
output "logging_role_arn" {
34+
description = "The ARN of the IAM role used for ECR logging (if logging is enabled)"
35+
value = try(aws_iam_role.ecr_logging[0].arn, null)
36+
}

variables.tf

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,31 @@ variable "tags" {
181181
type = map(string)
182182
default = {}
183183
}
184+
185+
# ----------------------------------------------------------
186+
# Logging Configuration
187+
# ----------------------------------------------------------
188+
189+
variable "enable_logging" {
190+
description = <<-EOT
191+
Whether to enable CloudWatch logging for the repository.
192+
When enabled, ECR API actions and image push/pull events will be logged to CloudWatch.
193+
Defaults to false.
194+
EOT
195+
type = bool
196+
default = false
197+
}
198+
199+
variable "log_retention_days" {
200+
description = <<-EOT
201+
Number of days to retain ECR logs in CloudWatch.
202+
Only applicable when enable_logging is true.
203+
Defaults to 30 days.
204+
EOT
205+
type = number
206+
default = 30
207+
validation {
208+
condition = contains([0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653], var.log_retention_days)
209+
error_message = "Log retention days must be one of: 0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653."
210+
}
211+
}

0 commit comments

Comments
 (0)