AWS lambda deploy

Michał Nowak

In this article, I will show how to deploy our lambda nodejs simple application using terraform. We will focus on how to connect our aws account with a local machine to easily apply terraform. In addition, we configure the API gateway to call lambda by HTTP method.

Access from a local machine to AWS

On the begging we want to configure access to AWS from our local machine by using aws-vault ((https://github.com/99designs/aws-vault))

IAM credentials

First we need to login to our AWS console and localize the user with whom we want to create access and get a secure access key.

IAM

Users

Create Access Key

Access Key

Before we get those parameters, Access key ID and Secreet access key we need to install on our machine aws-vault. After that, we can continue configuring our machines. We need to open a terminal (mac, linux) or cmd window (windows) and paste:

aws-vault add mn

Where mn is the profile’s name (as given by Michal Nowak).

After that, we will be asking for our generated credential.Access key ID and Secreet access key:

Configure the config file

We need to create a config file in the destination ~/.aws/config. So open this destination and add:

[profile mn]
region=eu-west-1
mfa_serial=arn:aws:iam::913600072448:mfa/michal.nowak

mfa_serial is taken from here:

(If you don’t have MFA you need to configure it).

Now we need to set our configured profile by command:

aws-vault exec mn

It will ask for an MFA code and, on Mac, for a keychain password. After login, we need to import key from:

cat ~/ .ssh/id_rsa.pub

to AWS console:

Go to ECS

Key pairs

Copy your code and add a name

Simple lambda aplication

AWS lambda is a serverless functionality that provides you with the ability to run your code easily, without a server infrastructure. For example, we can use lambda to invoke another service, perform some simple operations, and return a message to us. In our simple example, we mainly focused on how to apply the created lambda to AWS with terraform. In our case, lambda will only return a simple message.

Now let’s see some code. The whole project is available here: https://github.com/michaltomasznowak/aws_lambda

First let’s see lambda code. In our case lambda is a simple code in nodejs The path of code is: lambda/lambda.js:

module.exports.handler = async (event) => {
  console.log('Event: ', event);
  let responseMessage = 'Your first lambda!';

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      message: responseMessage,
    }),
  }
}

In this code, we will see the simple structure of nodejs lambda. We have:

module.exports.handler = async (event) => {
    // code 

    // in example we return json
    return json
}

Now we want to apply this to creating a lambda on AWS. To do this, we will create some terraform files. In this project, I created 3 files: terraform.tf , lambda.tf and variables.tf.

Providers configuration

The configuration related to the connection with AWS is configured in terraform.tf file. We have set providers and versions of the used terraform. (Providers will take the latest version)

terraform {
  required_providers {
    aws = {
      source  = "registry.terraform.io/hashicorp/aws"
    }
    random = {
      source  = "registry.terraform.io/hashicorp/random"
    }
    archive = {
      source  = "registry.terraform.io/hashicorp/archive"
    }
  }

  required_version = ">= 0.12"
}

Configuration of Lambda

lambda.tf is the core of our terraform project. Because lambda can have more than one file, we need to transfer it into a package. Here in data "archive_file" „lambda” we use .zip. In this part code, we tell what we want to zip and where we want to unzip after the transfer.

data "archive_file" "lambda" {
  type        = "zip"
  source_dir  = var.source_path
  output_path = "${var.source_path}.zip"
}

In the next lines we have resource "aws_lambda_function" "test_lambda" where there are a lot of properties:

  • functiofun_name name of displayed function
  • runtime environment to run lambda
  • handler point to the lambda file, which will be called after the lambda request
  • source_code_hash function to zip lambda
  • filename the path to the function’s deployment package within the local filesystem
  • role Amazon Resource Name (ARN) of the function’s execution role. The role provides the function’s identity and access to AWS services and resources
resource "aws_lambda_function" "test_lambda" {
  nctiofun_name = "lambda"
  runtime = "nodejs12.x"
  handler = "lambda.handler"
  source_code_hash = filebase64sha256(data.archive_file.lambda.output_path)
  filename         = data.archive_file.lambda.output_path
  role = aws_iam_role.lambda_exec.arn
}

