Integrating SSM with serverless Applications
Tags: aws, serverless
Published: 2022-11-24 14:55:28

We always think about ways to include env vars for different environments where they can be used by various team members and stored in one place.
Using AWS SSM will help you achieve that.

In this article, I'll be taking you into the steps to create a serverless app that can use SSM for env vars on different environments. 

To create a serverless framework app, let's make sure that you have the package installed globally by running `serverless`

- Pick `AWS - Node.js - Starter` to create a starter kit app
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rzpnsafhh21cx6zcftw8.png)
- Choose a name for the project in "What do you want to call this project?"
- Put "no" as an answer for the next steps, as we don't need to log in or deploy.

After those steps, you should have a serverless starter app created for you.

Let's use the AWS CLI to create an SSM param but first, ensure you have the [CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) installed locally.

Create two SSM params for dev and prod:
Dev:
<pre>
aws ssm put-parameter \
    --name "/api/dev/url" \
    --value "http://prod.api.com" \
    --type String
</pre>
Prod:
<pre>
aws ssm put-parameter \
    --name "/api/prod/url" \
    --value "http://prod.api.com" \
    --type String
</pre>
`
To confirm that the param is created, you can get one of the created params:
<pre>
aws ssm get-parameter --name "/api/prod/url"
</pre>

To use those params in our serverless app, let's create two files in the serverless app project having:
`env.dev.yml`:
<pre>
API_URL: ${ssm:/api/dev/url}
</pre>

`env.prod.yml`:
<pre>
API_URL: ${ssm:/api/dev/url}
</pre>

Edit your `serverless.yml` to be:
<pre>
service: aws-demo-serverless-project

frameworkVersion: '3'

provider:
  stage: ${opt:stage, "dev"}
  name: aws
  runtime: nodejs14.x
  environment: ${file(./env.${self:provider.stage}.yml)}

custom:
  serverless-offline:
    httpPort: 4000

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get

plugins:
  - serverless-offline
</pre>

To run the app locally, install the `serveless-offline` package. You can create this `package.json` file in your demo project and run `npm install`:
<pre>
{
  "name": "serverless-ssm-demo",
  "version": "1.0.0",
  "description": "",
  "main": "handler.js",
  "devDependencies": {
    "serverless-offline": "^11.1.3"
  },
  "scripts": {
    "serve": "serverless offline"
  },
  "author": "",
  "license": "ISC"
}
</pre>

As you can already see, we added a `serve` script in the app, which will use the `serverless-offline` package to run the application offline.

Now we can start using the above-created env var `API_URL` in our application. To do so, we can update the existing `handler.js` file:
<pre>
'use strict';

module.exports.hello = async (event) => {
  return {
    statusCode: 200,
    body: JSON.stringify(
      {
        message: process.env.API_URL
      },
      null,
      2
    ),
  };
};
</pre> 

Let's test that printing the value of the `API_URL` will work by running `yarn serve`.
After a successful run, you can check the output of the app by opening http://localhost:4000/dev/hello in your browser or running `curl http://localhost:4000/dev/hello` using your terminal:
<pre>
{
  "message": "http://dev.api.com"
}
</pre>

Awesome! 👏 we are ready to deploy our app to different environments where each one has different env vars values
Add some scripts to your existing `package.json`:

1. `"deploy:env": "sls deploy --stage $NODE_ENV"`
2. `"deploy:dev": "NODE_ENV=stage yarn deploy:env"`
3. `"deploy:production": "NODE_ENV=production yarn deploy:env"`

Or replace this below ready `package.json` with the existing one:
<pre>
{
  "name": "serverless-ssm-demo",
  "version": "1.0.0",
  "description": "",
  "main": "handler.js",
  "devDependencies": {
    "serverless-offline": "^11.1.3"
  },
  "scripts": {
    "serve": "serverless offline",
    "deploy:env": "sls deploy --stage $NODE_ENV",
    "deploy:dev": "NODE_ENV=dev yarn deploy:env",
    "deploy:production": "NODE_ENV=production yarn deploy:env"
  },
  "author": "",
  "license": "ISC"
}
</pre>

Let's start deploying to the dev environment by running `yarn deploy:dev`
After a success, serverless will return an endpoint for you in the terminal, copy it, and open it in your browser. You should see the value of the dev env var:
<pre>
{
  "message": "http://dev.api.com"
}
</pre>

Repeat the same by running `yarn deploy:production` and opening the new prod endpoint in your browser. Now you should see the production env var instead:
<pre>
{
  "message": "http://prod.api.com"
}
</pre>

Congrats! 🥳 now you can use the same solution to add more env vars with the ability to be used in different environments.

Link to the GitHub repo: https://github.com/bardawilpeter/integrating-ssm-serverless-framework