
AWS lambda deploy
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.
Michał Nowak |
03 Oct 2022
## 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:
```bash
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:
```bash
[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:
```bash
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:
```bash
cat ~/ .ssh/id_rsa.pub
```
to AWS console:
### Go to ECS

### Key pairs

### Import 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`:
```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:
```js
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
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.
```terraform
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
```terraform
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.
```terraform
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.
``` terraform
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.
```terraform
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.
```bash
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.
```bash
aws-vault exec mn terraform init
```
## APPLY
The terraform apply command executes the actions proposed in a Terraform plan.
```bash
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`:
```terraform
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:
```bash
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://github.com/99designs/aws-vault/
- https://docs.aws.amazon.com/
## More related info on the blog
https://blog.j-labs.pl/cgblog/category/53/terraform.html/
Michał Nowak
Java developer with over 7 years of experience. A fan of breaking down problems into smaller ones that are easier to solve.
Did you like this article?
5,0 / 1