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