Skip to content

Commit

Permalink
feat(queires): add serverless framework queries (#5679)
Browse files Browse the repository at this point in the history
* stage

* stage

* first ServerlessFW Queries

* changes

* add changes

* change azure func name

* change resource Name

* update utilities.md
  • Loading branch information
cxMiguelSilva committed Aug 18, 2022
1 parent e2fd843 commit 067d476
Show file tree
Hide file tree
Showing 61 changed files with 925 additions and 91 deletions.
37 changes: 37 additions & 0 deletions assets/libraries/serverlessfw.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package generic.serverlessfw

import data.generic.common as common_lib

resourceTypeMapping(resourceType, provider)= resourceTypeVal{
resourceTypeVal :=resourcesMap[provider][resourceType]
}

resourcesMap = {
"aws": {
"function": "AWS::Lambda",
"api": "AWS::ApiGateway",
"iam": "AWS::IAM"
},
"azure":{
"function": "Azure:Function",
"api": "Azure:APIManagement",
"iam": "Azure:Role"
},
"google":{
"function": "Google:Cloudfunctions",
"api": "Google:ApiGateway",
"iam": "Google:IAM"
},
"aliyun":{
"function": "Aliyun:FunctionCompute",
"api": "Aliyun:ApiGateway",
"iam": "Aliyun:RAM"
}
}

get_service_name(document) = name{
name := document.service.name
} else = name {
is_string(document.service)
name := document.service
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"queryName": "Serverless Function Without Tags",
"severity": "MEDIUM",
"category": "Insecure Configurations",
"descriptionText": "AWS Serverless Function must have associated tags",
"descriptionText": "AWS Serverless Function should have associated tags",
"descriptionUrl": "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-tags",
"platform": "CloudFormation",
"descriptionID": "fa1b224c",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": "a4d32883-aac7-42e1-b403-9415af0f3846",
"queryName": "Serverless API Access Logging Setting Undefined",
"severity": "MEDIUM",
"category": "Observability",
"descriptionText": "Serverless FW API should have HTTP Access Logging enabled",
"descriptionUrl": "https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml#logs",
"platform": "ServerlessFW",
"descriptionID": "15262598"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package Cx

import data.generic.common as common_lib
import data.generic.serverlessfw as sfw_lib

CxPolicy[result] {
document := input.document[i]
logs := document.provider.logs
restAPI := logs.restApi

restAPI.accessLogging == false

result := {
"documentId": input.document[i].id,
"resourceType": sfw_lib.resourceTypeMapping("api", document.provider.name),
"resourceName": sfw_lib.get_service_name(document),
"searchKey": sprintf("provider.logs.restApi.accessLogging", []),
"issueType": "IncorrectValue",
"keyExpectedValue": "provider.logs.restApi should have 'accessLogging' set to true",
"keyActualValue": "provider.logs.restApi has 'accessLogging' set to false",
"searchLine": common_lib.build_search_line(["provider", "logs", "restApi", "accessLogging"], []),
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
service: myservice
frameworkVersion: '2'
provider:
name: aws
logs:
# Enable HTTP API logs
# This can either be set to `httpApi: true` to use defaults, or configured via subproperties
# Can only be configured if the API is created by Serverless Framework
httpApi:
format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength" }'

# Enable REST API logs
# This can either be set to `restApi: true` to use defaults, or configured via subproperties
# Can only be configured if the API is created by Serverless Framework
restApi:
# Enables HTTP access logs (default: true)
accessLogging: true
# Log format to use for access logs
format: 'requestId: $context.requestId'
# Enable execution logging (default: true)
executionLogging: true
# Log level to use for execution logging: INFO or ERROR
level: INFO
# Log full requests/responses for execution logging (default: true)
fullExecutionData: true
# Existing IAM role to use for API Gateway when writing CloudWatch Logs (default: automatically created)
role: arn:aws:iam::123456:role
# Whether the API Gateway CloudWatch Logs role setting is not managed by Serverless (default: false)
roleManagedExternally: false

# Enable Websocket API logs
# This can either be set to `websocket: true` to use defaults, or configured via subproperties.
websocket:
# Enables HTTP access logs (default: true)
accessLogging: true
# Log format to use for access logs
format: 'requestId: $context.requestId'
# Enable execution logging (default: true)
executionLogging: true
# Log level to use for execution logging: INFO or ERROR
level: INFO
# Log full requests/responses for execution logging (default: true)
fullExecutionData: true

# Optional, whether to write CloudWatch logs for custom resource lambdas as added by the framework
frameworkLambda: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
service: myservice
frameworkVersion: '2'
provider:
name: aws
logs:
# Enable HTTP API logs
# This can either be set to `httpApi: true` to use defaults, or configured via subproperties
# Can only be configured if the API is created by Serverless Framework
httpApi:
format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength" }'

# Enable REST API logs
# This can either be set to `restApi: true` to use defaults, or configured via subproperties
# Can only be configured if the API is created by Serverless Framework
restApi:
# Enables HTTP access logs (default: true)
accessLogging: false
# Log format to use for access logs
format: 'requestId: $context.requestId'
# Enable execution logging (default: true)
executionLogging: true
# Log level to use for execution logging: INFO or ERROR
level: INFO
# Log full requests/responses for execution logging (default: true)
fullExecutionData: true
# Existing IAM role to use for API Gateway when writing CloudWatch Logs (default: automatically created)
role: arn:aws:iam::123456:role
# Whether the API Gateway CloudWatch Logs role setting is not managed by Serverless (default: false)
roleManagedExternally: false

# Enable Websocket API logs
# This can either be set to `websocket: true` to use defaults, or configured via subproperties.
websocket:
# Enables HTTP access logs (default: true)
accessLogging: true
# Log format to use for access logs
format: 'requestId: $context.requestId'
# Enable execution logging (default: true)
executionLogging: true
# Log level to use for execution logging: INFO or ERROR
level: INFO
# Log full requests/responses for execution logging (default: true)
fullExecutionData: true

# Optional, whether to write CloudWatch logs for custom resource lambdas as added by the framework
frameworkLambda: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"queryName": "Serverless API Access Logging Setting Undefined",
"severity": "MEDIUM",
"line": 17,
"fileName": "positive1.yml"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": "4d424558-c6d1-453c-be98-9a7f877abd9a",
"queryName": "Serverless API Endpoint Config Not Private",
"severity": "MEDIUM",
"category": "Networking and Firewall",
"descriptionText": "Serverless should have endpointType set to 'PRIVATE'. This way, it's not exposed to the public internet",
"descriptionUrl": "https://www.serverless.com/framework/docs/providers/aws/events/apigateway#configuring-endpoint-types",
"platform": "ServerlessFW",
"descriptionID": "7837a4b9"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package Cx

import data.generic.common as common_lib
import data.generic.serverlessfw as sfw_lib

CxPolicy[result] {
document := input.document[i]
provider := document.provider

endpointType := provider.endpointType
endpointType != "PRIVATE"

result := {
"documentId": input.document[i].id,
"resourceType": sfw_lib.resourceTypeMapping("api", document.provider.name),
"resourceName": sfw_lib.get_service_name(document),
"searchKey": sprintf("provider.endpointType", []),
"issueType": "IncorrectValue",
"keyExpectedValue": "endpointType should be set to PRIVATE",
"keyActualValue": "endpointType is not set to PRIVATE",
"searchLine": common_lib.build_search_line(["provider", "endpointType"], []),
}
}

CxPolicy[result] {
document := input.document[i]
provider := document.provider

not common_lib.valid_key(provider, "endpointType")

result := {
"documentId": input.document[i].id,
"resourceType": sfw_lib.resourceTypeMapping("api", document.provider.name),
"resourceName": sfw_lib.get_service_name(document),
"searchKey": sprintf("provider", []),
"issueType": "MissingAttribute",
"keyExpectedValue": "endpointType should be defined and set to PRIVATE",
"keyActualValue": "endpointType is not defined",
"searchLine": common_lib.build_search_line(["provider"], []),
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
service: my-service
frameworkVersion: '2'
provider:
name: aws
endpointType: PRIVATE
vpcEndpointIds:
- vpce-123
- vpce-456
functions:
hello:
events:
- http:
path: user/create
method: get
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
service: my-service
frameworkVersion: '2'
provider:
name: aws
functions:
hello:
events:
- http:
path: user/create
method: get
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
service: my-service
frameworkVersion: '2'
provider:
name: aws
endpointType: REGIONAL
functions:
hello:
events:
- http:
path: user/create
method: get
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"queryName": "Serverless API Endpoint Config Not Private",
"severity": "MEDIUM",
"line": 3,
"fileName": "positive1.yml"
},
{
"queryName": "Serverless API Endpoint Config Not Private",
"severity": "MEDIUM",
"line": 5,
"fileName": "positive2.yml"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": "d5d1fe08-89db-440c-8725-b93223387309",
"queryName": "Serverless API Without Content Encoding",
"severity": "MEDIUM",
"category": "Encryption",
"descriptionText": "Serverless should have API Gateway with Content Encoding enabled through the attribute 'minimumCompressionSize'. This value should be greater than -1 and smaller than 10485760",
"descriptionUrl": "https://www.serverless.com/framework/docs/providers/aws/events/apigateway#compression",
"platform": "ServerlessFW",
"descriptionID": "2a9e728c"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package Cx

import data.generic.common as common_lib
import data.generic.serverlessfw as sfw_lib

CxPolicy[result] {
document := input.document[i]
provider := document.provider
apiGateway := provider.apiGateway

not common_lib.valid_key(apiGateway, "minimumCompressionSize")

result := {
"documentId": input.document[i].id,
"resourceType": sfw_lib.resourceTypeMapping("api", document.provider.name),
"resourceName": sfw_lib.get_service_name(document),
"searchKey": sprintf("provider.apiGateway", []),
"issueType": "MissingAttribute",
"keyExpectedValue": "apiGateway should have 'minimumCompressionSize' defined and set to a recommended value",
"keyActualValue": "apiGateway does not have 'minimumCompressionSize' defined",
"searchLine": common_lib.build_search_line(["provider", "apiGateway"], []),
}
}

CxPolicy[result] {
document := input.document[i]
provider := document.provider
apiGateway := provider.apiGateway

unrecommended_minimum_compression_size(apiGateway.minimumCompressionSize)

result := {
"documentId": input.document[i].id,
"resourceType": sfw_lib.resourceTypeMapping("api", document.provider.name),
"resourceName": sfw_lib.get_service_name(document),
"searchKey": sprintf("provider.apiGateway.minimumCompressionSize", []),
"issueType": "IncorrectValue",
"keyExpectedValue": "'minimumCompressionSize' should be set to a recommended value",
"keyActualValue": "'minimumCompressionSize' is set a unrecommended value",
"searchLine": common_lib.build_search_line(["provider", "apiGateway", "minimumCompressionSize"], []),
}
}

unrecommended_minimum_compression_size(value) {
value < 0
} else {
value > 10485759
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
service: my-service
frameworkVersion: '2'
provider:
name: aws
apiGateway:
minimumCompressionSize: 1024
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
service: my-service
frameworkVersion: '2'
provider:
name: aws
apiGateway:
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
service: my-service
frameworkVersion: '2'
provider:
name: aws
apiGateway:
minimumCompressionSize: 10485760

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"queryName": "Serverless API Without Content Encoding",
"severity": "MEDIUM",
"line": 5,
"fileName": "positive1.yml"
},
{
"queryName": "Serverless API Without Content Encoding",
"severity": "MEDIUM",
"line": 6,
"fileName": "positive2.yml"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": "434945e5-4dfd-41b1-aba1-47075ccd9265",
"queryName": "Serverless API X-Ray Tracing Disabled",
"severity": "MEDIUM",
"category": "Observability",
"descriptionText": "Serverless API Gateway should have X-Ray Tracing enabled",
"descriptionUrl": "https://www.serverless.com/framework/docs/providers/aws/events/apigateway#aws-x-ray-tracing",
"platform": "ServerlessFW",
"descriptionID": "4af7c06f"
}
Loading

0 comments on commit 067d476

Please sign in to comment.