Serverless Framework - Setting up resource permissions for dynamodb - aws-lambda

I've the following serverless.yml file.
I'm trying to assign read write permissions to the generated dynamodb..
So far it generates my lambda and the dynamodb table but the lambda isn't assigned permissions to access it.
I get no errors and it doesn't seem to add the permission to the dynamodb table.
Can anyone shed any light please?
service:
name: catcam
custom:
stage: ${opt:stage, self:provider.stage}
tableName: ${self:custom.stage}-notes
environment:
tableName: ${self:custom.tableName}
plugins:
- '#hewmen/serverless-plugin-typescript'
- serverless-plugin-optimize
- serverless-offline
provider:
name: aws
runtime: nodejs12.x
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- { "Fn::GetAtt": ["NotesTable", "Arn" ] }
# - { !GetAtt NotesTable.Arn }
functions:
main: # The name of the lambda function
# The module 'handler' is exported in the file 'src/lambda'
handler: src/lambda.handler
events:
- http:
method: any
path: /{any+}
resources:
Resources:
NotesTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:custom.tableName}
AttributeDefinitions:
- AttributeName: userId
AttributeType: S
- AttributeName: noteId
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
- AttributeName: noteId
KeyType: RANGE
# Set the capacity to auto-scale
BillingMode: PAY_PER_REQUEST

Turns out there was nothing wrong with the above, it's correct!!.. it's was me being a banana and not matching the full name of the table with the environment in the application.. i.e. notes table becomes dev-notes for instance.. maybe the above will help someone.

Related

How to fix Unresolved resource dependencies [ApiGatewayRestApi] in the Resources block of the template

I am trying to set the ApiGatewayRestApi to an environment variable. I am getting the following error while trying to deploy using "sls deploy" :
The CloudFormation template is invalid: Template format error: Unresolved resource dependencies [ApiGatewayRestApi] in the Resources block of the template.
Here is the serverless.yml file:
service: upranklytoolsApi
frameworkVersion: '2 || 3'
provider:
name: aws
runtime: nodejs12.x
region: us-east-1
stage: dev
apiGateway:
minimumCompressionSize: 1024
environment:
RestApiId:
Ref: ApiGatewayRestApi
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:DescribeTable"
- "dynamodb:PutItem"
- "dynamodb:Get*"
- "dynamodb:Scan*"
- "dynamodb:Query"
- "dynamodb:UpdateItem"
- "dynamodb:DeleteItem"
- "dynamodb:BatchWriteItem"
- "lambda: InvokeFunction"
- "lambda: InvokeAsync"
- "dynamodb:ConditionCheckItem"
Resource: arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-ranktrackerTable-${self:provider.stage}
- Effect: Allow
Action:
- cognito-idp:CreateUserPool
- cognito-idp:DeleteUserPool
- cognito-idp:UpdateUserPool
- cognito-idp:DescribeUserPool
Resource: '*'
custom:
serverless-offline:
port: 5000
dynamodb:
stages:
- dev
start:
port: 8000
inMemory: true
migrate: true
plugins:
- serverless-dynamodb-local
- serverless-step-functions
- serverless-offline-lambda-invoke
- serverless-offline
functions:
createKey:
handler: handlers/createKey.main
events:
- httpApi:
path: /keyw
method: post
updateKey:
handler: handlers/updateKeyw.main
events:
- httpApi:
path: /{userName}/keyw/{id}
method: put
# CREDITS
addCreditTransaction:
handler: handlers/addCreditTransaction.main
events:
- httpApi:
path: /{userName}/credit-transactions/{transType}
method: post
resources:
Resources:
RankTrackerTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Delete
Properties:
TableName: ${self:service}-rankTable-${sls:stage}
AttributeDefinitions:
- AttributeName: "pk"
AttributeType: "S"
- AttributeName: "sk"
AttributeType: "S"
- AttributeName: "gsi1pk"
AttributeType: "S"
- AttributeName: "gsi1sk"
AttributeType: "S"
- AttributeName: "gsi3pk"
AttributeType: "S"
KeySchema:
- AttributeName: "pk"
KeyType: "HASH"
- AttributeName: "sk"
KeyType: "RANGE"
BillingMode: "PAY_PER_REQUEST"
GlobalSecondaryIndexes:
- IndexName: 'gsi1'
KeySchema:
- AttributeName: "gsi1pk"
KeyType: "HASH"
- AttributeName: "gsi1sk"
KeyType: "RANGE"
Projection:
ProjectionType: ALL
- IndexName: "gsi3"
KeySchema:
- AttributeName : "gsi3pk"
KeyType: "HASH"
Projection:
ProjectionType: ALL
CognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: ${self:service}-${self:provider.stage}-user-pool
UsernameAttributes:
- email
AutoVerifiedAttributes:
- email
CognitoUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: ${self:service}-${self:provider.stage}-user-pool-client
UserPoolId:
Ref: CognitoUserPool
ExplicitAuthFlows:
- ADMIN_NO_SRP_AUTH
GenerateSecret: false
I have found the error. Instead of using 'ApiGatewayRestApi" if I use "HttpApi" I get the desired result.
environment:
RestApiId:
Ref: HttpApi

