Topics on this page
Serverless Framework (AWS) Example
- Example Serverless Framework (
serverless.yml
) file - Example
serverless package
output - Example scan command
- Example Template Scanner API Output
Example Serverless Framework (serverless.yml
) file
app: aws-golang-rest-api-with-dynamodb
service: aws-golang-rest-api-with-dynamodb
frameworkVersion: "3"
provider:
name: aws
runtime: go1.x
region: us-east-1
environment:
DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
functions:
list:
handler: bin/list
package:
include:
- ./bin/list
events:
- http:
path: todos
method: get
resources:
Resources:
TodosDynamoDbTable:
Type: "AWS::DynamoDB::Table"
Properties:
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: ${self:provider.environment.DYNAMODB_TABLE}
Example serverless package
output
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application",
"Resources": {
"ServerlessDeploymentBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}
]
}
}
},
"ServerlessDeploymentBucketPolicy": {
"Type": "AWS::S3::BucketPolicy",
"Properties": {
"Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"PolicyDocument": {
"Statement": [
{
"Action": "s3:*",
"Effect": "Deny",
"Principal": "*",
"Resource": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":s3:::",
{
"Ref": "ServerlessDeploymentBucket"
},
"/*"
]
]
},
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":s3:::",
{
"Ref": "ServerlessDeploymentBucket"
}
]
]
}
],
"Condition": {
"Bool": {
"aws:SecureTransport": false
}
}
}
]
}
}
},
"ListLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/aws-golang-rest-api-with-dynamodb-dev-list"
}
},
"IamRoleLambdaExecution": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": ["lambda.amazonaws.com"]
},
"Action": ["sts:AssumeRole"]
}
]
},
"Policies": [
{
"PolicyName": {
"Fn::Join": [
"-",
["aws-golang-rest-api-with-dynamodb", "dev", "lambda"]
]
},
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:CreateLogGroup",
"logs:TagResource"
],
"Resource": [
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-golang-rest-api-with-dynamodb-dev*:*"
}
]
},
{
"Effect": "Allow",
"Action": ["logs:PutLogEvents"],
"Resource": [
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-golang-rest-api-with-dynamodb-dev*:*:*"
}
]
},
{
"Effect": "Allow",
"Action": [
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem"
],
"Resource": "arn:aws:dynamodb:us-east-1:*:table/aws-golang-rest-api-with-dynamodb-dev"
}
]
}
}
],
"Path": "/",
"RoleName": {
"Fn::Join": [
"-",
[
"aws-golang-rest-api-with-dynamodb",
"dev",
{
"Ref": "AWS::Region"
},
"lambdaRole"
]
]
}
}
},
"ListLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/aws-golang-rest-api-with-dynamodb/dev/1710062641444-2024-03-10T09:24:01.444Z/aws-golang-rest-api-with-dynamodb.zip"
},
"Handler": "bin/list",
"Runtime": "go1.x",
"FunctionName": "aws-golang-rest-api-with-dynamodb-dev-list",
"MemorySize": 1024,
"Timeout": 6,
"Environment": {
"Variables": {
"DYNAMODB_TABLE": "aws-golang-rest-api-with-dynamodb-dev"
}
},
"Role": {
"Fn::GetAtt": ["IamRoleLambdaExecution", "Arn"]
}
},
"DependsOn": ["ListLogGroup"]
},
"ListLambdaVersionJ684s4LZRbBw6J320LvKtLIeU1fR8jPz3N7XRVUU": {
"Type": "AWS::Lambda::Version",
"DeletionPolicy": "Retain",
"Properties": {
"FunctionName": {
"Ref": "ListLambdaFunction"
},
"CodeSha256": "h+adt3PlVl1Ojig8cC2oRoSspbiCI6OkH+atrtllc8c="
}
},
"ApiGatewayRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "dev-aws-golang-rest-api-with-dynamodb",
"EndpointConfiguration": {
"Types": ["EDGE"]
},
"Policy": ""
}
},
"ApiGatewayResourceTodos": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Fn::GetAtt": ["ApiGatewayRestApi", "RootResourceId"]
},
"PathPart": "todos",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayMethodTodosGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {},
"ResourceId": {
"Ref": "ApiGatewayResourceTodos"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": ["ListLambdaFunction", "Arn"]
},
"/invocations"
]
]
}
},
"MethodResponses": []
},
"DependsOn": ["ListLambdaPermissionApiGateway"]
},
"ApiGatewayDeployment1710062639137": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"StageName": "dev"
},
"DependsOn": ["ApiGatewayMethodTodosGet"]
},
"ListLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": ["ListLambdaFunction", "Arn"]
},
"Action": "lambda:InvokeFunction",
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"TodosDynamoDbTable": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"AttributeDefinitions": [
{
"AttributeName": "id",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "id",
"KeyType": "HASH"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 1,
"WriteCapacityUnits": 1
},
"TableName": "aws-golang-rest-api-with-dynamodb-dev"
}
}
},
"Outputs": {
"ServerlessDeploymentBucketName": {
"Value": {
"Ref": "ServerlessDeploymentBucket"
},
"Export": {
"Name": "sls-aws-golang-rest-api-with-dynamodb-dev-ServerlessDeploymentBucketName"
}
},
"ListLambdaFunctionQualifiedArn": {
"Description": "Current Lambda function version",
"Value": {
"Ref": "ListLambdaVersionJ684s4LZRbBw6J320LvKtLIeU1fR8jPz3N7XRVUU"
},
"Export": {
"Name": "sls-aws-golang-rest-api-with-dynamodb-dev-ListLambdaFunctionQualifiedArn"
}
},
"ServiceEndpoint": {
"Description": "URL of the service endpoint",
"Value": {
"Fn::Join": [
"",
[
"https://",
{
"Ref": "ApiGatewayRestApi"
},
".execute-api.",
{
"Ref": "AWS::Region"
},
".",
{
"Ref": "AWS::URLSuffix"
},
"/dev"
]
]
},
"Export": {
"Name": "sls-aws-golang-rest-api-with-dynamodb-dev-ServiceEndpoint"
}
}
}
}
Example scan command
#!/usr/bin/env bash
# Scans a template file
# Requires "serverless" (https://www.serverless.com/framework/docs/getting-started) to be installed
# Requires "jq" (https://stedolan.github.io/jq/) to be installed
api_key="Your Trend API Key"
api_base_url="https://conformity.us-1.cloudone.trendmicro.com/api"
# Modify serverless package command as needed depending on stage, region, etc.
serverless package --stage dev
contents=$( cat .serverless/cloudformation-template-update-stack.json | jq '.' -MRs)
payload="{\"data\":{\"attributes\":{\"type\":\"cloudformation-template\",\"contents\":${contents}}}}"
echo Request:
echo ${payload} | jq '.' -M
echo Response:
curl -s -X POST \
-H "Authorization: ApiKey ${api_key}" \
-H "Content-Type: application/vnd.api+json" \
${api_base_url}/template-scanner/scan \
--data-binary "${payload}" | jq '.' -M
Example Template Scanner API Output
Output truncated, actual number of checks generated for this template is greater than seen below.
{
"data": [
{
"type": "checks",
"id": "ccc:OrganisationId:S3-026:S3:global:ServerlessDeploymentBucket",
"attributes": {
"region": "global",
"status": "FAILURE",
"risk-level": "MEDIUM",
"pretty-risk-level": "Medium",
"message": "s3-bucket ServerlessDeploymentBucket doesn't have S3 Block Public Access feature enabled.",
"resource": "ServerlessDeploymentBucket",
"descriptorType": "s3-bucket",
"categories": ["security"],
"compliances": [
"AWAF",
"CISAWSF-1_5_0",
"CISAWSF-2_0",
"CIS-V8",
"NIST4",
"NIST5",
"SOC2",
"NIST-CSF",
"ISO27001",
"ISO27001-2022",
"AGISM",
"HIPAA",
"HITRUST",
"PCI",
"PCI-V4",
"APRA",
"FEDRAMP",
"MAS",
"ENISA",
"FISC-V9"
],
"last-updated-date": null,
"extradata": [
{
"label": "LocationConstraint",
"name": "LocationConstraint",
"value": "us-east-1",
"type": "META"
}
],
"tags": [],
"cost": 0,
"waste": 0,
"not-scored": false,
"ignored": false,
"rule-title": "Enable S3 Block Public Access for S3 Buckets",
"provider": "aws",
"resolution-page-url": "https://www.cloudconformity.com/knowledge-base/aws/S3/bucket-public-access-block.html",
"service": "S3",
"logicalResourceId": "ServerlessDeploymentBucket"
},
"relationships": {
"rule": {
"data": {
"type": "rules",
"id": "S3-026"
}
},
"account": {
"data": null
}
}
},
{
"type": "checks",
"id": "ccc:OrganisationId:DynamoDB-003:DynamoDB:us-east-1:todosdynamodbtable-tvifqyqn5qqy",
"attributes": {
"region": "us-east-1",
"status": "FAILURE",
"risk-level": "HIGH",
"pretty-risk-level": "High",
"message": "Continuous Backups aren't enabled for [todosdynamodbtable-tvifqyqn5qqy]",
"resource": "todosdynamodbtable-tvifqyqn5qqy",
"descriptorType": "dynamodb-table",
"categories": ["reliability"],
"compliances": [
"AWAF",
"CIS-V8",
"NIST4",
"NIST5",
"SOC2",
"NIST-CSF",
"ISO27001",
"ISO27001-2022",
"AGISM",
"HIPAA",
"HITRUST",
"ASAE-3150",
"PCI",
"PCI-V4",
"APRA",
"FEDRAMP",
"MAS",
"CSA",
"ENISA",
"FISC-V9"
],
"last-updated-date": null,
"tags": [],
"cost": 0,
"waste": 0,
"not-scored": false,
"ignored": false,
"rule-title": "DynamoDB Continuous Backups",
"provider": "aws",
"resolution-page-url": "https://www.cloudconformity.com/knowledge-base/aws/DynamoDB/continuous-backups.html",
"service": "DynamoDB",
"logicalResourceId": "todosdynamodbtable-tvifqyqn5qqy"
},
"relationships": {
"rule": {
"data": {
"type": "rules",
"id": "DynamoDB-003"
}
},
"account": {
"data": null
}
}
},
{
"type": "checks",
"id": "ccc:OrganisationId:Lambda-001:Lambda:us-east-1:aws-golang-rest-api-with-dynamodb-dev-list",
"attributes": {
"region": "us-east-1",
"status": "FAILURE",
"risk-level": "MEDIUM",
"pretty-risk-level": "Medium",
"message": "Function aws-golang-rest-api-with-dynamodb-dev-list isn't using the latest version of runtime environment",
"resource": "aws-golang-rest-api-with-dynamodb-dev-list",
"descriptorType": "lambda-function",
"categories": ["security", "reliability", "sustainability"],
"compliances": [
"AWAF",
"CIS-V8",
"NIST4",
"NIST5",
"SOC2",
"NIST-CSF",
"ISO27001",
"ISO27001-2022",
"AGISM",
"HIPAA",
"HITRUST",
"PCI",
"PCI-V4",
"APRA",
"FEDRAMP",
"MAS",
"ENISA",
"FISC-V9"
],
"last-updated-date": null,
"extradata": [
{
"name": "Runtime",
"label": "Runtime",
"value": "go1.x",
"type": "META"
},
{
"name": "Version",
"label": "Version",
"value": "1",
"type": "META"
},
{
"name": "MemorySize",
"label": "Memory Size",
"value": 1024,
"type": "META"
},
{
"name": "Timeout",
"label": "Timeout",
"value": 6,
"type": "META"
},
{
"name": "LastModified",
"label": "LastModified",
"value": "2024-03-10T09:24:02.930Z",
"type": "META"
}
],
"tags": [],
"cost": 0,
"waste": 0,
"not-scored": false,
"ignored": false,
"rule-title": "Lambda Using Latest Runtime Environment",
"provider": "aws",
"resolution-page-url": "https://www.cloudconformity.com/knowledge-base/aws/Lambda/runtime-environment.html",
"service": "Lambda",
"logicalResourceId": "aws-golang-rest-api-with-dynamodb-dev-list"
},
"relationships": {
"rule": {
"data": {
"type": "rules",
"id": "Lambda-001"
}
},
"account": {
"data": null
}
}
}
],
"meta": {
"missingParameters": [],
"errors": []
}
}