7

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?

3 Answers 3

14

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)

Sign up to request clarification or add additional context in comments.

2 Comments

Good example you have put here. Nevertheless it is not good to have user/password part of that serverless.yml. Because in the end, that its uploaded to S3, cloudformation will run it and the lambda will have the user/password in its environment.
@Edmond its an age old question of config at build time vs run time. I agree with you though that a more secure way would be for the lambda code to retrieve secrets from SSM (or whatever data store) at runtime, using its iam role to do so.
4

I suggest to use AWS SDK to get SSM parameters in code instead of saving in environment file (i.e. .env). It's more secure that way. You need to assign permission to the role you use with action=ssm:GetParameter and resource point to the parameter in the SSM Parameter store. I use serverless framework for deployment. Below is what I have in serverless.yml assumming parameter names with pattern "{stage}-myproject-*" (e.g. dev-myproject-username, qa-myproject-password):

custom:
  myStage: ${opt:stage}
provider:
  name: aws
  runtime: nodejs10.x
  stage: ${self:custom.myStage}
  region: us-east-1
  myAccountId: <aws account id>
  iamRoleStatements:
    - Effect: Allow
      Action:
        - ssm:GetParameter
      Resource: "arn:aws:ssm:${self:provider.region}:${self:provider.myAccountId}:parameter/${self:provider.stage}-myproject-*"

two useful resources are listed below: where to save credentials? wireless framework IAM doc

1 Comment

How do iamRoleStatements apply under the provider vs on the individual resources / lambda functions? Where do these end up getting tied to the lambda(s)?
0

In the case you are using codebuild in a ci/cd pipeline, dont forget to add the ssm authorization policies to the codebuild service role. (when we are talking about ssm we have to differenciate between secretsmanager and parametstore)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.