Import DynamoDB Table - YML

I have a serverless yml file for node project with aws. Also I have a dynamodb table in another file. I can deploy the project with no issues, however VSCode is showing a red alert problem in my import line: Incorrect type expected...
serverless.yml
service: auction-service
plugins:
- serverless-bundle
- serverless-pseudo-parameters
provider:
name: aws
runtime: nodejs12.x
memorySize: 256
stage: ${opt:stage, 'dev'}
region: eu-west-1
environment:
AUCTIONS_TABLE_NAME: ${self:custom.AuctionsTable.name}
iam:
role:
statements:
- ${file(iam/AuctionsTableIAM.yml):AuctionsTableIAM}
resources:
Resources:
AuctionsTable: ${file(resources/AuctionsTable.yml):AuctionsTable}
functions:
createAuction:
handler: src/handlers/createAuction.handler
events:
- http:
method: POST
path: /auction
custom:
AuctionsTable:
name: !Ref AuctionsTable
arn: !GetAtt AuctionsTable.Arn
bundle:
linting: false
AuctionsTable.yml:
[![AuctionsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: AuctionsTable--${self:provider.stage}
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH][1]][1]
Try This
resources:
Resources:
- ${file(resources/AuctionsTable.yml):AuctionsTable}
Note, you will need to add the name AuctionsTable to the imported file.

Unable to interpolate values in Serverless Framework for AWS

I'm trying to organize this serverless YML file, but getting failures.I've scanned their docs for understanding how to interpolate via file substitution and I just can't figure it out:
I've read all these:
https://www.serverless.com/framework/docs/providers/aws/guide/variables#reference-properties-in-other-files
https://forum.serverless.com/t/split-up-include-reference-serverless-yml-file/3747
https://github.com/AnomalyInnovations/serverless-stack-demo-api/blob/master/serverless.yml#L128-L137
ERRORS
Serverless Error ----------------------------------------
The CloudFormation template is invalid: [/Resources/IamRoleLambdaExecution/Type/Policies/0/PolicyDocument/Statement/2] 'null' values are not allowed in templates
Serverless.yaml
service: newsletter
frameworkVersion: '2'
plugins:
- serverless-bundle
provider:
name: aws
runtime: nodejs12.x
memorySize: 256
stage: ${opt:stage, 'dev'}
region: us-west-2
iamRoleStatements:
- ${file(resources/iam/UsersSubscriptionTable.yml):UsersSubscriptionTableIAM}
resources:
- ${file(/resources/dynamo/UsersSubscriptionTable.yml):UsersSubscriptionTable}
functions:
createEmailEntry:
handler: src/Email.addUser
events:
- http:
method: POST
path: /subscribe
removeEmailEntry:
handler: src/Email.removeUser
events:
- http:
method: GET
path: /unsubscribe
# Not recommended for production-use
custom:
bundle:
linting: false
resources/iam/UsersSubscriptionTable.yml
Resources:
UsersSubscriptionTableIAM:
Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:GetItem
Resource:
- arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/MyCoolTable
resources/dynamo/UsersSubscriptionTable.yml
Resources:
UsersSubscriptionTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: MyCoolTable
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: email
AttributeType: S
KeySchema:
- AttributeName: email
KeyType: HASH
This was a huge pain to figure out:
provider:
name: aws
runtime: nodejs12.x
memorySize: 256
stage: ${opt:stage, 'dev'}
region: us-west-2
iam:
role:
statements:
- ${file(resources/iam/UsersSubscriptionTable.yml):UsersSubscriptionTableIAM}
resources:
Resources:
UsersSubscriptionTable: ${file(resources/dynamo/UsersSubscriptionTable.yml):UsersSubscriptionTable}
Resources shouldn't be an array in this case.
In addition, the iam role statement shouldn't have a resources top-level item in the yml either:
UsersSubscriptionTableIAM:
Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:GetItem
Resource:
- arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/MyCoolTable
UsersSubscriptionTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: MyCoolTable
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: email
AttributeType: S
# Specifies the email as the partition key (primary key)
KeySchema:
- AttributeName: email
KeyType: HASH

