Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(queires): add serverless framework queries #5679

Merged
merged 10 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = {
cxMiguelSilva marked this conversation as resolved.
Show resolved Hide resolved
"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