Table of contents

Serverless Framework (AWS) Example

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": []
  }
}