ARN for Query on DynamoDB index is not working

I want to query an index in a DynamoDB table. When doing so I get the following error:
User: arn:aws:sts::XXX:assumed-role/bifr-dev-us-east-1-lambdaRole/bifr-dev-login is not authorized to perform: dynamodb:Query on resource: arn:aws:dynamodb:us-east-1:XXX:table/customers/index/email_index
After trying to fix it with the proposed configs in AccessDenied on DynamoDB GSI Index and AWS and DynamoDB permissions: "User is not authorized to access this resource" I came to the follwoing config, that still does not work. The same error persist. Maybe someone could help me with solving this problem.
Table config:
resources:
Resources:
customers:
Type: AWS::DynamoDB::Table
Properties:
TableName: customers
AttributeDefinitions:
- AttributeName: "id"
AttributeType: S
- AttributeName: "email"
AttributeType: S
KeySchema:
- AttributeName: "id"
KeyType: HASH
BillingMode: PAY_PER_REQUEST
GlobalSecondaryIndexes:
- IndexName: 'email_index'
KeySchema:
- AttributeName: 'email'
KeyType: 'HASH'
Projection:
ProjectionType: 'ALL'
IAM Role config:
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:UpdateItem
- dynamodb:PutItem
- dynamodb:Scan
Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/*"
- Effect: Allow
Action:
- dynamodb:Query
Resource: "arn:aws:dynamodb:us-east-1:250781267785:table/customers/index/email_index"
NodeJS code for the query:
var res = await aws.QueryItems({
TableName: tableName,
IndexName: 'email_index',
KeyConditionExpression: '#email = :email',
ExpressionAttributeNames: {
"#email": "email"
},
ExpressionAttributeValues: {
":email": email
}
});
According to https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazondynamodb.html#amazondynamodb-table
you need to add the ARN for the table to the dynamodb:Query IAM statement.
The problem was the indentation. The iamRoleStatements must be a child of the provider.
Here my working config:
provider:
name: aws
runtime: nodejs12.x
region: us-east-1
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:UpdateItem
- dynamodb:PutItem
- dynamodb:Scan
Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/*"
- Effect: Allow
Action:
- dynamodb:Query
Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/customers/index/*"

Dynamo UpdateItem AccessDeniedException with default LambdaRole

I'm having difficulties getting the right role to execute a Dynamo UpdateItem in my golang lambda handler.
I've deployed the function using the serverless framework with the following config:
provider:
name: aws
runtime: go1.x
stage: ${opt:stage, 'dev'}
environment: ${file(./env/config.${self:provider.stage}.yml)}
iamRoleStatements: # TODO: create special roles and restrict access per lambda
- Effect: Allow
Action:
- dynamodb:DescribeTable
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- "Fn::GetAtt": [ myTable, Arn ]
resources:
Resources:
myTable:
Type: 'AWS::DynamoDB::Table'
Properties:
TableName: myTable-${opt:stage, 'dev'}
AttributeDefinitions:
- AttributeName: UserID
AttributeType: S
KeySchema:
- AttributeName: UserID
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
functions:
myFunc:
handler: bin/myFunc
events:
- http:
path: myFunc
method: post
authorizer: app-auth
cors: true
The handler uses the golang aws-sdk to create a session and call UpdateItem on the table:
sess, err := session.NewSession()
svc := dynamodb.New(sess)
input := &dynamodb.UpdateItemInput{
...
}
_, err = svc.UpdateItem(input)
This throws the exception:
AccessDeniedException: User: arn:aws:sts::{acct}:assumed-role/myservice-stage-us-east-1-lambdaRole/myservice-stage-myfunc
The User: arn:aws:sts::{acct}:assumed-role/myservice-stage-us-east-1-lambdaRole is a role that has the correct permissions:
I'm not sure what the /myservice-stage-myfunc part of the User is in the exception as nothing of the sort exists in the IAM console.
Is there some kind of config step I'm missing. To my knowledge, the IAM permissions setup in the serverless.yaml should apply to all functions. However, the assumed role for when working with the go-aws-sdk seems wrong.
DynamoDB has sub resources that often need access. To ensure that you are also addressing those sub items I would recommend adding a wildcard * onto the end of the resource. To do this I prefer to use the serverless-pseudo-parameters plugin (you can install it quickly with serverless plugin install --name serverless-pseudo-parameters) and then use it to more cleanly describe the resource like:
Resource:
- arn:aws:dynamodb:#{AWS::Region}:#{AWS::AccountId}:table/myTable-${opt:stage, 'dev'}*

Resources