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(bom): bill of materials for rds in aws cloudformation #5856

Merged
merged 7 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 11 additions & 0 deletions assets/queries/cloudFormation/aws_bom/rds/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"id": "6ef03ff6-a2bd-483c-851f-631f248bc0ea",
"queryName": "BOM - AWS RDS",
"severity": "TRACE",
"category": "Bill Of Materials",
"descriptionText": "A list of RDS resources found. Amazon Relational Database Service (Amazon RDS) is a collection of managed services that makes it simple to set up, operate, and scale databases in the cloud.",
"descriptionUrl": "https://kics.io",
"platform": "CloudFormation",
"descriptionID": "77215b57",
"cloudProvider": "aws"
}
150 changes: 150 additions & 0 deletions assets/queries/cloudFormation/aws_bom/rds/query.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package Cx

import data.generic.common as common_lib
import data.generic.cloudformation as cf_lib

CxPolicy[result] {
document := input.document
resource := document[i].Resources[name]
resource.Type == "AWS::RDS::DBInstance"

accessibility := get_resource_accessibility(resource)

bom_output = {
"resource_type": "AWS::RDS::DBInstance",
"resource_name": cf_lib.get_resource_name(resource, name),
"resource_engine": resource.Properties.Engine,
"resource_accessibility": accessibility,
"resource_encryption": get_db_instance_encryption(resource),
"resource_vendor": "AWS",
"resource_category": "Storage",
}

final_bom_output := common_lib.get_bom_output(bom_output, "")

result := {
"documentId": input.document[i].id,
"searchKey": sprintf("Resources.%s", [name]),
"issueType": "BillOfMaterials",
"keyExpectedValue": "",
"keyActualValue": "",
"searchLine": common_lib.build_search_line(["Resources", name], []),
"value": json.marshal(final_bom_output),
}
}

## get accessibility functions
get_resource_accessibility(resource) = accessibility{
resource.Properties.PubliclyAccessible == true
accessibility:= "public"
} else = accessibility{
resource.Properties.PubliclyAccessible == false
accessibility:= "private"
} else = accessibility{
not common_lib.valid_key(resource,"PubliclyAccessible")
subnet_gp_name := resource.Properties.DBSubnetGroupName
has_vpc_gateway_attached(subnet_gp_name)
accessibility:= "public"
} else = accessibility{
not common_lib.valid_key(resource.Properties,"PubliclyAccessible")
common_lib.valid_key(resource.Properties, "DBSubnetGroupName")
accessibility:= "private"
} else = accessibility{
accessibility:= "unknown"
}

has_vpc_gateway_attached(subnet_gp_name){
res_subnet_gp := input.document[_].Resources[subnet_gp_name]
res_subnet_gp.Type == "AWS::RDS::DBSubnetGroup"
subnet_name := res_subnet_gp.Properties.SubnetIds[_].Ref

res_subnet := input.document[_].Resources[subnet_name]
res_subnet.Type == "AWS::EC2::Subnet"
vpc_name := res_subnet.Properties.VpcId.Ref

res_vpc_gateway := input.document[_].Resources[_]
res_vpc_gateway.Type == "AWS::EC2::VPCGatewayAttachment"
res_vpc_gateway.Properties.VpcId == vpc_name
}

## get encryption functions
get_db_instance_encryption(resource) = encryption{
engine := lower(resource.Properties.Engine)
not contains(engine, "aurora")
encryption := get_enc_for_not_aurora(resource)
} else = encryption{
engine := lower(resource.Properties.Engine)
contains(engine, "aurora")
encryption := get_enc_for_aurora(resource)
}

# get encytion for instances with engines that are not aurora
get_enc_for_not_aurora(resource) = encryption{
resource.Properties.StorageEncrypted == true
encryption := "encrypted"
} else = encryption{
resource.Properties.StorageEncrypted == false
encryption := "unencrypted"
} else = encryption{
not common_lib.valid_key(resource.Properties, "StorageEncrypted")
dbInstanceIdentifier := cf_lib.get_name(resource.Properties.SourceDBInstanceIdentifier)

res_subnet_gp := input.document[_].Resources[dbInstanceIdentifier]
res_subnet_gp.Type == "AWS::RDS::DBInstance"

encryption := get_encryption(res_subnet_gp)
} else = encryption{
not common_lib.valid_key(resource.Properties, "StorageEncrypted")
dbInstanceIdentifier := cf_lib.get_name(resource.Properties.SnapshotIdentifier)

res_subnet_gp := input.document[_].Resources[dbInstanceIdentifier]
res_subnet_gp.Type == "AWS::RDS::DBInstance"

encryption := get_encryption(res_subnet_gp)
} else = encryption{
encryption := "unencrypted"
}

