Serverless stack security guidelines

What is a stack?

Nic Wanavit
TenXor
2 min readSep 4, 2020

--

A stack is a collection of serverless functions, services, and database which are defined within a cloudformation stack in accordance to the cloudformation docs.

What is a serverless stack?

A serverless stack in the definition of villa market is where a stack does not contain any service that needs to be managed manually eg EC2, virtual machine, or Kubernetes-like services.

Features of a good serverless stack

a secure serverless stacks should have the following features

  1. permission should be defined within the template.yml file
  2. there should be no hard coded passwords/secret key in the stacks
  3. every function/services should have resource-based-permission set up within the template
  4. the stacks should not contain hard-coded resource names
  5. if connection to external stacks/service is required, all the secret keys should be stored using secret-manager or equivalent
  6. stack should be auto-deployed by an automated ci/cd tool, all the required environment variable should be stored securely within the tool

Example of a serverless stack design

Example of a good serverless app which contains a managed service

Design diagram

yaml cloudformation template docs

yaml docs should define all resources including functions and databases without hardcoding the resource names.

Resources:
getMember:
Type: AWS::Serverless::Function
Properties:
CodeUri: getSetData
Handler: app.getMember
Runtime: python3.8
FunctionName: !Join [ "-" , [ !Ref 'AWS::StackName', "get-member"]]
Policies:
- DynamoDBWritePolicy:
TableName: !Join [ "-" , ["member", "*", !Ref BRANCH]]
- DynamoDBReadPolicy:
TableName: !Join [ "-" , ["member", "*", !Ref BRANCH]]

MemberDatabase:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: hashedPhone
AttributeType: S
- AttributeName: memberId
AttributeType: S
BillingMode: PAY_PER_REQUEST
KeySchema:
- AttributeName: hashedPhone
KeyType: HASH
- AttributeName: memberId
KeyType: RANGE
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
TableName: !Join [ "-" , ["member", "database", !Ref BRANCH]]

Setting up Policies

AWS allows policies to be specified using the Policies: tag

Policies:
# use pre-defined sam policy template
- DynamoDBWritePolicy:
TableName: !Join [ "-" , ["member", "*", !Ref BRANCH]]
- DynamoDBReadPolicy:
TableName: !Join [ "-" , ["member", "*", !Ref BRANCH]]
# manually defined policy
- Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'cloudformation:Describe*'
- 'cloudformation:List*'
- 'cloudformation:Get*'
Resource: '*'

The users are able to set policies using pre-defined templated provided by the sam toolkit or define them manually using cloudfront guidelines

Resource based policy should be set up so that the entity is only callable by the specified function/iam entity. There are many tools to help with generating these including awsPolicyGenerator or reading this documentation

--

--