A defined role is required to configure policy.

resource "aws_iam_role" "lambda_exec" {
  name = "serverless_lambda"

  assume_role_policy = jsonencode({
    Version = "1"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Sid    = ""
      Principal = {
        Service = "lambda.amazonaws.com"
      }
    }
    ]
  })
}

Define access for the lambda.

resource "aws_iam_role_policy_attachment" "lambda_policy" {
  role       = aws_iam_role.lambda_exec.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

Variables used in other terraform files

This variable is used to define the path of lambda in the project structure.

variable "source_path" {
  description = "Path to zip containing source code"
  type        = string
  default = "lambda"
}

Apply the changes to AWS

Before all the next steps, we need to install terrfarom on our computer. This is simple to do on a Mac with brew (https://brew.sh/) and on Windows with chocolatey (https://chocolatey.org/).

To apply changes to AWS, we need to use our previously configured credentials by aws-vault (it was done at the beginning of this article). We have 3 steps in this process:

INIT

The terraform init command is used to initialize a working directory containing Terraform configuration files.

aws-vault exec mn terraform init

PLAN

The terraform plan command creates an execution plan, which lets you preview the changes that Terraform plans to make to your infrastructure.

aws-vault exec mn terraform init

APPLY

The terraform apply command executes the actions proposed in a Terraform plan.

aws-vault exec mn terraform apply

After all these operations, you check lambda on your AWS console and you can see:

API Gateway

Now we want to call our lambda via HTTP. To do this, we need to configure the AWS API gateway. Here is a simple terraform configuration in file api_gateway.tf:

resource "aws_apigatewayv2_api" "lambda" {
  name          = "serverless_lambda_gw"
  protocol_type = "HTTP"
}

resource "aws_apigatewayv2_stage" "lambda" {
  api_id = aws_apigatewayv2_api.lambda.id

  name        = "serverless_lambda_stage"
  auto_deploy = true

}

resource "aws_apigatewayv2_integration" "lambda" {
  api_id = aws_apigatewayv2_api.lambda.id

  integration_uri    = aws_lambda_function.test_lambda.invoke_arn
  integration_type   = "AWS_PROXY"
  integration_method = "POST"
}

resource "aws_apigatewayv2_route" "lambda" {
  api_id = aws_apigatewayv2_api.lambda.id

  route_key = "GET /lambda"
  target    = "integrations/${aws_apigatewayv2_integration.lambda.id}"
}

resource "aws_lambda_permission" "api_gw" {
  statement_id  = "AllowExecutionFromAPIGateway"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.test_lambda.function_name
  principal     = "apigateway.amazonaws.com"

  source_arn = "${aws_apigatewayv2_api.lambda.execution_arn}/*/*"
}
  • aws_apigatewayv2_ap here we set HTTP as the communication protocol.
  • aws_apigatewayv2_stage here we set a single stage.
  • aws_apigatewayv2_integration.lambda connect our lambda to the API Gateway.
  • aws_apigatewayv2_route.lambda define the lambda endpoint.
  • aws_lambda_permission grants access to the lambda function.

After adding this file, we need to apply terraform changes by:

aws-vault exec mn terraform plan
aws-vault exec mn terraform apply

After that we will see in AWS console new API gateway:

If we go into serverless_lambda_gw we will see the endpoint for our lambda.

When we call https://t37t4yqgd5.execute-api.eu-west-1.amazonaws.com/serverless_lambda_stage/lambda (we need to add the lambda that was configured in aws_apigatewayv2_route.lambda) we should see a response from our lambda:

Summary

In this article, I wanted to demonstrate how simple and reliable a connection between our local machine and AWS can be Terraform is a very powerful tool that enables us to configure the whole AWS infrastructure. In this article we showed only a small part of the functionality relating to the aws-vault and lambdas. But even for more complicated projects, the flow is always similar and if you are familiar with simple examples, then you can easily build more advanced projects.

References

https://blog.j-labs.pl/cgblog/category/53/terraform.html/

Poznaj mageek of j‑labs i daj się zadziwić, jak może wyglądać praca z j‑People!

Skontaktuj się z nami