AWS Compute Blog

Simplify Serverless Applications with Environment Variables in AWS Lambda

Gene Ting
Gene Ting, Solutions Architect

Lambda developers often want to configure their functions without changing any code. In this post, we show you how to use environment variables to pass settings to your Lambda function code and libraries.

Creating and updating a Lambda function

First, create a Lambda function that uses some environment variables. Here’s a simple but realistic example that allows you to control the log level of a Lambda function by setting an environment variable called, “LOG_LEVEL”. After you have created the code, pass values into LOG_LEVEL so your code can read it.


'use strict';

const logLevels = {error: 4, warn: 3, info: 2, verbose: 1, debug: 0};

// get the current log level from the current environment if set, else set to info
const currLogLevel = process.env.LOG_LEVEL != null ? process.env.LOG_LEVEL : 'info';

// print the log statement, only if the requested log level is greater than the current log level
function log(logLevel, statement) {
    if(logLevels[logLevel] >= logLevels[currLogLevel] ) {
        console.log(statement);
    }
}

// return the monthly payment, rounded to the cent. FOR DEMO PURPOSES ONLY
function monthlyPayment(principal, rate, years) {
    var fv = Math.pow(1+rate/1200, years * 12);
    return Number(Math.round(principal * (rate/1200*fv) / (fv - 1) + 'e2') + 'e-2'); 
}

exports.handler = (event, context, callback) => {
    log('debug', "principal: " + event.principal + " - rate: " + event.rate + " - years: " + event.years);
    callback(null, monthlyPayment(event.principal, event.rate, event.years));
};

Now, here’s how to get those values into the code. You can do this through the console, you can also do it programmatically with full API and CLI support. In the console, a new section below the Lambda function allows you to specify environment variables.

By default, Lambda chooses the default KMS service key for Lambda. Passing custom keys is supported, but not required.

If you use the default KMS service key for Lambda, then you dont need additional IAM permissions in your execution role – your role works automatically without any changes.

If you supply your own, custom KMS key, then you need to allow “kms:Decrypt”, as shown below in a basic execution role.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:us-east-1:xxxxxxxxxxxx:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:xxxxxxxxxxxx:log-group:/aws/lambda/mortgageCalc:*"
            ]
        }
    ]
}

Test your function and see environment variables in action.

Testing your Lambda function

First, in the Lambda console, configure a test event for this function, using the following JSON snippet:

{
  "principal": 100000,
  "rate": 6,
  "years": 30
}

Next, run the function by pressing “Test”:

You should verify the result of the calculator, but what’s really interesting is what you see in the logs. With the logging level set to ‘info’, no debug information should appear:

Change LOG_LEVEL to ‘debug’ and re-run the function:

Choose “Test” again, and examine the logs: you should see that the additional debugging logs appear. Console output can be found within the log stream for the function in Amazon CloudWatch Logs:

Targeting a table based on a given phase of a deployment lifecycle

In the example above, you used environment variables to modify the behavior of a Lambda function without changing its code. Here’s another typical use of environment variables: Providing stage-specific settings for code as it moves through lifecycle stages from development to deployment. Environment variables can be used to provide settings for resources, such as a development database password versus the production database password.

The example code below shows how to point an Amazon DynamoDB client in Java to a table that varies across stages. It also demonstrates how environment variables can be read in a Java-based Lambda function, using System.getenv.

//Write to the appropriate table based on the current environment

AmazonDynamoDBClient dynamoDB = new AmazonDynamoDBClient();
Table table = dynamoDB.getTable(System.getenv(TARGET_TABLE));
Item item = new Item();
table.putItem(item);

Based on the value of “TARGET_TABLE”, the function connects to different tables. Because you change only the configuration, not your code, you know that the behavior is unchanged as you promote from one stage to another; only the environment variable settings change.

Conclusion

Environment variables bring a new level of simplicity to working with Lambda functions. In this post, we described how to use environment variables to:

  • Change Lambda function behavior, such as switching the logging level, without changing the code
  • Configure access to stage-specific resources, such as a DynamoDB table name or a SQL table password, as your code progresses from development to production.

For more information, see Environment Variables in the AWS Lambda Developer Guide. Happy coding everyone, and have fun creating awesome serverless applications!