Reproducibly Setting Production Environment Variables for AWS Lambda Apps

The problem with infinitely flexible building blocks is that there are always a half-dozen well-documented ways to do things wrong.

I wanted my AWS Lambda app (I refuse to call it a “function” because it isn’t) to get the third-party API keys it needs from environment variables. Not from hardcoded strings or config files.

The most immediately accessible way to set up env vars for a Lambda is via the AWS console. But that’s not a reproducible, versionable workflow I can capture in my project.

Searching for info on setting up environment variables in a SAM-based AWS Lambda app turns up a lot of results. It seems you can set variables in the SAM config in template.yaml.

  Type: AWS::Serverless::Function
    CodeUri: hello_world/
    Handler: app.lambda_handler
    Runtime: python3.7
        API_KEY: 12345...

More usefully, you can define env vars that apply to all of your functions by putting them in the globals section that normally lives at the top of template.yaml

# ...
      API_KEY: 12345...

Which is all great, except that I explicitly don’t want these variable values to apply universally, and I don’t want them to be checked-in to my repo. I just want to set them for my production deployment.

My searching next took me down the rabbit hole of AWS Systems Manager Parameter Store. But that’s way too heavyweight a solution for what I want to do.

Finally, I realized that I could probably set env vars via the aws CLI (not sam). Like everything to do with AWS, the command isn’t particularly intuitive, but here’s what I cam up with:

aws --region us-east-1 lambda  update-function-configuration \
   --function-name myapp-MyFunction-1234ABCD \
   --environment "Variables={API_KEY=12345}"

Some points to note:

  1. Nothing worked until I explicitly set the –region
  2. Environment variables are part of a “function configuration”
  3. The function name for a SAM-managed app is the full name that SAM invents, including the app name, the function name, and some ID garbage at the end.
  4. You can’t just set environment variables directly; that would be too easy. You need to pass Variables={...}, where the contents of the curly braces are key=value pairs delimited by commas.

This gives me a documentable, reproducible template for setting API key environment variables in just the production deployment. Which is what I wanted.