Skip to content
Sandny Blog
  • Home
  • Java
  • JavaScript
  • AWS
  • Embedded
  • About
Create Lambda function with Terraform Node.js

How to create Lambda function with Terraform

  • October 6, 2022October 6, 2022
  • by Coder Kai

Terraform is a great IaaS framework that helps to automate cloud infrastructure easily. We will see how we can create an AWS lambda function with Terraform.

1. Initialize the terraform script with AWS

Create a file called main.tf in the folder you want to initialize the project. Then add the following provider block to main.tf which allow it to work with AWS infrastructure as the cloud service provider.

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "us-west-1"
  profile = "test" # name of the profile in credentials file
}

here we have defined profile = "test" to use of the test profile from AWS credentials located in ~/.aws/credentials file.

Next, we have to define the resources to create the lambda function.

2. Create an archive to upload using archive_file

We need to archive the code containing the lambda function. For that, we can use archive_file data source.

The file structure for the lambda function is as follows.

  ./lambda 
      main.tf
      /function
         index.js
         package.json

We need to archive the function folder and upload it to the lambda function. We can achieve it by following code block. This also has another resource that installs node_modules when running apply before archive using yarn. The local-exec command will perform that.


# Archive lambda function
data "archive_file" "main" {
  type        = "zip"
  source_dir  = "lambda/function"
  output_path = "${path.module}/.terraform/archive_files/function.zip"

  depends_on = [null_resource.main]
}

# Provisioner to install dependencies in lambda package before upload it.
resource "null_resource" "main" {

  triggers = {
    updated_at = timestamp()
  }

  provisioner "local-exec" {
    command = <<EOF
    yarn
    EOF

    working_dir = "${path.module}/lambda/function"
  }
}

3. Lambda function

For this example, I have used a simple hello world with a nanoID token.

import {nanoid} from 'nanoid'

export const handler = async (event) => {
  console.log('Event: ', JSON.stringify(event));

  return {
    status: 200,
    body: `Hello world! Your token is: ${nanoid()}`
  }
}

And the node modules are installed with the following package.json file.

{
  "name": "lambda",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "author": "",
  "dependencies": {
    "nanoid": "^4.0.0"
  }
}

This has nanoid dependency and it will be installed with the null_resource.main block using yarn.

Now we need to create resources to upload the lambda function in AWS account. For that, we can use aws_lambda_function resource.

resource "aws_lambda_function" "lambda_hello_world" {
  filename      = "${path.module}/.terraform/archive_files/function.zip"
  function_name = "lambda-hello-world"
  role          = aws_iam_role.lambda_hello_world_role.arn
  handler       = "index.handler"
  runtime       = "nodejs16.x"
  timeout = 300

  source_code_hash = data.archive_file.main.output_base64sha256
}

resource "aws_iam_role" "lambda_hello_world_role" {
  name               = "lambda_hello_world_role"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
  inline_policy {
    name = "lamda-hello-world-policy"
    policy = jsonencode({
      "Version" : "2012-10-17",
      "Statement" : [
        {
          "Sid" : "LambdaHelloWorld1",
          "Effect" : "Allow",
          "Action" : [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents",
          ],
          "Resource" : "*"
        }
      ]
    })
  }
}

And also as in the above code we need to define the IAM policy for the lambda function and its defined using aws_iam_role resource.

The full code will look like the following.

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

provider "aws" {
  region  = "us-east-1"
  profile = "profile_name"
}

# Archive lambda function
data "archive_file" "main" {
  type        = "zip"
  source_dir  = "lambda/function"
  output_path = "${path.module}/.terraform/archive_files/function.zip"

  depends_on = [null_resource.main]
}

# Provisioner to install dependencies in lambda package before upload it.
resource "null_resource" "main" {

  triggers = {
    updated_at = timestamp()
  }

  provisioner "local-exec" {
    command = <<EOF
    yarn
    EOF

    working_dir = "${path.module}/lambda/function"
  }
}

