I am using Terraform for the first time and got a little lost in the configuration and I am facing this issue with my Lambda Function that should be able to do a simple HTTP request to google.com or swapi.com ( or whatever other external API ). In my case in my linkedin callback I need to use the linkedin api. Here is some part of my configuration:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.21.0"
}
random = {
source = "hashicorp/random"
version = ">= 3.3.0"
}
archive = {
source = "hashicorp/archive"
version = ">= 2.2.0"
}
}
required_version = ">= 1.0"
}
provider "aws" {
region = var.region
access_key = var.access_key
secret_key = var.secret_key
}
resource "aws_vpc" "main_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "main-vpc"
}
lifecycle {
prevent_destroy = true
}
}
resource "aws_internet_gateway" "main_igw" {
vpc_id = aws_vpc.main_vpc.id
lifecycle {
prevent_destroy = true
}
}
resource "aws_route_table" "route-table-main" {
vpc_id = aws_vpc.main_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main_igw.id
}
tags = {
Name = "main-route-table"
}
lifecycle {
prevent_destroy = true
}
}
resource "aws_eip" "nat_eip" {
lifecycle {
prevent_destroy = true
}
}
resource "aws_nat_gateway" "nat_gateway" {
allocation_id = aws_eip.nat_eip.id
subnet_id = aws_subnet.main_subnet_nat_gateway_a.id
tags = {
Name = "nat-gateway"
}
}
resource "aws_route_table" "route-table-nat" {
vpc_id = aws_vpc.main_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_nat_gateway.nat_gateway.id
}
tags = {
Name = "nat-route-table"
}
}
resource "aws_security_group" "main_sg" {
name = "main-sg"
description = "Terraform SG"
vpc_id = aws_vpc.main_vpc.id
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24" ]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
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"]
}
lifecycle {
prevent_destroy = true
}
}
resource "aws_subnet" "main_subnet_a" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-2a"
lifecycle {
prevent_destroy = true
}
}
resource "aws_subnet" "main_subnet_b" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.2.0/24"
availability_zone = "us-east-2b"
lifecycle {
prevent_destroy = true
}
}
resource "aws_subnet" "main_subnet_c" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.3.0/24"
availability_zone = "us-east-2c"
lifecycle {
prevent_destroy = true
}
}
resource "aws_subnet" "main_subnet_nat_gateway_a" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.4.0/24"
availability_zone = "us-east-2a"
}
resource "aws_subnet" "main_subnet_nat_gateway_b" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.5.0/24"
availability_zone = "us-east-2b"
}
resource "aws_subnet" "main_subnet_nat_gateway_c" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.6.0/24"
availability_zone = "us-east-2c"
}
resource "aws_db_subnet_group" "db_subnet_group" {
name = "db_subnet_group"
description = "My DB subnet group"
subnet_ids = [
aws_subnet.main_subnet_a.id,
aws_subnet.main_subnet_b.id,
aws_subnet.main_subnet_c.id
]
lifecycle {
prevent_destroy = true
}
}
resource "aws_route_table_association" "subnet-association-a" {
subnet_id = aws_subnet.main_subnet_a.id
route_table_id = aws_route_table.route-table-main.id
lifecycle {
prevent_destroy = true
}
}
resource "aws_route_table_association" "subnet-association-b" {
subnet_id = aws_subnet.main_subnet_b.id
route_table_id = aws_route_table.route-table-main.id
lifecycle {
prevent_destroy = true
}
}
resource "aws_route_table_association" "subnet-association-c" {
subnet_id = aws_subnet.main_subnet_c.id
route_table_id = aws_route_table.route-table-main.id
lifecycle {
prevent_destroy = true
}
}
resource "aws_route_table_association" "subnet-association-nat-gateway-a" {
subnet_id = aws_subnet.main_subnet_nat_gateway_a.id
route_table_id = aws_route_table.route-table-nat.id
}
resource "aws_route_table_association" "subnet-association-nat-gateway-b" {
subnet_id = aws_subnet.main_subnet_nat_gateway_b.id
route_table_id = aws_route_table.route-table-nat.id
}
resource "aws_route_table_association" "subnet-association-nat-gateway-c" {
subnet_id = aws_subnet.main_subnet_nat_gateway_c.id
route_table_id = aws_route_table.route-table-nat.id
}
resource "aws_iam_role" "lambda_exec" {
name = "lambda-exec"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "lambda_policy" {
role = aws_iam_role.lambda_exec.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}
resource "aws_iam_role_policy_attachment" "lambda_sns_policy" {
role = aws_iam_role.lambda_exec.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSNSFullAccess"
}
data "archive_file" "lambda_auth" {
type = "zip"
source_dir = "../${path.module}/lambdas/auth"
output_path = "../${path.module}/lambdas/auth.zip"
}
resource "aws_s3_object" "lambda_auth" {
bucket = aws_s3_bucket.lambda_bucket.id
key = "auth.zip"
source = data.archive_file.lambda_auth.output_path
etag = filemd5(data.archive_file.lambda_auth.output_path)
}
resource "aws_lambda_function" "auth_test" {
function_name = "auth-test"
s3_bucket = aws_s3_bucket.lambda_bucket.id
s3_key = aws_s3_object.lambda_auth.key
runtime = "nodejs18.x"
handler = "index.test"
source_code_hash = data.archive_file.lambda_auth.output_base64sha256
role = aws_iam_role.lambda_exec.arn
environment {
variables = {
RDS_DATABASE_NAME = var.database_name
RDS_DATABASE_HOST = aws_db_instance.cyrannus_database.address
RDS_DATABASE_USER = aws_db_instance.cyrannus_database.username
RDS_DATABASE_PASS = aws_db_instance.cyrannus_database.password
}
}
vpc_config {
security_group_ids = [aws_security_group.main_sg.id]
subnet_ids = [aws_subnet.main_subnet_nat_gateway_a.id, aws_subnet.main_subnet_nat_gateway_b.id, aws_subnet.main_subnet_nat_gateway_c.id]
}
timeout = 60
}
resource "aws_lambda_function" "auth_linkedin_callback" {
function_name = "auth-linkedin-callback"
s3_bucket = aws_s3_bucket.lambda_bucket.id
s3_key = aws_s3_object.lambda_auth.key
runtime = "nodejs18.x"
handler = "index.linkedinCallback"
source_code_hash = data.archive_file.lambda_auth.output_base64sha256
role = aws_iam_role.lambda_exec.arn
environment {
variables = {
RDS_DATABASE_NAME = var.database_name
RDS_DATABASE_HOST = aws_db_instance.cyrannus_database.address
RDS_DATABASE_USER = aws_db_instance.cyrannus_database.username
RDS_DATABASE_PASS = aws_db_instance.cyrannus_database.password
LINKEDIN_CLIENT_ID = var.linkedin_client_id
LINKEDIN_CLIENT_SECRET = var.linkedin_client_secret
LINKEDIN_REDIRECT_URI = "${aws_apigatewayv2_stage.dev.invoke_url}/auth/linkedin/callback"
}
}
vpc_config {
security_group_ids = [aws_security_group.main_sg.id]
subnet_ids = [aws_subnet.main_subnet_nat_gateway_a.id, aws_subnet.main_subnet_nat_gateway_b.id, aws_subnet.main_subnet_nat_gateway_c.id]
}
timeout = 60
}
resource "aws_cloudwatch_log_group" "auth_test" {
name = "/aws/lambda/${aws_lambda_function.auth_test.function_name}"
retention_in_days = 14
}
resource "aws_cloudwatch_log_group" "auth_linkedin_callback" {
name = "/aws/lambda/${aws_lambda_function.auth_linkedin_callback.function_name}"
retention_in_days = 14
}
I've tried to use NAT Gateway as presented in some tutorial but I am a little lost, AWS Console interface seems to do a lot of things by default and I am not sure what I am missing.
I've managed for example to create an EC2 that is in the VPC to access a RDS that is in the same VPC and gave it network access with IGW and I am able to to curl commands an added a simple phpmyadmin.
You have placed a NAT Gateway in a subnet that has a route to the NAT Gateway. That's a circular reference. This subnet does not actually have a route to the Internet, so the NAT Gateway will not actually work.