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?

sudo soul
  • 1,504
  • 13
  • 20

3 Answers3

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)

ruohola
  • 21,987
  • 6
  • 62
  • 97
sudo soul
  • 1,504
  • 13
  • 20
  • 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 Jun 21 '20 at 20:32
  • @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. – sudo soul Jun 29 '20 at 17:00
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

Raymond
  • 115
  • 2
  • 11
  • 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)? – Charlie Schliesser Oct 16 '20 at 02:10
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)

DonMehdi
  • 11
  • 1