From e79573d0869ca91fb088e91bc8a3429ecc60c1f8 Mon Sep 17 00:00:00 2001 From: Eamonn Moloney Date: Fri, 20 May 2022 12:53:23 +0100 Subject: [PATCH] feat: Added support for lambda permissions when the target is a lambda function (#240) --- .pre-commit-config.yaml | 2 +- README.md | 11 ++++---- examples/complete-alb/README.md | 3 ++- examples/complete-alb/main.tf | 45 +++++++++++++++++++++++++-------- main.tf | 24 ++++++++++++++++++ 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bbf2a55..19dda01 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.67.0 + rev: v1.71.0 hooks: - id: terraform_fmt - id: terraform_validate diff --git a/README.md b/README.md index 2052da1..4b90900 100644 --- a/README.md +++ b/README.md @@ -33,16 +33,16 @@ module "alb" { backend_protocol = "HTTP" backend_port = 80 target_type = "instance" - targets = [ - { + targets = { + my_target = { target_id = "i-0123456789abcdefg" port = 80 - }, - { + } + my_other_target = { target_id = "i-a1b2c3d4e5f6g7h8i" port = 8080 } - ] + } } ] @@ -311,6 +311,7 @@ No modules. | Name | Type | |------|------| +| [aws_lambda_permission.lb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | | [aws_lb.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb) | resource | | [aws_lb_listener.frontend_http_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource | | [aws_lb_listener.frontend_https](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource | diff --git a/examples/complete-alb/README.md b/examples/complete-alb/README.md index dc8e98d..ead2e9a 100644 --- a/examples/complete-alb/README.md +++ b/examples/complete-alb/README.md @@ -38,7 +38,8 @@ Note that this example may create resources which cost money. Run `terraform des |------|--------|---------| | [acm](#module\_acm) | terraform-aws-modules/acm/aws | ~> 3.0 | | [alb](#module\_alb) | ../../ | n/a | -| [lambda\_function](#module\_lambda\_function) | terraform-aws-modules/lambda/aws | ~> 3.0 | +| [lambda\_with\_allowed\_triggers](#module\_lambda\_with\_allowed\_triggers) | terraform-aws-modules/lambda/aws | ~> 3.0 | +| [lambda\_without\_allowed\_triggers](#module\_lambda\_without\_allowed\_triggers) | terraform-aws-modules/lambda/aws | ~> 3.0 | | [lb\_disabled](#module\_lb\_disabled) | ../../ | n/a | | [security\_group](#module\_security\_group) | terraform-aws-modules/security-group/aws | ~> 4.0 | diff --git a/examples/complete-alb/main.tf b/examples/complete-alb/main.tf index 2ffbd94..54814a8 100644 --- a/examples/complete-alb/main.tf +++ b/examples/complete-alb/main.tf @@ -405,13 +405,18 @@ module "alb" { target_type = "lambda" lambda_multi_value_headers_enabled = true targets = { - # Lambda function permission should be granted before - # it is used. There can be an error: - # NB: Error registering targets with target group: - # AccessDenied: elasticloadbalancing principal does not - # have permission to invoke ... from target group ... - my_lambda = { - target_id = module.lambda_function.lambda_function_arn + lambda_with_allowed_triggers = { + target_id = module.lambda_with_allowed_triggers.lambda_function_arn + } + } + }, + { + name_prefix = "l2-" + target_type = "lambda" + targets = { + lambda_without_allowed_triggers = { + target_id = module.lambda_without_allowed_triggers.lambda_function_arn + attach_lambda_permission = true } } }, @@ -500,12 +505,12 @@ resource "null_resource" "download_package" { } } -module "lambda_function" { +module "lambda_with_allowed_triggers" { source = "terraform-aws-modules/lambda/aws" version = "~> 3.0" - function_name = "${random_pet.this.id}-lambda" - description = "My awesome lambda function" + function_name = "${random_pet.this.id}-with-allowed-triggers" + description = "My awesome lambda function (with allowed triggers)" handler = "index.lambda_handler" runtime = "python3.8" @@ -523,3 +528,23 @@ module "lambda_function" { depends_on = [null_resource.download_package] } + +module "lambda_without_allowed_triggers" { + source = "terraform-aws-modules/lambda/aws" + version = "~> 3.0" + + function_name = "${random_pet.this.id}-without-allowed-triggers" + description = "My awesome lambda function (without allowed triggers)" + handler = "index.lambda_handler" + runtime = "python3.8" + + publish = true + + create_package = false + local_existing_package = local.downloaded + + # Allowed triggers will be managed by ALB module + allowed_triggers = {} + + depends_on = [null_resource.download_package] +} diff --git a/main.tf b/main.tf index 8001ced..6c0a168 100644 --- a/main.tf +++ b/main.tf @@ -133,6 +133,28 @@ locals { if k == "targets" ] ])...) + + # Filter out the attachments for lambda functions. The ALB target group needs permission to forward a request on to + # the specified lambda function. This filtered list is used to create those permission resources + target_group_attachments_lambda = { + for k, v in local.target_group_attachments : + (k) => merge(v, { lambda_function_name = split(":", v.target_id)[6] }) + if try(v.attach_lambda_permission, false) + } +} + +resource "aws_lambda_permission" "lb" { + for_each = var.create_lb && local.target_group_attachments_lambda != null ? local.target_group_attachments_lambda : {} + + function_name = each.value.lambda_function_name + qualifier = try(each.value.lambda_qualifier, null) + + statement_id = try(each.value.lambda_statement_id, "AllowExecutionFromLb") + action = try(each.value.lambda_action, "lambda:InvokeFunction") + principal = try(each.value.lambda_principal, "elasticloadbalancing.amazonaws.com") + source_arn = aws_lb_target_group.main[each.value.tg_index].arn + source_account = try(each.value.lambda_source_account, null) + event_source_token = try(each.value.lambda_event_source_token, null) } resource "aws_lb_target_group_attachment" "this" { @@ -142,6 +164,8 @@ resource "aws_lb_target_group_attachment" "this" { target_id = each.value.target_id port = lookup(each.value, "port", null) availability_zone = lookup(each.value, "availability_zone", null) + + depends_on = [aws_lambda_permission.lb] } resource "aws_lb_listener_rule" "https_listener_rule" {