diff --git a/assets/queries/cloudFormation/aws_bom/rds/metadata.json b/assets/queries/cloudFormation/aws_bom/rds/metadata.json
new file mode 100644
index 00000000000..f2d507cdd6d
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/metadata.json
@@ -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"
+ }
diff --git a/assets/queries/cloudFormation/aws_bom/rds/query.rego b/assets/queries/cloudFormation/aws_bom/rds/query.rego
new file mode 100644
index 00000000000..b8c23231ae9
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/query.rego
@@ -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"
+}
diff --git a/assets/queries/cloudFormation/aws_bom/rds/test/negative1.yaml b/assets/queries/cloudFormation/aws_bom/rds/test/negative1.yaml
new file mode 100644
index 00000000000..5759552661c
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/test/negative1.yaml
@@ -0,0 +1,7 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Resources:
+ myDistribution:
+ Type: AWS::CloudFront::Distribution
+ Properties:
+ DistributionConfig:
+ Enabled: true
diff --git a/assets/queries/cloudFormation/aws_bom/rds/test/positive1.json b/assets/queries/cloudFormation/aws_bom/rds/test/positive1.json
new file mode 100644
index 00000000000..9767621aece
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/test/positive1.json
@@ -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"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/assets/queries/cloudFormation/aws_bom/rds/test/positive2.json b/assets/queries/cloudFormation/aws_bom/rds/test/positive2.json
new file mode 100644
index 00000000000..2a0bca5f09e
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/test/positive2.json
@@ -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"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/assets/queries/cloudFormation/aws_bom/rds/test/positive3.json b/assets/queries/cloudFormation/aws_bom/rds/test/positive3.json
new file mode 100644
index 00000000000..788083ca024
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/test/positive3.json
@@ -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"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/assets/queries/cloudFormation/aws_bom/rds/test/positive4.yaml b/assets/queries/cloudFormation/aws_bom/rds/test/positive4.yaml
new file mode 100644
index 00000000000..fac405ea661
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/test/positive4.yaml
@@ -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
diff --git a/assets/queries/cloudFormation/aws_bom/rds/test/positive5.yaml b/assets/queries/cloudFormation/aws_bom/rds/test/positive5.yaml
new file mode 100644
index 00000000000..420cbfabe71
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/test/positive5.yaml
@@ -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
diff --git a/assets/queries/cloudFormation/aws_bom/rds/test/positive6.yaml b/assets/queries/cloudFormation/aws_bom/rds/test/positive6.yaml
new file mode 100644
index 00000000000..70130566c48
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/test/positive6.yaml
@@ -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
diff --git a/assets/queries/cloudFormation/aws_bom/rds/test/positive_expected_result.json b/assets/queries/cloudFormation/aws_bom/rds/test/positive_expected_result.json
new file mode 100644
index 00000000000..e839529e01e
--- /dev/null
+++ b/assets/queries/cloudFormation/aws_bom/rds/test/positive_expected_result.json
@@ -0,0 +1,50 @@
+[
+ {
+ "queryName": "BOM - AWS RDS",
+ "severity": "TRACE",
+ "line": 4,
+ "fileName": "positive1.json"
+ },
+ {
+ "queryName": "BOM - AWS RDS",
+ "severity": "TRACE",
+ "line": 4,
+ "fileName": "positive2.json"
+ },
+ {
+ "queryName": "BOM - AWS RDS",
+ "severity": "TRACE",
+ "line": 14,
+ "fileName": "positive2.json"
+ },
+ {
+ "queryName": "BOM - AWS RDS",
+ "severity": "TRACE",
+ "line": 4,
+ "fileName": "positive3.json"
+ },
+ {
+ "queryName": "BOM - AWS RDS",
+ "severity": "TRACE",
+ "line": 14,
+ "fileName": "positive3.json"
+ },
+ {
+ "queryName": "BOM - AWS RDS",
+ "severity": "TRACE",
+ "line": 3,
+ "fileName": "positive4.yaml"
+ },
+ {
+ "queryName": "BOM - AWS RDS",
+ "severity": "TRACE",
+ "line": 3,
+ "fileName": "positive5.yaml"
+ },
+ {
+ "queryName": "BOM - AWS RDS",
+ "severity": "TRACE",
+ "line": 3,
+ "fileName": "positive6.yaml"
+ }
+]
diff --git a/docs/bom.md b/docs/bom.md
index 78a06d196d3..7fb7e20b211 100644
--- a/docs/bom.md
+++ b/docs/bom.md
@@ -139,13 +139,13 @@ Observe more detailed information about it in the table below.
| **Field** | **Possible Values** | **Required** | **Resources** | **Type** |
|:----------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:------------:|:------------------------------------------------------------------------:|:---------------:|
| acl | Private,
PublicRead,
PublicReadWrite,
AuthenticatedRead,
LogDeliveryWrite,
BucketOwnerRead,
BucketOwnerFullControl,
AwsExecRead | No | `AWS::S3::Bucket` | string |
-| policy | policy content (in case `resource_accessibility` equals hasPolicy) | No | `AWS::EFS::FileSystem`,
`AWS::S3::Bucket`,
`AWS::SNS::Topic`,
`AWS::SQS::Queue` | JSON marshalled |
-| resource_accessibility | public, private, hasPolicy or unknown for `AWS::EC2::Volume`, `AWS::EFS::FileSystem`, `AWS::AmazonMQ::Broker`, `AWS::MSK::Cluster`, `AWS::S3::Bucket`, `AWS::SNS::Topic`, and `AWS::SQS::Queue`
at least one security group associated with the elasticache is unrestricted, all security groups associated with the elasticache are restricted or unknown for `AWS::ElastiCache::CacheCluster` | Yes | all | string |
-| resource_category | In Memory Data Structure for `AWS::ElastiCache::CacheCluster`
Messaging for `AWS::SNS::Topic`
Queues for `AWS::AmazonMQ::Broker` and `AWS::SQS::Queue`
Storage for `AWS::EC2::Volume`, `AWS::EFS::FileSystem`, and `AWS::S3::Bucket`
Streaming for `AWS::MSK::Cluster` | Yes | all | string |
+| policy | policy content (in case `resource_accessibility` equals hasPolicy) | No | `AWS::EFS::FileSystem`,
`AWS::S3::Bucket`,
`AWS::SNS::Topic`,
`AWS::SQS::Queue`,
`AWS::RDS::DBInstance` | JSON marshalled |
+| resource_accessibility | public, private, hasPolicy or unknown for `AWS::EC2::Volume`, `AWS::EFS::FileSystem`, `AWS::AmazonMQ::Broker`, `AWS::MSK::Cluster`, `AWS::S3::Bucket`, `AWS::SNS::Topic`, `AWS::SQS::Queue`, and `AWS::RDS::DBInstance`
at least one security group associated with the elasticache is unrestricted, all security groups associated with the elasticache are restricted or unknown for `AWS::ElastiCache::CacheCluster` | Yes | all | string |
+| resource_category | In Memory Data Structure for `AWS::ElastiCache::CacheCluster`
Messaging for `AWS::SNS::Topic`
Queues for `AWS::AmazonMQ::Broker` and `AWS::SQS::Queue`
Storage for `AWS::EC2::Volume`, `AWS::EFS::FileSystem`, `AWS::S3::Bucket`, and `AWS::RDS::DBInstance`
Streaming for `AWS::MSK::Cluster` | Yes | all | string |
| resource_encryption | encrypted,
unencrypted,
unknown | Yes | all | string |
-| resource_engine | memcached, redis or unknown for `AWS::ElastiCache::CacheCluster`
ACTIVEMQ or RABBITMQ for `AWS::AmazonMQ::Broker` | No | `AWS::ElastiCache::CacheCluster`,
`AWS::AmazonMQ::Broker` | string |
+| resource_engine | memcached, redis or unknown for `AWS::ElastiCache::CacheCluster`
ACTIVEMQ or RABBITMQ for `AWS::AmazonMQ::Broker`
aurora, aurora-mysql, aurora-postgresql, mariadb, mysql, oracle-ee, oracle-ee-cdb, oracle-se2, oracle-se2-cdb, postgres, sqlserver-ee, sqlserver-se, sqlserver-ex, sqlserver-web or unknown for `AWS::RDS::DBInstance` | No | `AWS::ElastiCache::CacheCluster`,
`AWS::AmazonMQ::Broker`,
`AWS::RDS::DBInstance` | string |
| resource_name | anything (if the name is defined),
unknown (if the name is not defined) | Yes | all | string |
-| resource_type | AWS::EC2::Volume for `AWS::EC2::Volume`,
AWS::EFS::FileSystem for `AWS::EFS::FileSystem`,
AWS::ElastiCache::CacheCluster for `AWS::ElastiCache::CacheCluster`,
AWS::AmazonMQ::Broker for `AWS::AmazonMQ::Broker`,
AWS::MSK::Cluster for `AWS::MSK::Cluster`,
AWS::S3::Bucket for `AWS::S3::Bucket`,
AWS::SNS::Topic for `AWS::SNS::Topic`, AWS::SQS::Queue for `AWS::SQS::Queue` | Yes | all | string |
+| resource_type | AWS::EC2::Volume for `AWS::EC2::Volume`,
AWS::EFS::FileSystem for `AWS::EFS::FileSystem`,
AWS::ElastiCache::CacheCluster for `AWS::ElastiCache::CacheCluster`,
AWS::AmazonMQ::Broker for `AWS::AmazonMQ::Broker`,
AWS::MSK::Cluster for `AWS::MSK::Cluster`,
AWS::S3::Bucket for `AWS::S3::Bucket`,
AWS::SNS::Topic for `AWS::SNS::Topic`,
AWS::SQS::Queue for `AWS::SQS::Queue`,
AWS::RDS::DBInstance for `AWS::RDS::DBInstance`| Yes | all | string |
| resource_vendor | AWS | Yes | all | string |