In the ever-evolving landscape of cloud computing, automation becomes the cornerstone of efficiency, scalability, and reliability. As businesses move towards serverless architectures, tools like Terraform offer streamlined deployment solutions. This article aims to guide you through automating the deployment of serverless applications on AWS using Terraform. By the end, you'll have a solid grasp of how to set up a lambda function, configure an API Gateway, and manage related resources effectively.
Serverless architecture eliminates the need for server management, allowing developers to focus on writing code. In an AWS context, Lambda functions are at the heart of this paradigm. These functions are stateless, event-driven units of code that execute in response to triggers such as HTTP requests, database changes, or file uploads.
To understand how to automate deployments using Terraform, it's crucial to familiarize yourself with some fundamental components:
These elements will be orchestrated using Terraform scripts to achieve a cohesive serverless infrastructure.
Terraform is an Infrastructure as Code (IaC) tool that enables you to define and provision your cloud infrastructure using a declarative configuration language. This section provides a clear roadmap to create and manage your serverless resources.
Before you start, ensure you have Terraform and AWS CLI installed and configured on your machine.
# To install Terraform
brew install terraform
# To install AWS CLI
brew install awscli
# Configure AWS CLI
aws configure
Create a new directory for your Terraform project and initialize it:
mkdir my-serverless-app
cd my-serverless-app
terraform init
Now, create a main.tf
file where you'll define your infrastructure:
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "website_bucket" {
bucket = "my-unique-bucket-name"
acl = "public-read"
website {
index_document = "index.html"
error_document = "error.html"
}
}
resource "aws_lambda_function" "my_lambda" {
function_name = "my_lambda_function"
role = aws_iam_role.lambda_exec.arn
handler = "index.handler"
runtime = "nodejs14.x"
filename = "lambda_function.zip"
source_code_hash = filebase64sha256("lambda_function.zip")
}
resource "aws_iam_role" "lambda_exec" {
name = "lambda_exec_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy" "lambda_exec_policy" {
name = "lambda_exec_policy"
role = aws_iam_role.lambda_exec.id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:*",
"cloudwatch:*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}
Run the Terraform commands to apply your configuration:
terraform plan
terraform apply
This will set up your S3 bucket, Lambda function, and IAM role with the necessary permissions.
Once your basic infrastructure is in place, the next step is to configure API Gateway to expose your Lambda functions via RESTful APIs.
Add the API Gateway configuration to your main.tf
file:
resource "aws_api_gateway_rest_api" "my_api" {
name = "my_api"
description = "My API Gateway"
}
resource "aws_api_gateway_resource" "my_resource" {
rest_api_id = aws_api_gateway_rest_api.my_api.id
parent_id = aws_api_gateway_rest_api.my_api.root_resource_id
path_part = "myresource"
}
resource "aws_api_gateway_method" "my_method" {
rest_api_id = aws_api_gateway_rest_api.my_api.id
resource_id = aws_api_gateway_resource.my_resource.id
http_method = "GET"
authorization = "NONE"
}
resource "aws_lambda_permission" "api_gateway" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.my_lambda.function_name
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_rest_api.my_api.execution_arn}/*/*"
}
resource "aws_api_gateway_integration" "lambda_integration" {
rest_api_id = aws_api_gateway_rest_api.my_api.id
resource_id = aws_api_gateway_resource.my_resource.id
http_method = aws_api_gateway_method.my_method.http_method
type = "AWS_PROXY"
integration_http_method = "POST"
uri = aws_lambda_function.my_lambda.invoke_arn
}
Save the above changes and apply the Terraform configuration again:
terraform apply
This will create an API Gateway REST API, configure a resource and method, and integrate it with your Lambda function.
In addition to API services, you can host a static website on AWS using S3 and CloudFront. This section covers the essential steps to achieve this.
Your Terraform configuration already includes an S3 bucket with website hosting enabled. Now, upload your static files to this bucket.
aws s3 cp index.html s3://my-unique-bucket-name/
aws s3 cp error.html s3://my-unique-bucket-name/
Enhance the delivery of your website by setting up a CloudFront distribution:
resource "aws_cloudfront_distribution" "my_distribution" {
origin {
domain_name = aws_s3_bucket.website_bucket.bucket_regional_domain_name
origin_id = "s3-my-unique-bucket-name"
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.my_identity.cloudfront_access_identity_path
}
}
enabled = true
is_ipv6_enabled = true
comment = "My CloudFront distribution"
default_root_object = "index.html"
default_cache_behavior {
target_origin_id = "s3-my-unique-bucket-name"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
Run terraform apply
to create the CloudFront distribution. This will provide you with a fast and secure URL for your static website.
Setting up IAM roles and policies is crucial for ensuring that your resources are secure. Follow these guidelines to create robust security policies.
Ensure your Lambda functions have the necessary permissions by defining IAM roles and policies:
resource "aws_iam_role" "lambda_exec" {
name = "lambda_exec_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy" "lambda_exec_policy" {
name = "lambda_exec_policy"
role = aws_iam_role.lambda_exec.id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:*",
"cloudwatch:*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}
Automating the deployment of serverless applications using Terraform in the AWS cloud ecosystem is an efficient way to manage and scale your infrastructure. By defining your resources, such as Lambda functions, API Gateway, and S3 buckets, in Terraform scripts, you can ensure a consistent and repeatable deployment process. Adding CloudFront distributions enhances the performance and security of your static websites.
Embrace the power of IaC with Terraform, and streamline the configuration and deployment of your AWS resources. This automation not only saves time but also reduces the probability of human errors, leading to a more reliable and scalable cloud environment.
By following the guidelines and examples provided in this article, you are now well-equipped to automate your serverless deployments, ensuring that your applications are ready for the future.