user672009
user672009

Reputation: 4585

My Lambda can't connect to my RDS instance

I'm trying to create both services within the same VPC and give them appropriate security groups but they I can't make it work.

variable "vpc_cidr_block" {
  default = "10.1.0.0/16"
}

variable "cidr_block_subnet_public" {
  default = "10.1.1.0/24"
}

variable "cidr_block_subnets_private" {
  default = ["10.1.2.0/24", "10.1.3.0/24", "10.1.4.0/24"]
}

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_vpc" "vpc" {
  cidr_block = var.vpc_cidr_block
}

resource "aws_subnet" "private" {
  count = length(var.cidr_block_subnets_private)
  cidr_block = var.cidr_block_subnets_private[count.index]
  vpc_id = aws_vpc.vpc.id
  availability_zone = data.aws_availability_zones.available.names[count.index]
}

resource "aws_security_group" "lambda" {
  vpc_id = aws_vpc.vpc.id

  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group" "rds" {
  vpc_id = aws_vpc.vpc.id

  ingress {
    description = "PostgreSQL"
    from_port = 5432
    protocol = "tcp"
    to_port = 5432
//    security_groups = [aws_security_group.lambda.id]
  }

  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_lambda_function" "event" {
  function_name = "ServerlessExampleEvent"

  timeout = 30

  s3_bucket = "mn-lambda"
  s3_key = "mn/v1.0.0/lambda-1.0.0-all.jar"

  handler = "dk.fitfit.handler.EventRequestHandler"
  runtime = "java11"

  memory_size = 256

  role = aws_iam_role.event.arn

  vpc_config {
    security_group_ids = [aws_security_group.lambda.id]
    subnet_ids = [for s in aws_subnet.private: s.id]
  }

  environment {
    variables = {
      JDBC_DATABASE_URL = "jdbc:postgresql://${aws_db_instance.rds.address}:${aws_db_instance.rds.port}/${aws_db_instance.rds.identifier}"
      DATABASE_USERNAME = aws_db_instance.rds.username
      DATABASE_PASSWORD = aws_db_instance.rds.password
    }
  }
}

resource "aws_db_subnet_group" "db" {
  subnet_ids = aws_subnet.private.*.id
}

resource "aws_db_instance" "rds" {
  allocated_storage = 10
  engine = "postgres"
  engine_version = "11.5"
  instance_class = "db.t2.micro"
  username = "postgres"
  password = random_password.password.result
  skip_final_snapshot = true
  apply_immediately = true

  vpc_security_group_ids = [aws_security_group.rds.id]
  db_subnet_group_name = aws_db_subnet_group.db.name
}

resource "random_password" "password" {
  length = 32
  special = false
}

I tried to not clutter the question by only posting the relevant part of my HCL. Please let me know if I missed anything important.

Upvotes: 2

Views: 882

Answers (1)

ydaetskcoR
ydaetskcoR

Reputation: 56997

The biggest issue is the commented out security_groups parameter on the ingress block of the rds security group. Uncommenting that should then allow Postgresql traffic from the lambda security group:

resource "aws_security_group" "rds" {
  vpc_id = aws_vpc.vpc.id

  ingress {
    description     = "PostgreSQL"
    from_port       = 5432
    protocol        = "tcp"
    to_port         = 5432
    security_groups = [aws_security_group.lambda.id]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

As well as that your JDBC string is basically resolving to something like jdbc:postgresql://terraform-20091110230000000000000001.xxxx.us-east-1.rds.amazonaws.com:5432/terraform-20091110230000000000000001 because you aren't specifying an identifier for the RDS instance and so it defaults to generating an identifier prefixed with terraform- plus the timestamp and a counter. The important part to note here is that your RDS instance doesn't yet include a database of the name terraform-20091110230000000000000001 for your application to connect to because you haven't specified it.

You can have RDS create a database on the RDS instance by using the name parameter. You can then update your JDBC connection string to specify the database name as well:

resource "aws_db_instance" "rds" {
  allocated_storage   = 10
  engine              = "postgres"
  engine_version      = "11.5"
  instance_class      = "db.t2.micro"
  username            = "postgres"
  password            = random_password.password.result
  skip_final_snapshot = true
  apply_immediately   = true
  name                = "foo"

  vpc_security_group_ids = [aws_security_group.rds.id]
  db_subnet_group_name   = aws_db_subnet_group.db.name
}

resource "aws_lambda_function" "event" {
  function_name = "ServerlessExampleEvent"

  timeout = 30

  s3_bucket = "mn-lambda"
  s3_key    = "mn/v1.0.0/lambda-1.0.0-all.jar"

  handler = "dk.fitfit.handler.EventRequestHandler"
  runtime = "java11"

  memory_size = 256

  role = aws_iam_role.event.arn

  vpc_config {
    security_group_ids = [aws_security_group.lambda.id]
    subnet_ids         = [for s in aws_subnet.private : s.id]
  }

  environment {
    variables = {
      JDBC_DATABASE_URL = "jdbc:postgresql://${aws_db_instance.rds.address}:${aws_db_instance.rds.port}/${aws_db_instance.rds.name}"
      DATABASE_USERNAME = aws_db_instance.rds.username
      DATABASE_PASSWORD = aws_db_instance.rds.password
    }
  }
}

Upvotes: 1

Related Questions