I am currently learning for the AWS Developer Certification. Most of the learning material shows examples in the AWS Console, but I am trying to recreate all of this in Terraform since I guess it is much more likely to be used this way in a professional environment.
In one chapter an Application Load Balancer is linked to a Lambda Function.
I have been trying to recreate this in Terraform for a few days no, but it never worked.
My current configuration is this
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.41.0"
}
}
}
provider "aws" {
region = "eu-central-1"
}
# Create an IAM role for the Lambda function
resource "aws_iam_role" "lambda_role" {
name = "lambda_role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}
]
})
}
# Lambda Function Code as Data Source
data "archive_file" "code" {
type = "zip"
source_file = "./code/hello_world.py"
output_path = "code.zip"
}
# Create the Lambda function
resource "aws_lambda_function" "test_lambda" {
function_name = "test_lambda"
filename = "code.zip"
handler = "provider.handler"
role = aws_iam_role.lambda_role.arn
runtime = "python3.9"
memory_size = 128
timeout = 30
source_code_hash = data.archive_file.code.output_base64sha256
}
# Create the target group
resource "aws_lb_target_group" "lambda" {
name = "lambda-target-group"
target_type = "lambda"
depends_on = [aws_iam_role_policy_attachment.alb_policy_attach]
}
# Attach the Lambda function to the target group
resource "aws_lambda_permission" "with_lb" {
statement_id = "AllowExecutionFromlb"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.test_lambda.function_name
principal = "elasticloadbalancing.amazonaws.com"
source_arn = aws_lb_target_group.lambda.arn
}
resource "aws_lb_target_group_attachment" "test" {
target_group_arn = aws_lb_target_group.lambda.arn
target_id = aws_lambda_function.test_lambda.arn
depends_on = [aws_lambda_permission.with_lb]
}
# Create the load balancer
resource "aws_lb" "lambda" {
name = "lambda-lb"
internal = false
load_balancer_type = "application"
subnets = ["subnet-ce43c7b2", "subnet-6e119a22"]
security_groups = [aws_security_group.lb_sg.id]
}
# Create IAM role for ALB
resource "aws_iam_role" "alb_role" {
name = "alb_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "elasticloadbalancing.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
# Attach permissions policy to ALB role
resource "aws_iam_policy" "alb_permissions" {
name = "alb_permissions"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:Describe*",
"lambda:InvokeFunction"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "alb_policy_attach" {
role = aws_iam_role.alb_role.name
policy_arn = aws_iam_policy.alb_permissions.arn
}
# Create the load balancer listener
resource "aws_lb_listener" "lambda" {
load_balancer_arn = aws_lb.lambda.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.lambda.arn
}
}
resource "aws_security_group" "lb_sg" {
name = "lb-sg"
description = "Allow incoming traffic to load balancer"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
It gives me a 502 when accessing the Load Balancer. Also no Cloudwatch Logs are written, despite the ALB having permission to do so.
I have tried:
- I have already consulted the Terraform Documentation, the AWS Documentation, searched for best practice Examples via Google (which only returned examples done in the AWS Console).
- I have also asked Chat GPT, Microsoft Copilot and Cody, but they never produced functioning examples there where always mayor errors that I was unable to fix.
- I also consulted AmazonQ/CodeWhisperer since I figured the Amazon AI would be more precise in regards to AWS specific problems. But the example given by AmazonQ also had mayor errors and I was unable to deploy them even after a lot of adjusting.
- I have also tried to create the infrastructure in the console and export it to terraform, but this would require me to get familiar with Terraformer or Former 2 which, as far as I can tell, are completely new "rabbit holes" that I would like to avoid for now.
Could anyone please provide me with a working/best practice terraform example for an alb that is calling a lambda function including all necessary permissions and security groups?
2
Answers
You would need to put your lambda function inside the VPC in which the load balancer is and then assign a security group to the lambda function which allows traffic from the load balancer. The lambda target would be failing health checks in the target group and thus giving 502 errors.
You mention that "no Cloudwatch Logs are written, despite the ALB having permission to do so", which is strange, because you can’t assign IAM permissions to ALBs. Indeed, the
aws_iam_role.alb_role
IAM role you are creating in your Terraform code is never actually assigned to anything. That role is completely unused and pointless.The resource
resource "aws_lambda_permission" "with_lb"
is the only thing you should have needed to create to give the ALB access to call the Lambda function.The only logging you can enable on a load balancer are Access Logs, and Connection Logs, both of which are only configurable to go to an S3 bucket at this time, not CloudWatch Logs. You don’t have either of those enabled in your Terraform code.