How to use parameter store with serverless framework

This example contains serveless framework project that manages lambda functions inside VPC.

Most of the time we don't want to commit our app configuration settings to the source repository. Instead of using config files or hard coding configuration inside yaml file we can leverage parameter store which is a part of AWS System Manager Service.

NOTE: If you are not familiar with parameter store I recommend reading AWS System Manager Parameter Store docs.

Let's assume that we have requirement to create lambda function that will access serverless aurora. According to AWS Docs you can't give an Aurora Serverless DB cluster a public IP address. You can access an Aurora Serverless DB cluster only from within a virtual private cloud (VPC) based on the Amazon VPC service.

Instead of juggling with networking, digging tunnels, spawning EC2 instances we can make our lambda run inside the VPC. We do so by adding VPC configuration to our yaml file.

PREREQUISITIES:

  • Configure VPC with 3 subnets and default security group.
  • Add policies to allow lambda to access RDS and SSM
  • Add name value pairs to parameter store
{
  "SUBNET_ID_1": "subnet-*******",
  "SUBNET_ID_2": "subnet-*******",
  "SUBNET_ID_3": "subnet-*******",
  "AURORA": { 
    "host": "hostname",
    "port": 3306,
    "user": "username",
    "password": "password",
    "database": "database"   
  }
}

YAML

service: ssm-params-aurora 

provider:
  name: aws
  runtime: nodejs10.x
  iamManagedPolicies:
    - arn:aws:iam::aws:policy/AmazonSSMFullAccess
    - arn:aws:iam::aws:policy/AmazonRDSFullAccess
  vpc:
    securityGroupIds:
      - ${ssm:SECURITY_GROUP_1}
    subnetIds:
      - ${ssm:SUBNET_ID_1}
      - ${ssm:SUBNET_ID_2}
      - ${ssm:SUBNET_ID_3}

functions:
  aurora:
    handler: aurora.handler
    events:
     - http:
        cors: true
        path: ssm
        method: get

Configuration above referencing system manager service named parameters. By default, when a Lambda function is executed inside a VPC, it loses internet access and some resources inside AWS may become unavailable. AWS supports SSM VPC endpoint that will allow us to access SSM from our lambda that is running inside VPC.

Go to VPC console -> endpoints -> click Create endpoint button -> select AWS Service then com.amazonaws.REGION.ssm from the list. Continue by selecting your VPC, subnets and security groups then click on Create endpoint button at the bottom of the screen.
Don’t forget to add policy that will allow our lambda to access SSM parameters and policy that will allow access to aurora API's. I have added two AWS IAM managed policies to allow this.

iamManagedPolicies:
  - arn:aws:iam::aws:policy/AmazonSSMFullAccess
  - arn:aws:iam::aws:policy/AmazonRDSFullAccess

You can create IAM role statement by yourself and create fine grained access to given services.

When deployed, lambda will run inside VPC. Assuming that aurora is inside same VPC we will be able to connect and query database. The rest of the code is straightforward. I will use mysql2 node module to connect with credentials retrieved from parameter store and query users table that I have in my database.

const mysql = require('mysql2');
const AWS = require('aws-sdk');
const ssm = new AWS.SSM({apiVersion: '2014-11-06'});

const response = (statusCode, body) => {
  return {
    statusCode, 
    body: JSON.stringify(body)
  }
}

const handler = async (event) => {

  try {
    const AURORA = await ssm.getParameter({ Name: 'AURORA' }).promise();
    const { host, database, port, user, password } = JSON.parse(AURORA['Parameter']['Value']);

    const connection = await mysql.createConnection({
      host,
      port,
      database,
      user,
      password
    });

    const [rows] = await connection.promise().query('SELECT * from users');
    return response(200, rows);
  
  } catch(err) {
    return response(500, { message: 'server error' });
  }

};

module.exports = { handler }

Now deploy and test your service. If all goes well you should be able to see results of the query in your response.

NOTE: You don't need to install aws-sdk module as it is part of lambda environment.

Full source code is available on GitHub.