Unable to interpolate values in Serverless Framework for AWS - aws-lambda

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

Related

Lambda(Serverless Framework) + DynamoDB Accelerator(DAX): App can not connect

i created my app using AWS(API Gateway/Lambda/DynamoDB).
but loading speed of the app is too late.
so, i want to improve the loading speed using DynamoDB DAX(cache).
serverless.yml
service: myapp
frameworkVersion: '2.31'
provider:
name: aws
runtime: nodejs14.x
lambdaHashingVersion: 20201221
stage: $opt:stage
region: us-east-1
iamRoleStatements:
- Effect: Allow
Action:
- dax:*
Resource: '*'
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: '*'
vpc:
securityGroupIds:
- !GetAtt daxSecurityGroup.GroupId
subnetIds:
- !Ref daxSubnet
functions:
graphql:
handler: ./build/src/app.handler
events:
- http:
path: graphql
method: ANY
environment:
DAX_ENDPOINT: !GetAtt daxCluster.ClusterDiscoveryEndpoint
vpc:
securityGroupIds:
- !GetAtt daxSecurityGroup.GroupId
subnetIds:
- !Ref daxSubnet
resources:
Resources:
daxCluster:
Type: AWS::DAX::Cluster
Properties:
ClusterName: dax-cluster
IAMRoleARN: !GetAtt daxRole.Arn
NodeType: dax.t2.small
ReplicationFactor: 1
SecurityGroupIds:
- !GetAtt daxSecurityGroup.GroupId
SubnetGroupName: !Ref daxSubnetGroup
daxRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- dax.amazonaws.com
Version: '2012-10-17'
RoleName: dax-role
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess
daxSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security Group for Dax
GroupName: dax-security-group
VpcId: !Ref daxVpc
daxSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
DependsOn: daxSecurityGroup
Properties:
GroupId: !GetAtt daxSecurityGroup.GroupId
IpProtocol: tcp
FromPort: 8111
ToPort: 8111
SourceSecurityGroupId: !GetAtt daxSecurityGroup.GroupId
daxVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: dax-cluster
daxSubnet:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ''
CidrBlock: 10.0.0.0/20
Tags:
- Key: Name
Value: dax-cluster
VpcId: !Ref daxVpc
daxSubnetGroup:
Type: AWS::DAX::SubnetGroup
Properties:
Description: Subnet group for DAX
SubnetGroupName: dax-subnet-group
SubnetIds:
- !Ref daxSubnet
MyTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:provider.stage}_table
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
app.ts
import { DynamoDB } from "aws-sdk";
import AmazonDaxClient from "amazon-dax-client";
export default async() {
...
const endpoint = process.env.DAX_ENDPOINT as string;
const config = { ... }
const dax: any = new AmazonDaxClient({endpoints: [endpoint], region: 'us-east-1'});
const dynamodb = new DynamoDB.DocumentClient({...config, service: dax});
await dynamodb.transactWrite({
TransactItems: [
{
Delete: {
TableName: 'development_table',
Key: {
id: args.id,
createdAt: createdAt
}
}
},
],
}).promise();
return ( ... )
}
My App can not connect to API Gateway.(Timeout)
Please help me, That's very kind of you.
i tried...
serverless.yml
...
functions:
graphql:
handler: ./build/src/app.handler
events:
- httpApi:
path: /{id+}
method: GET
- httpApi:
path: /
method: POST
...
But, App can not connect.
i referred to AWS blog
package
"#types/amazon-dax-client": "^1.2.3",
"amazon-dax-client": "^1.2.9",

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.

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/*"

Serverless Framework - Setting up resource permissions for dynamodb

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.

Resources