resource "aws_lambda_function" "lambda_hello_world" {
  filename      = "${path.module}/.terraform/archive_files/function.zip"
  function_name = "lambda-hello-world"
  role          = aws_iam_role.lambda_hello_world_role.arn
  handler       = "index.handler"
  runtime       = "nodejs16.x"
  timeout = 300

  # upload the function if the code hash is changed
  source_code_hash = data.archive_file.main.output_base64sha256
}

resource "aws_iam_role" "lambda_hello_world_role" {
  name               = "lambda_hello_world_role"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
  inline_policy {
    name = "lamda-hello-world-policy"
    policy = jsonencode({
      "Version" : "2012-10-17",
      "Statement" : [
        {
          "Sid" : "LambdaHelloWorld1",
          "Effect" : "Allow",
          "Action" : [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents",
          ],
          "Resource" : "*"
        }
      ]
    })
  }
}

4. How to create the infrastructure

First, download the necessary libraries to run the main.tf file you have created by executing the following

terraform init
Create Lambda function with Terraform - terraform init

After that, you can run terraform apply to apply the changes to the backend. Note that it will ask for the changes that going to be applied in the backend first. You have to confirm it by typing yes.

Create Lambda function with Terraform - terraform apply

Now you can test your lambda function after the code is applied. And it will print as following.

{
  "status": 200,
  "body": "Hello world! Your token is: _ffz8vIrfyIFUybwu0v14"
}

5. Conclusion

The following points are not addressed by the implementation

  • It’s not minifying the codebase and just copies the node_modules directly.
  • Doesn’t support type checkers like typescript

This can be overcome by using bundlers like webpack. We can dive into this in another post in future on create Lambda function with Terraform and typescript with package bundlers.

How to read AWS credential profiles with Terraform
Coder Kai
A humble developer
archive lambda before uploading terraform iam policy terraform lambda function terraform lambda resource null_resource

Related articles

Create Lambda function with Terraform
How to read AWS credential…
Immutable and Mutable Values in Javascript
07. Immutable and Mutable Values…
SSL Websocket using Nginx Proxy
SSL Websocket proxy with Nginx…

Categories

  • android 3
  • Apollo Client 1
  • AWS 8
    • AppSync 5
    • EC2 1
    • EKS 1
    • Route53 1
    • S3 1
  • AWS Amplify 1
  • Chakra UI 1
  • Docker 1
  • Embedded 1
  • EmberJS 1
  • FCM 1
  • Godaddy 1
  • GraphQL 3
  • ios 1
  • Jasper 1
  • Java 10
    • Java 11 1
    • Java 14 1
  • JavaEE 2
  • JavaScript 39
    • Express.js 4
    • Javascript Guide 7
    • Node.js 3
    • react-native 4
    • React.js 17
    • Typescript 1
  • Kubernetes 1
  • machine learning 1
  • Maven 2
  • OCaml 3
  • PostgreSQL 1
  • Python 2
  • react-native 4
  • ReactJS 3
  • sass 1
  • Server 6
  • spark 1
  • Terraform 2
  • Ubuntu 4
  • Uncategorized 1
  • webpack 2

Recent Comments

  • pg soft on Android/iOS React-native heap limit allocation failed error
  • pengeluaran china on Android/iOS React-native heap limit allocation failed error
  • jeannette on How to create Lambda function with Terraform

Meta

  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org

Archives

  • October 2022 3
  • September 2022 7
  • May 2022 1
  • December 2021 1
  • August 2021 1
  • July 2021 6
  • June 2021 3
  • February 2021 1
  • July 2020 1
  • December 2019 5
  • November 2019 6
  • October 2019 3
  • August 2019 1
  • March 2019 1
  • February 2019 1
  • January 2019 2
  • December 2018 1
  • September 2018 2
  • August 2018 1
  • June 2018 1
  • February 2018 1
  • November 2017 2
  • October 2017 5
  • September 2017 1
  • June 2017 1
  • May 2017 10
Sandny Blog space
Theme by Colorlib Powered by WordPress