Skip to content

Commit 28ad27c

Browse files
committed
[New Pattern] AWS Lambda to Amazon Aurora Serverless
1 parent d2a9667 commit 28ad27c

35 files changed

+4989
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
builds/*
2+
.terraform
3+
.terraform.*
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# AWS Lambda function to Amazon Aurora Serverless
2+
3+
The pattern creates a Lambda function and a Amazon Aurora Serverless cluster, a Log group and the IAM resources required to run the application.
4+
5+
The Lambda function is written in Python that uses pymysql client to establish connectivity with the serverless database.
6+
7+
## Getting started with Terraform Serverless Patterns
8+
9+
Read more about general requirements and deployment instructions for Terraform Serverless Patterns [here](https://github.com/aws-samples/serverless-patterns/blob/main/terraform-fixtures/docs/README.md).
10+
11+
## Testing
12+
13+
After deployment, invoke Lambda function with multiple inputs, and go to the Step Function Console and view the different invocations to note the different behavior with the different inputs.
14+
15+
To do this, you can run these commands in the terminal (replace `<function-name>` with the value returned in `lambda_function_name`):
16+
17+
```shell
18+
aws lambda invoke --function-name <function-name> --payload '{"key": "value"}' response.json
19+
```
20+
## Output
21+
22+
Upon successful invocation, the function returns the following response -
23+
24+
```json
25+
{
26+
"statusCode": 200,
27+
"body": "{\"message\": \"Successfully connected to the database\", \"database\": \"mydb\", \"host\": \"aurora-serverless-cluster.cluster-cna4c0mg426r.us-east-1.rds.amazonaws.com\"}"
28+
}
29+
```
30+
31+
## Providers
32+
33+
| Name | Version |
34+
|------|---------|
35+
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= "5.84.0" |
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"title": "AWS Lambda function to Amazon Aurora Serverless",
3+
"description": "The pattern creates a Lambda function and an Amazon Aurora Cluster with Serverless instance.",
4+
"language": "Python",
5+
"level": "200",
6+
"framework": "Terraform",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"The pattern creates a Lambda function and an Amazon Aurora Cluster with Serverless instance.",
11+
"It also guides how to invoke the function to access the database."
12+
]
13+
},
14+
"gitHub": {
15+
"template": {
16+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/terraform-lambda-aurora-serverless",
17+
"templateURL": "serverless-patterns/terraform-lambda-aurora-serverless",
18+
"projectFolder": "terraform-lambda-aurora-serverless",
19+
"templateFile": "terraform-lambda-aurora-serverless/main.tf"
20+
}
21+
},
22+
"resources": {
23+
"bullets": [
24+
{
25+
"test": "Terraform AWS Lambda examples",
26+
"link": "https://github.com/terraform-aws-modules/terraform-aws-lambda/tree/master/examples"
27+
},
28+
{
29+
"test": "Terraform Registry - RDS (Relational Database)",
30+
"link": "https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster.html"
31+
},
32+
{
33+
"text": "Amazon Aurora User Guide",
34+
"link": "https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html"
35+
},
36+
{
37+
"test": "AWS Lambda Developer Guide",
38+
"link": "https://docs.aws.amazon.com/lambda/latest/dg/welcome.html"
39+
}
40+
]
41+
},
42+
"deploy": {
43+
"text": [
44+
"terraform init && terraform apply"
45+
]
46+
},
47+
"testing": {
48+
"text": [
49+
"See the GitHub repo for detailed testing instructions."
50+
]
51+
},
52+
"cleanup": {
53+
"text": [
54+
"terraform destroy"
55+
]
56+
},
57+
"authors": [
58+
{
59+
"name": "Saborni Bhattacharya",
60+
"image": "https://drive.google.com/file/d/1AZFquOkafEQRUlrT4hKOtIbt4Cq66SHd/view?usp=sharing",
61+
"bio": "AWS SA, Cloud Enthusiast",
62+
"linkedin": "https://www.linkedin.com/in/saborni-bhattacharya-5b523812a/"
63+
}
64+
]
65+
}
45.7 KB
Binary file not shown.
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
# VPC and Networking
2+
resource "aws_vpc" "lambda_vpc" {
3+
cidr_block = var.vpc_cidr
4+
enable_dns_hostnames = true
5+
enable_dns_support = true
6+
7+
tags = {
8+
Name = "lambda-aurora-vpc"
9+
Environment = var.environment
10+
}
11+
}
12+
13+
# Internet Gateway
14+
resource "aws_internet_gateway" "main" {
15+
vpc_id = aws_vpc.lambda_vpc.id
16+
17+
tags = {
18+
Name = "main-igw"
19+
Environment = var.environment
20+
}
21+
}
22+
23+
# Public Subnet for NAT Gateway
24+
resource "aws_subnet" "public" {
25+
vpc_id = aws_vpc.lambda_vpc.id
26+
cidr_block = cidrsubnet(var.vpc_cidr, 8, 0)
27+
availability_zone = "${var.aws_region}a"
28+
map_public_ip_on_launch = true
29+
30+
tags = {
31+
Name = "public-subnet"
32+
Environment = var.environment
33+
}
34+
}
35+
36+
# Private Subnets for Lambda and Aurora
37+
resource "aws_subnet" "lambda_subnet_1" {
38+
vpc_id = aws_vpc.lambda_vpc.id
39+
cidr_block = cidrsubnet(var.vpc_cidr, 8, 1)
40+
availability_zone = "${var.aws_region}a"
41+
42+
tags = {
43+
Name = "lambda-aurora-subnet-1"
44+
Environment = var.environment
45+
}
46+
}
47+
48+
resource "aws_subnet" "lambda_subnet_2" {
49+
vpc_id = aws_vpc.lambda_vpc.id
50+
cidr_block = cidrsubnet(var.vpc_cidr, 8, 2)
51+
availability_zone = "${var.aws_region}b"
52+
53+
tags = {
54+
Name = "lambda-aurora-subnet-2"
55+
Environment = var.environment
56+
}
57+
}
58+
59+
# NAT Gateway
60+
resource "aws_eip" "nat" {
61+
domain = "vpc"
62+
}
63+
64+
resource "aws_nat_gateway" "main" {
65+
allocation_id = aws_eip.nat.id
66+
subnet_id = aws_subnet.public.id
67+
68+
tags = {
69+
Name = "main-nat"
70+
Environment = var.environment
71+
}
72+
}
73+
74+
# Route Tables
75+
resource "aws_route_table" "public" {
76+
vpc_id = aws_vpc.lambda_vpc.id
77+
78+
route {
79+
cidr_block = "0.0.0.0/0"
80+
gateway_id = aws_internet_gateway.main.id
81+
}
82+
83+
tags = {
84+
Name = "public-rt"
85+
Environment = var.environment
86+
}
87+
}
88+
89+
resource "aws_route_table" "private" {
90+
vpc_id = aws_vpc.lambda_vpc.id
91+
92+
route {
93+
cidr_block = "0.0.0.0/0"
94+
nat_gateway_id = aws_nat_gateway.main.id
95+
}
96+
97+
tags = {
98+
Name = "private-rt"
99+
Environment = var.environment
100+
}
101+
}
102+
103+
# Route Table Associations
104+
resource "aws_route_table_association" "public" {
105+
subnet_id = aws_subnet.public.id
106+
route_table_id = aws_route_table.public.id
107+
}
108+
109+
resource "aws_route_table_association" "private_1" {
110+
subnet_id = aws_subnet.lambda_subnet_1.id
111+
route_table_id = aws_route_table.private.id
112+
}
113+
114+
resource "aws_route_table_association" "private_2" {
115+
subnet_id = aws_subnet.lambda_subnet_2.id
116+
route_table_id = aws_route_table.private.id
117+
}
118+
119+
# Security Groups
120+
resource "aws_security_group" "aurora_sg" {
121+
name = "aurora-security-group"
122+
description = "Security group for Aurora Serverless"
123+
vpc_id = aws_vpc.lambda_vpc.id
124+
125+
ingress {
126+
from_port = 3306
127+
to_port = 3306
128+
protocol = "tcp"
129+
cidr_blocks = [var.vpc_cidr]
130+
}
131+
132+
egress {
133+
from_port = 0
134+
to_port = 0
135+
protocol = "-1"
136+
cidr_blocks = ["0.0.0.0/0"]
137+
}
138+
139+
tags = {
140+
Name = "aurora-sg"
141+
Environment = var.environment
142+
}
143+
}
144+
145+
# Aurora Configuration
146+
resource "aws_db_subnet_group" "aurora_subnet_group" {
147+
name = "aurora-subnet-group"
148+
subnet_ids = [aws_subnet.lambda_subnet_1.id, aws_subnet.lambda_subnet_2.id]
149+
150+
tags = {
151+
Name = "Aurora subnet group"
152+
Environment = var.environment
153+
}
154+
}
155+
156+
resource "aws_rds_cluster" "aurora_cluster" {
157+
cluster_identifier = "aurora-serverless-cluster"
158+
engine = "aurora-mysql"
159+
engine_version = "8.0.mysql_aurora.3.04.1"
160+
engine_mode = "provisioned"
161+
database_name = var.database_name
162+
master_username = var.db_username
163+
master_password = var.db_password
164+
storage_encrypted = true
165+
skip_final_snapshot = true
166+
db_subnet_group_name = aws_db_subnet_group.aurora_subnet_group.name
167+
vpc_security_group_ids = [aws_security_group.aurora_sg.id]
168+
169+
serverlessv2_scaling_configuration {
170+
min_capacity = 0.5
171+
max_capacity = 16.0
172+
}
173+
174+
tags = {
175+
Environment = var.environment
176+
}
177+
# Add explicit dependencies
178+
depends_on = [
179+
aws_vpc.lambda_vpc,
180+
aws_subnet.lambda_subnet_1,
181+
aws_subnet.lambda_subnet_2,
182+
aws_security_group.aurora_sg
183+
]
184+
}
185+
186+
# Create Aurora Instance
187+
resource "aws_rds_cluster_instance" "aurora_instance" {
188+
cluster_identifier = aws_rds_cluster.aurora_cluster.id
189+
instance_class = "db.serverless"
190+
engine = aws_rds_cluster.aurora_cluster.engine
191+
engine_version = aws_rds_cluster.aurora_cluster.engine_version
192+
193+
depends_on = [aws_rds_cluster.aurora_cluster]
194+
}
195+
196+
# IAM Configuration
197+
resource "aws_iam_role" "lambda_role" {
198+
name = "lambda_aurora_role"
199+
assume_role_policy = jsonencode({
200+
Version = "2012-10-17"
201+
Statement = [
202+
{
203+
Action = "sts:AssumeRole"
204+
Effect = "Allow"
205+
Principal = {
206+
Service = "lambda.amazonaws.com"
207+
}
208+
}
209+
]
210+
})
211+
}
212+
213+
resource "aws_iam_role_policy" "lambda_policy" {
214+
name = "lambda_aurora_policy"
215+
role = aws_iam_role.lambda_role.id
216+
217+
policy = jsonencode({
218+
Version = "2012-10-17"
219+
Statement = [
220+
{
221+
Effect = "Allow"
222+
Action = [
223+
"rds-data:ExecuteStatement",
224+
"rds-data:BatchExecuteStatement",
225+
"rds-data:BeginTransaction",
226+
"rds-data:CommitTransaction",
227+
"rds-data:RollbackTransaction",
228+
"logs:CreateLogGroup",
229+
"logs:CreateLogStream",
230+
"logs:PutLogEvents",
231+
"ec2:CreateNetworkInterface",
232+
"ec2:DescribeNetworkInterfaces",
233+
"ec2:DeleteNetworkInterface"
234+
]
235+
Resource = "*"
236+
}
237+
]
238+
})
239+
}
240+
241+
# Lambda Function
242+
data "archive_file" "lambda_zip" {
243+
type = "zip"
244+
source_dir = "${path.module}/src/function"
245+
output_path = "${path.module}/function.zip"
246+
}
247+
248+
resource "aws_lambda_function" "aurora_lambda" {
249+
depends_on = [
250+
aws_vpc.lambda_vpc,
251+
aws_subnet.lambda_subnet_1,
252+
aws_subnet.lambda_subnet_2,
253+
aws_security_group.aurora_sg,
254+
aws_rds_cluster.aurora_cluster,
255+
aws_iam_role.lambda_role
256+
]
257+
258+
function_name = var.lambda_function_name
259+
role = aws_iam_role.lambda_role.arn
260+
filename = data.archive_file.lambda_zip.output_path
261+
source_code_hash = data.archive_file.lambda_zip.output_base64sha256
262+
handler = var.lambda_handler
263+
runtime = var.lambda_runtime
264+
timeout = var.lambda_timeout
265+
memory_size = var.lambda_memory_size
266+
267+
environment {
268+
variables = {
269+
DB_ENDPOINT = aws_rds_cluster.aurora_cluster.endpoint
270+
DB_NAME = var.database_name
271+
DB_USERNAME = var.db_username
272+
DB_PASSWORD = var.db_password
273+
}
274+
}
275+
276+
vpc_config {
277+
subnet_ids = [aws_subnet.lambda_subnet_1.id, aws_subnet.lambda_subnet_2.id]
278+
security_group_ids = [aws_security_group.aurora_sg.id]
279+
}
280+
281+
tags = {
282+
Environment = var.environment
283+
}
284+
}

0 commit comments

Comments
 (0)