Logo

dev-resources.site

for different kinds of informations.

✨ Porting Lambda Functions to AWS SAM

Published at
4/23/2023
Categories
aws
lambda
sam
serverless
Author
gfabrizi
Categories
4 categories in total
aws
open
lambda
open
sam
open
serverless
open
Author
8 person written this
gfabrizi
open
✨ Porting Lambda Functions to AWS SAM

Two weeks ago I attended to JsDay 2023 (from Verona, Italy 🇮🇹).
One talk hit me in particular: "Production-ready lambdas with Node.js" by Luciano Mammino.
He explained some trick, tips and best practices to work with AWS Lambda in a production environment.
One best practice is this:

"Stop creating resources manually on your AWS account, like right now! If you are doing this, please STOP"

Everyone loves meme

Ok, when he said this i felt reaaallly really guilty.

AWS SAM

There are many IAC tools that can be used with AWS. Maybe the logic option (or the one that seems to fit better) is using AWS SAM.
The AWS Serverless Application Model (SAM) is a framework for building serverless applications. It's open-source and all the configuration can be written in YAML files.
It consists of a cli tool to be installed (it's separate from aws-cli); you can use it to deploy your infrastructure, deploy (and sync) your application, for local test of your code and much much more.
I confess that i never used it (really never even heard of it...) so let's learn it by porting a previous project in SAM.

THE PROJECT

The project is my previous "Lambda Inception Architectural Pattern" (quite a mouthful, right? 🤭):
https://dev.to/gfabrizi/lambda-inception-architectural-pattern-f67

In that post I wrote blocks and blocks of code to describe roles and policies of the infrastructure... how naive!
So let's start by looking at the SAM documentation:
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html
After digging the examples and the documentation I started writing my template.yaml

THE CODE

First thing first: the roles and policies.
The simplest role to be ported in SAM is the LambdaInceptionWorker:

LambdaInceptionWorker:
  Type: AWS::IAM::Role
  Properties:
    RoleName: LambdaInceptionWorker
    AssumeRolePolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
Enter fullscreen mode Exit fullscreen mode

just some boilerplate code were we define a role (Type: AWS::IAM::Role) and attach a AssumeRolePolicyDocument that says that every Lambda functions can assume this role. As we saw in the previous post, the LambdaInceptionWorker role is empty, so there's nothing more to add here.

Next is the LambdaInceptionManager:

LambdaInceptionManager:
  Type: AWS::IAM::Role
  Properties:
    RoleName: LambdaInceptionManager
    AssumeRolePolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
    ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    Policies:
      - PolicyName: LambdaInceptionPassRole
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - iam:PassRole
              Resource: !Sub arn:aws:iam::${AWS::AccountId}:role/LambdaInceptionWorker
      - PolicyName: LambdaInceptionCreateFunction
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - lambda:CreateFunction
              Resource: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:*
      - PolicyName: LambdaInceptionDeleteFunction
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - lambda:DeleteFunction
              Resource: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:*
      - PolicyName: LambdaInvokeFunction
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - lambda:InvokeFunction
              Resource: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:*

Enter fullscreen mode Exit fullscreen mode

Let's analyze the code section by section:

ManagedPolicyArns:
  - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Enter fullscreen mode Exit fullscreen mode

with this we are attaching an AWS managed policy to the role (the basic execution role, needed by Lambda Function URL).
Then we started adding inline policies to the role; we see just the first policy:

- PolicyName: LambdaInceptionPassRole
  PolicyDocument:
    Version: '2012-10-17'
    Statement:
      - Effect: Allow
        Action:
          - iam:PassRole
        Resource: !Sub arn:aws:iam::${AWS::AccountId}:role/LambdaInceptionWorker
Enter fullscreen mode Exit fullscreen mode

here we are creating a new inline policy called LambdaInceptionPassRole; this policy allows the iam:PassRole action only to the specified resource.
In the Resource line we specify the LambdaInceptionWorker role by passing it's ARN. We are using a builtin variable to specify the account id (${AWS::AccountId}). The keyword !Sub at the beginning of the line indicates that the string contains a variable to be replaced with it's value. Another useful builtin variable is ${AWS::Region}.
The others 3 policies have the same structure, so we skip them.

Then we create the IAM user that will invoke the Inception manager function from the command line:

LambdaInceptionInvoker:
  Type: AWS::IAM::User
  Properties:
    UserName: lambda-inception-invoker
    Policies:
      - PolicyName: LambdaInceptionInvoke
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - lambda:InvokeFunctionUrl
              Resource: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:lambda-inception
Enter fullscreen mode Exit fullscreen mode

The syntax of this block is the same as the previous, nothing new.

Finally we can write the definition of the Inception Manager function:

LambdaInceptionManagerFunction:
  Type: AWS::Serverless::Function
  Properties:
    FunctionName: "lambda-inception"
    CodeUri: manager/
    Handler: manager.handler
    Runtime: nodejs18.x
    Architectures:
      - x86_64
    MemorySize: 512
    Timeout: 30
    Role: !GetAtt LambdaInceptionManager.Arn
    FunctionUrlConfig:
      AuthType: AWS_IAM
    Environment:
      Variables:
        LAMBDA_INCEPTION_WORKER_ROLE: !GetAtt LambdaInceptionWorker.Arn
Enter fullscreen mode Exit fullscreen mode

we are using the type AWS::Serverless::Function to specify that we are defining a Lambda Function.
We gave it a name, specify the path where the code lies, the handler and some more common Lambda configuration.

Then we assign a role to the function. !GetAtt is another keyword that returns an attribute; in this case it returns the ARN of the LambdaInceptionManager role seen previously.

With the 3 last lines we pass a variable to the function handler. We can access this variable from the js code with process.env.LAMBDA_INCEPTION_WORKER_ROLE.

DEPLOY

The sam build command is used to processes the AWS SAM template file, application code, and any applicable language-specific files and dependencies (i.e. npm install).

Then we can launch sam deploy to deploy the infrastructure and code on AWS

SAM succesfully deployed

FINAL NOTES

It was quite a journey 😅
We saw how we can start using an IAC tool to define and manage a cloud infrastructure.
The infrastructure as defined here is far from perfect, this is just a learn-by-doing exercise.

The updated code can be downloaded from:
https://github.com/gfabrizi/lambda-inception-sam

Leave a comment for questions or issues with the code
Thank for reading! 👋

sam Article's
30 articles in total
Favicon
Running lambdas locally using Javascript/Node.js
Favicon
Cut Your AWS Lambda Logging Costs: Filter Logs with AWS SAM
Favicon
Building a "Real-Time" Data Integration Platform on AWS
Favicon
Using Amazon Cognito with the user-password flow
Favicon
SAM Registration and Maintenance Ensuring Your Business Stays Compliant
Favicon
Utilizing the System for Award Management SAM for Government Contracting Success
Favicon
Secure API Gateway with Amazon Cognito using SAM
Favicon
Resources and Properties for AWS SAM
Favicon
Adding Cognito Authentication to our Serverless Dash App
Favicon
Using YAML anchors and aliases in a SAM template
Favicon
First impressions of CloudFormation’s IaC generator and CDK migrate
Favicon
Building Scalable Serverless Applications with AWS SQS and Lambda using SAM
Favicon
How to add CI/CD to my SAM project
Favicon
How to create serverless applications with AWS SAM (Serverless Application Model)
Favicon
Introduction to AWS SAM (Serverless Application Model)
Favicon
Help! How do I set DeletionPolicy to Retain for production only?
Favicon
An efficient way to build your serverless microservices. Part 3. CI/CD with AWS SAM.
Favicon
Leveraging Infrastructure as Code (IaC) for AWS Lambda: A Comparative Analysis of AWS SAM, Terraform, and Serverless Framework
Favicon
AWS Lambda with Rust and SAM
Favicon
Deploying Lambdas with AWS SAM & GitHub Actions: Step by Step
Favicon
Speed up new serverless application development with customized SAM templates
Favicon
Streamline AWS Development with CI/CD, SAM, and GitHub Actions
Favicon
AWS sam #3: sam local + ApiGateway Lambda authorizer
Favicon
✨ Porting Lambda Functions to AWS SAM
Favicon
Store Thumbnails from Your Live Stream Using AWS SAM CLI to Set Up Lambda Function and API Gateway
Favicon
AWS sam #2: sam local + logs
Favicon
AWS sam #1: sam local + DynamoDB
Favicon
Event-driven file management using S3 Notifications and Step Functions
Favicon
Folding as a Service with AWS StepFunctions
Favicon
Elevating Your Serverless Development with AWS SAM

Featured ones: