Creating an AWS Lambda Function with Terraform
Tags: terraform, aws, devops, sre
Published: 2023-02-16 12:18:06

## Creating an AWS Lambda Function with Terraform
Writing the proper Terraform code for an AWS Lambda function may seem like a daunting task but it doesn't have to be.

While there are a few moving parts to the process, I'll explain how to deploy a Lambda function to a VPC that can access other resources within your VPC using
appropriate IAM permissions.

Full code example here: https://github.com/terrateamio/terraform-aws-lambda-example

### `main.tf`
The below resources are examples and should be adjusted to suit your needs. The code can be added to your Terraform repository in a file named `main.tf`.

### Provider
Add the `aws` provider
```hcl
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

provider "aws" {
  region = "us-west-2"
}
```

### VPC
Create a new VPC
```hcl
resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true

  tags = {
    Name = "example-vpc"
  }
}
```

### Subnets
Create at least one subnet
```hcl
resource "aws_subnet" "example" {
  cidr_block = "10.0.1.0/24"
  vpc_id = aws_vpc.example.id
  availability_zone = "us-west-2b"

  tags = {
    Name = "example-subnet"
  }
}
```

### Security Group
Create a security group
```hcl
resource "aws_security_group" "example" {
  name_prefix = "example-sg"
  vpc_id = aws_vpc.example.id

  ingress {
    from_port = 0
    to_port = 65535
    protocol = "tcp"
    cidr_blocks = ["10.0.1.0/24"]
  }

  egress {
    from_port = 0
    to_port = 65535
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
```

### IAM Role and Policy
Create an IAM role and policy
```hcl
resource "aws_iam_role" "example" {
  name = "example-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = {
        Service = "lambda.amazonaws.com"
      }
    }]
  })
}

resource "aws_iam_policy" "example" {
  name        = "example-policy"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Action = [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ]
      Resource = ["arn:aws:logs:*:*:*"]
    },{
      Effect = "Allow"
      Action = [
        "ec2:CreateNetworkInterface",
        "ec2:DescribeNetworkInterfaces",
        "ec2:DeleteNetworkInterface"
      ]
      Resource = ["*"]
    }]
  })
}

resource "aws_iam_role_policy_attachment" "example" {
  policy_arn = aws_iam_policy.example.arn
  role = aws_iam_role.example.name
}
```

This IAM role and policy allows your Lambda function to create, describe, and delete network interfaces, and create and push logs to CloudWatch.

### Lambda Function
The last step is to create your actual Lambda function
```hcl
resource "aws_lambda_function" "example" {
  function_name    = "example-lambda"
  filename         = "lambda_function_payload.zip"
  source_code_hash = filebase64sha256("lambda_function_payload.zip")
  handler          = "index.handler"
  role             = aws_iam_role.example.arn
  runtime          = "nodejs14.x"
  vpc_config {
    subnet_ids = [aws_subnet.example.id]
    security_group_ids = [aws_security_group.example.id]
  }
}
```

### Verify Changes
View the changes to be deployed to your AWS account
```
$ terraform init
$ terraform validate
$ terraform plan
```

### Apply Changes
Create the AWS resources defined in your `main.tf`
```
$ terraform apply
```

## Conclusion
By following these steps, you can deploy an AWS Lambda function to a VPC with all the proper IAM permissions. Check out [Terrateam](https://terrateam.io) to learn how to safely `plan` and `apply` infrastructure changes alongside other code and with your teammates.