Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serverless Framework - What permissions do I need to use AWS SSM Parameter Store?

I'm opening this question because there seems to be no documentation on this, so I would like to provide the answer after much time wasted in trial and error.

As background, the Serverless framework [allows loading both plaintext & SecureString values from AWS SSM Parameter Store].1

What permissions are needed to access & load these SSM Parameter Store values when performing serverless deploy?

like image 955
sudo soul Avatar asked May 21 '19 16:05

sudo soul


People also ask

What is SSM in serverless framework?

Serverless SSM Fetch is an "AWS provider only" plugin that allows to fetch parameters from AWS Store Parameters and assign them to serverless. yml functions environment variables.

How do I access AWS parameter store from Lambda?

In order to grant a Lambda function access to an SSM parameter, we have to attach an IAM policy to the function's execution role. The policy should grant permissions for all the Actions the function needs to perform on the SSM parameter.

How do I pass an environment variable in serverless?

To reference environment variables, use the ${env:SOME_VAR} syntax in your serverless. yml configuration file. It is valid to use the empty string in place of SOME_VAR . This looks like " ${env:} " and the result of declaring this in your serverless.


1 Answers

In general, accessing & decrypting AWS SSM parameter store values requires these 3 permissions:

  1. ssm:DescribeParameters
  2. ssm:GetParameters
  3. kms:Decrypt

-

Here's a real world example that only allows access to SSM parameters relating to my lambda functions (distinguished by following a common naming convention/pattern) - it works under the following circumstances:

  1. SecureString values are encrypted with the default AWS SSM encryption key.
  2. All parameters use the following naming convention

    a. /${app-name-or-app-namespace}/serverless/${lambda-function-name/then/whatever/else/you/want

    b.${lambda-function-name} must begin with sls-

So let's say I have an app called myCoolApp, and a Lambda function called sls-myCoolLambdaFunction. Perhaps I want to save database config values such as username and password.

I would have two SSM parameters created:

  1. /myCoolApp/serverless/sls-myCoolLambdaFunction/dev/database/username (plaintext)

  2. /myCoolApp/serverless/sls-myCoolLambdaFunction/dev/database/password (SecureString)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:DescribeParameters"
            ],
            "Resource": [
                "arn:aws:ssm:${region-or-wildcard}:${aws-account-id-or-wildcard}:*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameter"
            ],
            "Resource": [
                "arn:aws:ssm:${region-or-wildcard}:${aws-account-id-or-wildcard}:parameter/myCoolApp/serverless/sls-*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": [
                "arn:aws:kms:*:${aws-account-id}:key/alias/aws/ssm"
            ]
        }
    ]
}

Then in my serverless.yml file, I might reference these two SSM values as function level environment variables like so

environment:
      DATABASE_USERNAME: ${ssm:/myCoolApp/serverless/sls-myCoolLambdaFunction/dev/database/username}
      DATABASE_PASSWORD: ${ssm:/myCoolApp/serverless/sls-myCoolLambdaFunction/dev/database/password~true}

Or, even better, if I want to be super dynamic for situations where I have different config values depending on the stage, I can set the environment variables like so

environment:
      DATABASE_USERNAME: ${ssm:/myCoolApp/serverless/sls-myCoolLambdaFunction/${self:provider.stage}/database/username}
      DATABASE_PASSWORD: ${ssm:/myCoolApp/serverless/sls-myCoolLambdaFunction/${self:provider.stage}/database/password~true}

With this above example, if I had two stages - dev & prod, perhaps I would create the following SSM parameters:

  1. /myCoolApp/serverless/sls-myCoolLambdaFunction/dev/database/username (plaintext)

  2. /myCoolApp/serverless/sls-myCoolLambdaFunction/dev/database/password (SecureString)

  3. /myCoolApp/serverless/sls-myCoolLambdaFunction/prod/database/username (plaintext)

  4. /myCoolApp/serverless/sls-myCoolLambdaFunction/prod/database/password (SecureString)

like image 174
sudo soul Avatar answered Nov 05 '22 13:11

sudo soul