AWS Lambda configuration scheme

Building servlerless applications with AWS lambda and not sure how to setup your configuration per environment? Here’s an approach that keeps things neat and tidy, yet allows for secure configuration values as well.

For the example we’ll be using the servlerless framework, but you could use a similar approach with SAM.

Configuration

With Lambda each environment is a stage. We’ll setup each stage (aka environment) in our serverless config like this:

service: my-service
 
custom:
  default:
    prefix: my-service-prefix
    db_user: ssm://${self:custom.default.prefix}-${self:provider.stage}-db-user
    db_pwd: ssm://${self:custom.default.prefix}-${self:provider.stage}-db-pwd
  dev:
    db_host: host.hash.us-west-2.rds.amazonaws.com
    db_user: ${self:custom.default.db_user}
    db_password: ${self:custom.default.db_pwd}n_dev_1
    db_database: my-service-db
 
provider:
    name: aws
    runtime: nodejs8.10
    stage: ${opt:stage, 'dev'}
    region: us-west-2
    environment:
        db_host: ${self:custom.${self:provider.stage}.db_host}
        db_user: ${self:custom.${self:provider.stage}.db_user}
        db_password: ${self:custom.${self:provider.stage}.db_password}
        db_database: ${self:custom.${self:provider.stage}.db_database}

In the provider section we’ll set the stage by defaulting to ‘dev’ or taking the stage from the command line. This stage is referenced elsewhere to control stage specific settings. In the custom section we’ve define defaults and settings for the dev stage.

Server Side

Take note of how some values are plain text (db_database) and other values have the prefix ssm://. The ssm values have names that start with the service prefix and include the stage in the path. This prevents ssm name collisions between services and stages within a single service.

To accomplish this you’ll need some javascript code in your lambda:

var AWS = require('aws-sdk');
var ssm = new AWS.SSM({region: 'us-west-2'});
 
module.exports = {
    getEnvironment: async function (paramName) {
        let value = process.env[paramName];
        if (value.substr(0, 6) === 'ssm://') {
            var params = {
                Name: value.substr(6, value.length),
                WithDecryption: true
            };
            let request = await ssm.getParameter(params).promise();
            value = request.Parameter.Value;
        }
        return value;
    }
};

To reference an environment variable use this code (assuming the code above is imported as env):

let user = await env.getEnvironment('db_user');

Conclusion

This approach allows for configuration values to be set as environment variables or ssm values interchangeably. It also provides for default values that can be easily changed per environment.

About the Author

Phil True profile.

Phil True

Principal Technologist

Phil is a veteran software engineer and technologist with over 24 years of experience. Phil is a proven communicator known for his ability to work with all levels within an organization. He is equally at home in the code, working with clients and senior management and has had leadership roles in most projects. He has a proven ability in web services based integration layer including security, performance and reliability. He’s also an expert JEE and UI developer and designer with expertise in AJAX and RESTful architecture.

Leave a Reply

Your email address will not be published.

Related Blog Posts
Building Better Data Visualization Experiences: Part 1 of 2
Through direct experience with data scientists, business analysts, lab technicians, as well as other UX professionals, I have found that we need a better understanding of the people who will be using our data visualization products in order to build them. Creating a product utilizing data with the goal of providing insight is fundamentally different from a typical user-centric web experience, although traditional UX process methods can help.
Kafka Schema Evolution With Java Spring Boot and Protobuf
In this blog I will be demonstrating Kafka schema evolution with Java, Spring Boot and Protobuf.  This app is for tutorial purposes, so there will be instances where a refactor could happen. I tried to […]
Redis Bitmaps: Storing state in small places
Redis is a popular open source in-memory data store that supports all kinds of abstract data structures. In this post and in an accompanying example Java project, I am going to explore two great use […]
Let’s build a WordPress & Kernel updated AMI with Packer
First, let’s start with What is an AMI? An Amazon Machine Image (AMI) is a master image for the creation of virtual servers in an AWS environment. The machine images are like templates that are configured with […]