From 05bbc4d3fa22a5288189d3c9085d24f0c6f1400b Mon Sep 17 00:00:00 2001 From: jamesthompson26-nhs Date: Tue, 10 Feb 2026 09:44:35 +0000 Subject: [PATCH 1/5] CCM-14149: Support Container Based Lambdas --- infrastructure/modules/lambda/README.md | 9 ++-- .../lambda/data_archive_file_lambda.tf | 1 + .../lambda/data_iam_policy_document_ecr.tf | 14 ++++++ .../modules/lambda/iam_role_policy_ecr.tf | 6 +++ .../modules/lambda/lambda_function.tf | 26 +++++++--- .../modules/lambda/s3_object_lambda.tf | 7 +-- infrastructure/modules/lambda/variables.tf | 50 +++++++++++++++++++ 7 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 infrastructure/modules/lambda/data_iam_policy_document_ecr.tf create mode 100644 infrastructure/modules/lambda/iam_role_policy_ecr.tf diff --git a/infrastructure/modules/lambda/README.md b/infrastructure/modules/lambda/README.md index 44c1fdc..4677e5f 100644 --- a/infrastructure/modules/lambda/README.md +++ b/infrastructure/modules/lambda/README.md @@ -22,11 +22,11 @@ | [filter\_pattern](#input\_filter\_pattern) | Filter pattern to use for the log subscription filter | `string` | `""` | no | | [force\_lambda\_code\_deploy](#input\_force\_lambda\_code\_deploy) | If the lambda package in s3 has the same commit id tag as the terraform build branch, the lambda will not update automatically. Set to True if making changes to Lambda code from on the same commit for example during development | `bool` | `false` | no | | [function\_code\_base\_path](#input\_function\_code\_base\_path) | The base path to the sourcecode directories needed for this lambda | `string` | `"./"` | no | -| [function\_code\_dir](#input\_function\_code\_dir) | The directory for this lambda | `string` | n/a | yes | +| [function\_code\_dir](#input\_function\_code\_dir) | The directory for this lambda (required for Zip) | `string` | `null` | no | | [function\_include\_common](#input\_function\_include\_common) | Include the 'common' lambda module with this lambda | `bool` | `true` | no | | [function\_module\_name](#input\_function\_module\_name) | The name of the function module as used by the lambda handler, e.g. index or exports | `string` | `"index"` | no | | [function\_name](#input\_function\_name) | Base name of this lambda | `string` | n/a | yes | -| [function\_s3\_bucket](#input\_function\_s3\_bucket) | The bucket to upload Lambda packages to | `string` | n/a | yes | +| [function\_s3\_bucket](#input\_function\_s3\_bucket) | The bucket to upload Lambda packages to (required for Zip) | `string` | `null` | no | | [group](#input\_group) | The name of the tfscaffold group | `string` | `null` | no | | [handler\_function\_name](#input\_handler\_function\_name) | The name of the lambda handler function (passed directly to the Lambda's handler option) | `string` | `"handler"` | no | | [iam\_policy\_document](#input\_iam\_policy\_document) | n/a |
object({
body = string
})
| `null` | no | @@ -44,7 +44,10 @@ | [permission\_statements](#input\_permission\_statements) | Statements giving an external source permission to invoke the Lambda function |
list(object({
action = optional(string)
principal = string
source_arn = optional(string)
source_account = optional(string)
statement_id = string
}))
| `[]` | no | | [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes | | [region](#input\_region) | The AWS Region | `string` | n/a | yes | -| [runtime](#input\_runtime) | The runtime to use for the lambda function | `string` | n/a | yes | +| [runtime](#input\_runtime) | The runtime to use for the lambda function (required for Zip) | `string` | `null` | no | +| [package\_type](#input\_package\_type) | Lambda package type: Zip or Image | `string` | `"Zip"` | no | +| [image\_uri](#input\_image\_uri) | ECR image URI for Image-based Lambda | `string` | `null` | no | +| [image\_config](#input\_image\_config) | Optional image configuration for Image-based Lambda |
object({
entry_point = optional(list(string))
command = optional(list(string))
working_directory = optional(string)
})
| `null` | no | | [schedule](#input\_schedule) | The fully qualified Cloudwatch Events schedule for when to run the lambda function, e.g. rate(1 day) or a cron() expression. Default disables all events resources | `string` | `""` | no | | [send\_to\_firehose](#input\_send\_to\_firehose) | Enable sending logs to firehose | `bool` | `true` | no | | [sns\_destination](#input\_sns\_destination) | SNS Topic ARN to be used for on-failure Lambda invocation records | `string` | `null` | no | diff --git a/infrastructure/modules/lambda/data_archive_file_lambda.tf b/infrastructure/modules/lambda/data_archive_file_lambda.tf index a7ad069..f1fd1ba 100644 --- a/infrastructure/modules/lambda/data_archive_file_lambda.tf +++ b/infrastructure/modules/lambda/data_archive_file_lambda.tf @@ -1,4 +1,5 @@ data "archive_file" "lambda" { + count = var.package_type == "Zip" ? 1 : 0 type = "zip" source_dir = "${path.root}/${var.function_code_base_path}/${var.function_code_dir}" diff --git a/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf b/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf new file mode 100644 index 0000000..d102a33 --- /dev/null +++ b/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf @@ -0,0 +1,14 @@ +data "aws_iam_policy_document" "ecr" { + statement { + effect = "Allow" + + actions = [ + "ecr:GetAuthorizationToken", + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer", + "ecr:BatchCheckLayerAvailability", + ] + + resources = ["*"] + } +} \ No newline at end of file diff --git a/infrastructure/modules/lambda/iam_role_policy_ecr.tf b/infrastructure/modules/lambda/iam_role_policy_ecr.tf new file mode 100644 index 0000000..1fc3edf --- /dev/null +++ b/infrastructure/modules/lambda/iam_role_policy_ecr.tf @@ -0,0 +1,6 @@ +resource "aws_iam_role_policy" "ecr" { + count = var.package_type == "Image" ? 1 : 0 + name = "${local.csi}-ecr" + role = aws_iam_role.main.id + policy = data.aws_iam_policy_document.ecr.json +} \ No newline at end of file diff --git a/infrastructure/modules/lambda/lambda_function.tf b/infrastructure/modules/lambda/lambda_function.tf index d088acd..d6fc380 100644 --- a/infrastructure/modules/lambda/lambda_function.tf +++ b/infrastructure/modules/lambda/lambda_function.tf @@ -2,15 +2,27 @@ resource "aws_lambda_function" "main" { description = var.description function_name = local.csi role = aws_iam_role.main.arn - handler = "${var.function_module_name}.${var.handler_function_name}" - runtime = var.runtime + handler = var.package_type == "Zip" ? "${var.function_module_name}.${var.handler_function_name}" : null + runtime = var.package_type == "Zip" ? var.runtime : null + package_type = var.package_type publish = true memory_size = var.memory timeout = var.timeout - s3_bucket = aws_s3_object.lambda.bucket - s3_key = aws_s3_object.lambda.key - s3_object_version = aws_s3_object.lambda.version_id + s3_bucket = var.package_type == "Zip" ? aws_s3_object.lambda[0].bucket : null + s3_key = var.package_type == "Zip" ? aws_s3_object.lambda[0].key : null + s3_object_version = var.package_type == "Zip" ? aws_s3_object.lambda[0].version_id : null + + image_uri = var.package_type == "Image" ? var.image_uri : null + + dynamic "image_config" { + for_each = var.package_type == "Image" && var.image_config != null ? [1] : [] + content { + entry_point = try(var.image_config.entry_point, null) + command = try(var.image_config.command, null) + working_directory = try(var.image_config.working_directory, null) + } + } logging_config { application_log_level = var.application_log_level @@ -19,12 +31,12 @@ resource "aws_lambda_function" "main" { system_log_level = var.system_log_level } - layers = compact(concat( + layers = var.package_type == "Zip" ? compact(concat( var.layers, [ var.enable_lambda_insights && var.lambda_at_edge == false ? "arn:aws:lambda:${var.region}:580247275435:layer:LambdaInsightsExtension:53" : null ] - )) + )) : [] environment { variables = var.lambda_env_vars diff --git a/infrastructure/modules/lambda/s3_object_lambda.tf b/infrastructure/modules/lambda/s3_object_lambda.tf index f65d11a..9c829a4 100644 --- a/infrastructure/modules/lambda/s3_object_lambda.tf +++ b/infrastructure/modules/lambda/s3_object_lambda.tf @@ -1,12 +1,13 @@ resource "aws_s3_object" "lambda" { + count = var.package_type == "Zip" ? 1 : 0 bucket = var.function_s3_bucket key = "${local.csi}.zip" - source = data.archive_file.lambda.output_path + source = data.archive_file.lambda[0].output_path - source_hash = var.force_lambda_code_deploy ? data.archive_file.lambda.output_base64sha256 : null + source_hash = var.force_lambda_code_deploy ? data.archive_file.lambda[0].output_base64sha256 : null metadata = { - hash = data.archive_file.lambda.output_base64sha256 + hash = data.archive_file.lambda[0].output_base64sha256 function = local.csi commit = try(data.external.git_commit.result["sha"], "null") } diff --git a/infrastructure/modules/lambda/variables.tf b/infrastructure/modules/lambda/variables.tf index 33dbe13..0844c52 100644 --- a/infrastructure/modules/lambda/variables.tf +++ b/infrastructure/modules/lambda/variables.tf @@ -92,6 +92,44 @@ variable "log_retention_in_days" { variable "runtime" { type = string description = "The runtime to use for the lambda function" + default = null + + validation { + condition = var.package_type != "Zip" || (var.runtime != null && var.runtime != "") + error_message = "runtime must be set when package_type is Zip." + } +} + +variable "package_type" { + type = string + description = "Lambda package type: Zip or Image" + default = "Zip" + + validation { + condition = contains(["Zip", "Image"], var.package_type) + error_message = "package_type must be either Zip or Image." + } +} + +variable "image_uri" { + type = string + description = "ECR image URI for Image-based Lambda" + default = null + + validation { + condition = var.package_type != "Image" || (var.image_uri != null && var.image_uri != "") + error_message = "image_uri must be set when package_type is Image." + } +} + +variable "image_config" { + type = object({ + entry_point = optional(list(string)) + command = optional(list(string)) + working_directory = optional(string) + }) + description = "Optional image configuration for Image-based Lambda" + default = null } variable "schedule" { @@ -122,11 +160,23 @@ variable "function_code_base_path" { variable "function_code_dir" { type = string description = "The directory for this lambda" + default = null + + validation { + condition = var.package_type != "Zip" || (var.function_code_dir != null && var.function_code_dir != "") + error_message = "function_code_dir must be set when package_type is Zip." + } } variable "function_s3_bucket" { type = string description = "The bucket to upload Lambda packages to" + default = null + + validation { + condition = var.package_type != "Zip" || (var.function_s3_bucket != null && var.function_s3_bucket != "") + error_message = "function_s3_bucket must be set when package_type is Zip." + } } variable "function_include_common" { From 6418efcb403dd5ddc070bdddbe7f097ca72e5429 Mon Sep 17 00:00:00 2001 From: jamesthompson26-nhs Date: Tue, 10 Feb 2026 09:53:36 +0000 Subject: [PATCH 2/5] CCM-14149: Support Container Based Lambdas --- .../modules/lambda/data_iam_policy_document_ecr.tf | 13 +++++++++++-- .../modules/lambda/iam_role_policy_ecr.tf | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf b/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf index d102a33..c2bdc5f 100644 --- a/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf +++ b/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf @@ -4,11 +4,20 @@ data "aws_iam_policy_document" "ecr" { actions = [ "ecr:GetAuthorizationToken", + ] + + resources = ["*"] + } + + statement { + effect = "Allow" + + actions = [ "ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer", "ecr:BatchCheckLayerAvailability", ] - resources = ["*"] + resources = ["arn:aws:ecr:${var.region}:${var.aws_account_id}:repository/*"] } -} \ No newline at end of file +} diff --git a/infrastructure/modules/lambda/iam_role_policy_ecr.tf b/infrastructure/modules/lambda/iam_role_policy_ecr.tf index 1fc3edf..2e8dc7b 100644 --- a/infrastructure/modules/lambda/iam_role_policy_ecr.tf +++ b/infrastructure/modules/lambda/iam_role_policy_ecr.tf @@ -3,4 +3,4 @@ resource "aws_iam_role_policy" "ecr" { name = "${local.csi}-ecr" role = aws_iam_role.main.id policy = data.aws_iam_policy_document.ecr.json -} \ No newline at end of file +} From ea2157c8e553ce84a0ed6c6dc88d6d47af492dd4 Mon Sep 17 00:00:00 2001 From: jamesthompson26-nhs Date: Tue, 10 Feb 2026 10:00:01 +0000 Subject: [PATCH 3/5] CCM-14149: Support Container Based Lambdas --- infrastructure/modules/lambda/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/infrastructure/modules/lambda/README.md b/infrastructure/modules/lambda/README.md index 4677e5f..0e7a51b 100644 --- a/infrastructure/modules/lambda/README.md +++ b/infrastructure/modules/lambda/README.md @@ -22,14 +22,16 @@ | [filter\_pattern](#input\_filter\_pattern) | Filter pattern to use for the log subscription filter | `string` | `""` | no | | [force\_lambda\_code\_deploy](#input\_force\_lambda\_code\_deploy) | If the lambda package in s3 has the same commit id tag as the terraform build branch, the lambda will not update automatically. Set to True if making changes to Lambda code from on the same commit for example during development | `bool` | `false` | no | | [function\_code\_base\_path](#input\_function\_code\_base\_path) | The base path to the sourcecode directories needed for this lambda | `string` | `"./"` | no | -| [function\_code\_dir](#input\_function\_code\_dir) | The directory for this lambda (required for Zip) | `string` | `null` | no | +| [function\_code\_dir](#input\_function\_code\_dir) | The directory for this lambda | `string` | `null` | no | | [function\_include\_common](#input\_function\_include\_common) | Include the 'common' lambda module with this lambda | `bool` | `true` | no | | [function\_module\_name](#input\_function\_module\_name) | The name of the function module as used by the lambda handler, e.g. index or exports | `string` | `"index"` | no | | [function\_name](#input\_function\_name) | Base name of this lambda | `string` | n/a | yes | -| [function\_s3\_bucket](#input\_function\_s3\_bucket) | The bucket to upload Lambda packages to (required for Zip) | `string` | `null` | no | +| [function\_s3\_bucket](#input\_function\_s3\_bucket) | The bucket to upload Lambda packages to | `string` | `null` | no | | [group](#input\_group) | The name of the tfscaffold group | `string` | `null` | no | | [handler\_function\_name](#input\_handler\_function\_name) | The name of the lambda handler function (passed directly to the Lambda's handler option) | `string` | `"handler"` | no | | [iam\_policy\_document](#input\_iam\_policy\_document) | n/a |
object({
body = string
})
| `null` | no | +| [image\_config](#input\_image\_config) | Optional image configuration for Image-based Lambda |
object({
entry_point = optional(list(string))
command = optional(list(string))
working_directory = optional(string)
})
| `null` | no | +| [image\_uri](#input\_image\_uri) | ECR image URI for Image-based Lambda | `string` | `null` | no | | [kms\_key\_arn](#input\_kms\_key\_arn) | KMS key arn to use for this function | `string` | n/a | yes | | [lambda\_at\_edge](#input\_lambda\_at\_edge) | Whether this Lambda is a Lambda@Edge function | `bool` | `false` | no | | [lambda\_dlq\_message\_retention\_seconds](#input\_lambda\_dlq\_message\_retention\_seconds) | The number of seconds to retain messages in the Lambda DLQ SQS queue | `number` | `1209600` | no | @@ -41,13 +43,11 @@ | [log\_subscription\_lambda\_create\_permission](#input\_log\_subscription\_lambda\_create\_permission) | Whether to create a permission for the log forwarder. Set to false if using a generic one. | `bool` | `true` | no | | [log\_subscription\_role\_arn](#input\_log\_subscription\_role\_arn) | The ARN of the IAM role to use for the log subscription filter | `string` | `""` | no | | [memory](#input\_memory) | The amount of memory to apply to the created Lambda | `number` | n/a | yes | +| [package\_type](#input\_package\_type) | Lambda package type: Zip or Image | `string` | `"Zip"` | no | | [permission\_statements](#input\_permission\_statements) | Statements giving an external source permission to invoke the Lambda function |
list(object({
action = optional(string)
principal = string
source_arn = optional(string)
source_account = optional(string)
statement_id = string
}))
| `[]` | no | | [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes | | [region](#input\_region) | The AWS Region | `string` | n/a | yes | -| [runtime](#input\_runtime) | The runtime to use for the lambda function (required for Zip) | `string` | `null` | no | -| [package\_type](#input\_package\_type) | Lambda package type: Zip or Image | `string` | `"Zip"` | no | -| [image\_uri](#input\_image\_uri) | ECR image URI for Image-based Lambda | `string` | `null` | no | -| [image\_config](#input\_image\_config) | Optional image configuration for Image-based Lambda |
object({
entry_point = optional(list(string))
command = optional(list(string))
working_directory = optional(string)
})
| `null` | no | +| [runtime](#input\_runtime) | The runtime to use for the lambda function | `string` | `null` | no | | [schedule](#input\_schedule) | The fully qualified Cloudwatch Events schedule for when to run the lambda function, e.g. rate(1 day) or a cron() expression. Default disables all events resources | `string` | `""` | no | | [send\_to\_firehose](#input\_send\_to\_firehose) | Enable sending logs to firehose | `bool` | `true` | no | | [sns\_destination](#input\_sns\_destination) | SNS Topic ARN to be used for on-failure Lambda invocation records | `string` | `null` | no | From 262548af7f31db370cf17f558d16fad5baa0f040 Mon Sep 17 00:00:00 2001 From: jamesthompson26-nhs Date: Tue, 10 Feb 2026 10:12:22 +0000 Subject: [PATCH 4/5] CCM-14149: Support Container Based Lambdas --- .../modules/lambda/data_archive_file_lambda.tf | 2 +- .../lambda/data_iam_policy_document_ecr.tf | 5 ++++- .../modules/lambda/iam_role_policy_ecr.tf | 2 +- .../modules/lambda/lambda_function.tf | 18 +++++++++--------- infrastructure/modules/lambda/locals.tf | 2 ++ .../modules/lambda/s3_object_lambda.tf | 2 +- infrastructure/modules/lambda/variables.tf | 10 +++++----- 7 files changed, 23 insertions(+), 18 deletions(-) diff --git a/infrastructure/modules/lambda/data_archive_file_lambda.tf b/infrastructure/modules/lambda/data_archive_file_lambda.tf index f1fd1ba..762512a 100644 --- a/infrastructure/modules/lambda/data_archive_file_lambda.tf +++ b/infrastructure/modules/lambda/data_archive_file_lambda.tf @@ -1,5 +1,5 @@ data "archive_file" "lambda" { - count = var.package_type == "Zip" ? 1 : 0 + count = local.package_type == "zip" ? 1 : 0 type = "zip" source_dir = "${path.root}/${var.function_code_base_path}/${var.function_code_dir}" diff --git a/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf b/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf index c2bdc5f..875c1a1 100644 --- a/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf +++ b/infrastructure/modules/lambda/data_iam_policy_document_ecr.tf @@ -18,6 +18,9 @@ data "aws_iam_policy_document" "ecr" { "ecr:BatchCheckLayerAvailability", ] - resources = ["arn:aws:ecr:${var.region}:${var.aws_account_id}:repository/*"] + resources = [ + for repo_name in var.image_repository_names : + "arn:aws:ecr:${var.region}:${var.aws_account_id}:repository/${repo_name}" + ] } } diff --git a/infrastructure/modules/lambda/iam_role_policy_ecr.tf b/infrastructure/modules/lambda/iam_role_policy_ecr.tf index 2e8dc7b..3da8378 100644 --- a/infrastructure/modules/lambda/iam_role_policy_ecr.tf +++ b/infrastructure/modules/lambda/iam_role_policy_ecr.tf @@ -1,5 +1,5 @@ resource "aws_iam_role_policy" "ecr" { - count = var.package_type == "Image" ? 1 : 0 + count = local.package_type == "image" ? 1 : 0 name = "${local.csi}-ecr" role = aws_iam_role.main.id policy = data.aws_iam_policy_document.ecr.json diff --git a/infrastructure/modules/lambda/lambda_function.tf b/infrastructure/modules/lambda/lambda_function.tf index d6fc380..f67849a 100644 --- a/infrastructure/modules/lambda/lambda_function.tf +++ b/infrastructure/modules/lambda/lambda_function.tf @@ -2,21 +2,21 @@ resource "aws_lambda_function" "main" { description = var.description function_name = local.csi role = aws_iam_role.main.arn - handler = var.package_type == "Zip" ? "${var.function_module_name}.${var.handler_function_name}" : null - runtime = var.package_type == "Zip" ? var.runtime : null - package_type = var.package_type + handler = local.package_type == "zip" ? "${var.function_module_name}.${var.handler_function_name}" : null + runtime = local.package_type == "zip" ? var.runtime : null + package_type = title(local.package_type) publish = true memory_size = var.memory timeout = var.timeout - s3_bucket = var.package_type == "Zip" ? aws_s3_object.lambda[0].bucket : null - s3_key = var.package_type == "Zip" ? aws_s3_object.lambda[0].key : null - s3_object_version = var.package_type == "Zip" ? aws_s3_object.lambda[0].version_id : null + s3_bucket = local.package_type == "zip" ? aws_s3_object.lambda[0].bucket : null + s3_key = local.package_type == "zip" ? aws_s3_object.lambda[0].key : null + s3_object_version = local.package_type == "zip" ? aws_s3_object.lambda[0].version_id : null - image_uri = var.package_type == "Image" ? var.image_uri : null + image_uri = local.package_type == "image" ? var.image_uri : null dynamic "image_config" { - for_each = var.package_type == "Image" && var.image_config != null ? [1] : [] + for_each = local.package_type == "image" && var.image_config != null ? [1] : [] content { entry_point = try(var.image_config.entry_point, null) command = try(var.image_config.command, null) @@ -31,7 +31,7 @@ resource "aws_lambda_function" "main" { system_log_level = var.system_log_level } - layers = var.package_type == "Zip" ? compact(concat( + layers = local.package_type == "zip" ? compact(concat( var.layers, [ var.enable_lambda_insights && var.lambda_at_edge == false ? "arn:aws:lambda:${var.region}:580247275435:layer:LambdaInsightsExtension:53" : null diff --git a/infrastructure/modules/lambda/locals.tf b/infrastructure/modules/lambda/locals.tf index 04398ea..bd112a0 100644 --- a/infrastructure/modules/lambda/locals.tf +++ b/infrastructure/modules/lambda/locals.tf @@ -1,6 +1,8 @@ locals { module = "lambda" + package_type = lower(var.package_type) + # Compound Scope Identifier csi = replace( format( diff --git a/infrastructure/modules/lambda/s3_object_lambda.tf b/infrastructure/modules/lambda/s3_object_lambda.tf index 9c829a4..65f619b 100644 --- a/infrastructure/modules/lambda/s3_object_lambda.tf +++ b/infrastructure/modules/lambda/s3_object_lambda.tf @@ -1,5 +1,5 @@ resource "aws_s3_object" "lambda" { - count = var.package_type == "Zip" ? 1 : 0 + count = local.package_type == "zip" ? 1 : 0 bucket = var.function_s3_bucket key = "${local.csi}.zip" source = data.archive_file.lambda[0].output_path diff --git a/infrastructure/modules/lambda/variables.tf b/infrastructure/modules/lambda/variables.tf index 0844c52..0977fc1 100644 --- a/infrastructure/modules/lambda/variables.tf +++ b/infrastructure/modules/lambda/variables.tf @@ -95,7 +95,7 @@ variable "runtime" { default = null validation { - condition = var.package_type != "Zip" || (var.runtime != null && var.runtime != "") + condition = lower(var.package_type) != "zip" || (var.runtime != null && var.runtime != "") error_message = "runtime must be set when package_type is Zip." } } @@ -106,7 +106,7 @@ variable "package_type" { default = "Zip" validation { - condition = contains(["Zip", "Image"], var.package_type) + condition = contains(["zip", "image"], lower(var.package_type)) error_message = "package_type must be either Zip or Image." } } @@ -117,7 +117,7 @@ variable "image_uri" { default = null validation { - condition = var.package_type != "Image" || (var.image_uri != null && var.image_uri != "") + condition = lower(var.package_type) != "image" || (var.image_uri != null && var.image_uri != "") error_message = "image_uri must be set when package_type is Image." } } @@ -163,7 +163,7 @@ variable "function_code_dir" { default = null validation { - condition = var.package_type != "Zip" || (var.function_code_dir != null && var.function_code_dir != "") + condition = lower(var.package_type) != "zip" || (var.function_code_dir != null && var.function_code_dir != "") error_message = "function_code_dir must be set when package_type is Zip." } } @@ -174,7 +174,7 @@ variable "function_s3_bucket" { default = null validation { - condition = var.package_type != "Zip" || (var.function_s3_bucket != null && var.function_s3_bucket != "") + condition = lower(var.package_type) != "zip" || (var.function_s3_bucket != null && var.function_s3_bucket != "") error_message = "function_s3_bucket must be set when package_type is Zip." } } From b2b512bc2d26bfca321ff9ce0bb2623f19788a5c Mon Sep 17 00:00:00 2001 From: jamesthompson26-nhs Date: Tue, 10 Feb 2026 10:17:35 +0000 Subject: [PATCH 5/5] CCM-14149: Support Container Based Lambdas --- infrastructure/modules/lambda/README.md | 1 + infrastructure/modules/lambda/variables.tf | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/infrastructure/modules/lambda/README.md b/infrastructure/modules/lambda/README.md index 0e7a51b..d09e623 100644 --- a/infrastructure/modules/lambda/README.md +++ b/infrastructure/modules/lambda/README.md @@ -31,6 +31,7 @@ | [handler\_function\_name](#input\_handler\_function\_name) | The name of the lambda handler function (passed directly to the Lambda's handler option) | `string` | `"handler"` | no | | [iam\_policy\_document](#input\_iam\_policy\_document) | n/a |
object({
body = string
})
| `null` | no | | [image\_config](#input\_image\_config) | Optional image configuration for Image-based Lambda |
object({
entry_point = optional(list(string))
command = optional(list(string))
working_directory = optional(string)
})
| `null` | no | +| [image\_repository\_names](#input\_image\_repository\_names) | ECR repository names allowed for Image-based Lambda | `list(string)` | `[]` | no | | [image\_uri](#input\_image\_uri) | ECR image URI for Image-based Lambda | `string` | `null` | no | | [kms\_key\_arn](#input\_kms\_key\_arn) | KMS key arn to use for this function | `string` | n/a | yes | | [lambda\_at\_edge](#input\_lambda\_at\_edge) | Whether this Lambda is a Lambda@Edge function | `bool` | `false` | no | diff --git a/infrastructure/modules/lambda/variables.tf b/infrastructure/modules/lambda/variables.tf index 0977fc1..ed335f9 100644 --- a/infrastructure/modules/lambda/variables.tf +++ b/infrastructure/modules/lambda/variables.tf @@ -132,6 +132,17 @@ variable "image_config" { default = null } +variable "image_repository_names" { + type = list(string) + description = "ECR repository names allowed for Image-based Lambda" + default = [] + + validation { + condition = lower(var.package_type) != "image" || length(var.image_repository_names) > 0 + error_message = "image_repository_names must include at least one repository name when package_type is Image." + } +} + variable "schedule" { type = string description = "The fully qualified Cloudwatch Events schedule for when to run the lambda function, e.g. rate(1 day) or a cron() expression. Default disables all events resources"