How to automate the deployment of serverless applications using Terraform?

12 June 2024

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.

Understanding the Basics of Serverless Architecture

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.

Key Components

To understand how to automate deployments using Terraform, it's crucial to familiarize yourself with some fundamental components:

  • Lambda Functions: The core of serverless applications, running your code in response to specified events.
  • API Gateway: Acts as a front door for your application, providing a way to expose Lambda functions to the internet.
  • S3 Buckets: Used for storing static assets like HTML, CSS, and JavaScript files.
  • IAM Roles and Policies: Define permissions to access AWS resources securely.
  • CloudFront Distribution: Ensures fast content delivery globally.

These elements will be orchestrated using Terraform scripts to achieve a cohesive serverless infrastructure.

Setting Up Your Infrastructure with Terraform AWS

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.

Installing Terraform and AWS CLI

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

Writing Your First Terraform Script

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
}

Running Terraform

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.

Configuring API Gateway for Lambda Functions

Once your basic infrastructure is in place, the next step is to configure API Gateway to expose your Lambda functions via RESTful APIs.

Defining the API Gateway in Terraform

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
}

Applying the Configuration

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.

Hosting a Static Website with S3 and CloudFront

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.

Configuring S3 Website Bucket

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/

Setting Up CloudFront Distribution

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.

Policies, Roles, and Security Best Practices

Setting up IAM roles and policies is crucial for ensuring that your resources are secure. Follow these guidelines to create robust security policies.

Creating IAM Roles and 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
}

Best Practices

  1. Minimal Permissions: Grant the least privileges necessary for the roles and policies.
  2. Regular Audits: Regularly review and update your IAM roles and policies to ensure they adhere to best practices and security standards.
  3. Logging and Monitoring: Use AWS CloudWatch and CloudTrail to monitor activities and maintain logs for auditing purposes.

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.

Copyright 2024. All Rights Reserved