get_encryption(resource) = encryption{
resource.Properties.StorageEncrypted == true
encryption := "encrypted"
} else = encryption{
encryption := "unencrypted"
}

#get encytion for instances with aurora engines
get_enc_for_aurora(resource) = encryption{
cluster_name := resource.Properties.DBClusterIdentifier

cluster := input.document[_].Resources[cluster_name]
cluster.Type == "AWS::RDS::DBCluster"

encryption := get_cluster_enc(cluster)
}

# get encytion for for the cluster
get_cluster_enc(resource)= encryption{
resource.Properties.StorageEncrypted == true
encryption := "encrypted"
} else = encryption{
resource.Properties.StorageEncrypted == false
encryption := "unencrypted"
} else = encryption{
not common_lib.valid_key(resource.Properties, "SourceDBClusterIdentifier ")
dbClusterIdentifier := cf_lib.get_name(resource.Properties.SourceDBClusterIdentifier)

dbCluster := input.document[_].Resources[dbClusterIdentifier]
dbCluster.Type == "AWS::RDS::DBCluster"

encryption := get_encryption(dbCluster)
} else = encryption{
not common_lib.valid_key(resource.Properties, "StorageEncrypted")
dbClusterIdentifier := cf_lib.get_name(resource.Properties.SnapshotIdentifier)

dbCluster := input.document[_].Resources[dbClusterIdentifier]
dbCluster.Type == "AWS::RDS::DBCluster"

encryption := get_encryption(dbCluster)
} else = encryption{
encryption := "unencrypted"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
AWSTemplateFormatVersion: '2010-09-09'
Resources:
myDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
40 changes: 40 additions & 0 deletions assets/queries/cloudFormation/aws_bom/rds/test/positive1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"DBInstanceSample1":{
"Type": "AWS::RDS::DBInstance",
"Properties": {
"Engine": "oracle-ee",
"DBSubnetGroupName": "DBSubnetGroupSample1",
"StorageEncrypted": false
}
},
"VPCGatewayAttachmentSample1": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"InternetGatewayId": "",
"VpcId": "VPCSample1",
"VpnGatewayId": ""
}
},
"SubnetSample1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "172.16.1.0/24",
"VpcId": {
"Ref": "VPCSample1"
}
}
},
"DBSubnetGroupSample1": {
"Type": "AWS::RDS::DBSubnetGroup",
"Properties": {
"SubnetIds": [
{
"Ref": "SubnetSample1"
}
]
}
}
}
}
42 changes: 42 additions & 0 deletions assets/queries/cloudFormation/aws_bom/rds/test/positive2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"DBInstanceSample2":{
"Type": "AWS::RDS::DBInstance",
"Properties": {
"Engine": "oracle-ee",
"DBSubnetGroupName": "DBSubnetGroupSample2",
"SourceDBInstanceIdentifier": {
"Ref":"DBInstanceRefSample2"
}
}
},
"DBInstanceRefSample2":{
"Type": "AWS::RDS::DBInstance",
"Properties": {
"Engine": "oracle-ee",
"DBSubnetGroupName": "DBSubnetGroupSample2",
"StorageEncrypted": false
}
},
"SubnetSample2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "172.16.1.0/24",
"VpcId": {
"Ref": "VPCSample2"
}
}
},
"DBSubnetGroupSample2": {
"Type": "AWS::RDS::DBSubnetGroup",
"Properties": {
"SubnetIds": [
{
"Ref": "SubnetSample2"
}
]
}
}
}
}
42 changes: 42 additions & 0 deletions assets/queries/cloudFormation/aws_bom/rds/test/positive3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"DBInstanceSample3":{
"Type": "AWS::RDS::DBInstance",
"Properties": {
"Engine": "oracle-ee",
"DBSubnetGroupName": "DBSubnetGroupSample3",
"SnapshotIdentifier": {
"Ref":"DBInstanceRefSample3"
}
}
},
"DBInstanceRefSample3":{
"Type": "AWS::RDS::DBInstance",
"Properties": {
"Engine": "oracle-ee",
"DBSubnetGroupName": "DBSubnetGroupSample3",
"StorageEncrypted": true
}
},
"SubnetSample3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "172.16.1.0/24",
"VpcId": {
"Ref": "VPCSample3"
}
}
},
"DBSubnetGroupSample3": {
"Type": "AWS::RDS::DBSubnetGroup",
"Properties": {
"SubnetIds": [
{
"Ref": "SubnetSample3"
}
]
}
}
}
}
23 changes: 23 additions & 0 deletions assets/queries/cloudFormation/aws_bom/rds/test/positive4.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
AWSTemplateFormatVersion: '2010-09-09'
Resources:
DBInstanceSample4:
Type: AWS::RDS::DBInstance
Properties:
Engine: aurora
PubliclyAccessible: true
DBClusterIdentifier: DBClusterSample4
DBClusterSample4:
Type: 'AWS::RDS::DBCluster'
Properties:
MasterUsername: !Ref DBUsername
MasterUserPassword: !Ref DBPassword
DBClusterIdentifier: my-serverless-cluster
Engine: aurora
EngineVersion: 5.6.10a
EngineMode: serverless
StorageEncrypted: true
ScalingConfiguration:
AutoPause: true
MinCapacity: 4
MaxCapacity: 32
SecondsUntilAutoPause: 1000
38 changes: 38 additions & 0 deletions assets/queries/cloudFormation/aws_bom/rds/test/positive5.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
AWSTemplateFormatVersion: '2010-09-09'
Resources:
DBInstanceSample5:
Type: AWS::RDS::DBInstance
Properties:
Engine: aurora
PubliclyAccessible: true
DBClusterIdentifier: DBClusterSample5
DBClusterSample5:
Type: 'AWS::RDS::DBCluster'
Properties:
MasterUsername: !Ref DBUsername
MasterUserPassword: !Ref DBPassword
DBClusterIdentifier: my-serverless-cluster
Engine: aurora
EngineVersion: 5.6.10a
EngineMode: serverless
SourceDBClusterIdentifier: !Ref DBClusterSampleRef5
ScalingConfiguration:
AutoPause: true
MinCapacity: 4
MaxCapacity: 32
SecondsUntilAutoPause: 1000
DBClusterSampleRef5:
Type: 'AWS::RDS::DBCluster'
Properties:
MasterUsername: !Ref DBUsername
MasterUserPassword: !Ref DBPassword
DBClusterIdentifier: my-serverless-cluster
Engine: aurora
EngineVersion: 5.6.10a
EngineMode: serverless
StorageEncrypted: true
ScalingConfiguration:
AutoPause: true
MinCapacity: 4
MaxCapacity: 32
SecondsUntilAutoPause: 1000
38 changes: 38 additions & 0 deletions assets/queries/cloudFormation/aws_bom/rds/test/positive6.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
AWSTemplateFormatVersion: '2010-09-09'
Resources:
DBInstanceSample6:
Type: AWS::RDS::DBInstance
Properties:
Engine: aurora
PubliclyAccessible: true
DBClusterIdentifier: DBClusterSample6
DBClusterSample6:
Type: 'AWS::RDS::DBCluster'
Properties:
MasterUsername: !Ref DBUsername
MasterUserPassword: !Ref DBPassword
DBClusterIdentifier: my-serverless-cluster
Engine: aurora
EngineVersion: 5.6.10a
EngineMode: serverless
SnapshotIdentifier: !Ref DBClusterSampleRef6
ScalingConfiguration:
AutoPause: true
MinCapacity: 4
MaxCapacity: 32
SecondsUntilAutoPause: 1000
DBClusterSampleRef6:
Type: 'AWS::RDS::DBCluster'
Properties:
MasterUsername: !Ref DBUsername
MasterUserPassword: !Ref DBPassword
DBClusterIdentifier: my-serverless-cluster
Engine: aurora
EngineVersion: 5.6.10a
EngineMode: serverless
StorageEncrypted: true
ScalingConfiguration:
AutoPause: true
MinCapacity: 4
MaxCapacity: 32
SecondsUntilAutoPause: 1000
Loading