Skip to content
This repository has been archived by the owner on Jun 1, 2022. It is now read-only.

Commit

Permalink
Add RDS
Browse files Browse the repository at this point in the history
  • Loading branch information
liamg authored and owenrumney committed Oct 7, 2021
1 parent b9f1124 commit caa673d
Show file tree
Hide file tree
Showing 30 changed files with 781 additions and 99 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/aquasecurity/cfsec
go 1.16

require (
github.com/aquasecurity/defsec v0.0.17
github.com/aquasecurity/defsec v0.0.19
github.com/google/go-cmp v0.5.5 // indirect
github.com/liamg/clinch v1.5.6
github.com/liamg/jfather v0.0.2
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ github.com/aquasecurity/defsec v0.0.15 h1:WmUxI6ep6uHDeXxbVIqBZn/QKxhPO4YaBSmira
github.com/aquasecurity/defsec v0.0.15/go.mod h1:E53TX/xJkcgpJyF5GPSat3Z+cZiLyvSNBdJAyfdl3fc=
github.com/aquasecurity/defsec v0.0.16 h1:w1zHQfOZIcGiGtxxXyUU3o16AoSN2p2PjUlm7Lo+6DQ=
github.com/aquasecurity/defsec v0.0.16/go.mod h1:E53TX/xJkcgpJyF5GPSat3Z+cZiLyvSNBdJAyfdl3fc=
github.com/aquasecurity/defsec v0.0.17 h1:DJ1bbCsuaRXmTbyO/f5udG4XAd6xVmsne6zi3QjRtXU=
github.com/aquasecurity/defsec v0.0.17/go.mod h1:E53TX/xJkcgpJyF5GPSat3Z+cZiLyvSNBdJAyfdl3fc=
github.com/aquasecurity/defsec v0.0.18 h1:V1iSvJfnc6OObmxBSQnc/5RqDF+upXWI/1QkqW4rxzk=
github.com/aquasecurity/defsec v0.0.18/go.mod h1:E53TX/xJkcgpJyF5GPSat3Z+cZiLyvSNBdJAyfdl3fc=
github.com/aquasecurity/defsec v0.0.19 h1:Q4sEBTsoMlsDJW8JJXnQGYddszVPl0jGkxyoX8Y+nQk=
github.com/aquasecurity/defsec v0.0.19/go.mod h1:E53TX/xJkcgpJyF5GPSat3Z+cZiLyvSNBdJAyfdl3fc=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
Expand Down
2 changes: 2 additions & 0 deletions internal/app/cfsec/adapter/aws/adapt.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/aquasecurity/cfsec/internal/app/cfsec/adapter/aws/elasticache"
"github.com/aquasecurity/cfsec/internal/app/cfsec/adapter/aws/elasticsearch"
"github.com/aquasecurity/cfsec/internal/app/cfsec/adapter/aws/iam"
"github.com/aquasecurity/cfsec/internal/app/cfsec/adapter/aws/rds"
"github.com/aquasecurity/cfsec/internal/app/cfsec/adapter/aws/redshift"
"github.com/aquasecurity/cfsec/internal/app/cfsec/adapter/aws/s3"
"github.com/aquasecurity/cfsec/internal/app/cfsec/adapter/aws/sns"
Expand Down Expand Up @@ -52,6 +53,7 @@ func Adapt(cfFile parser.FileContext) aws.AWS {
EKS: eks.Adapt(cfFile),
ElastiCache: elasticache.Adapt(cfFile),
Elasticsearch: elasticsearch.Adapt(cfFile),
RDS: rds.Adapt(cfFile),
Redshift: redshift.Adapt(cfFile),
S3: s3.Adapt(cfFile),
SNS: sns.Adapt(cfFile),
Expand Down
154 changes: 154 additions & 0 deletions internal/app/cfsec/adapter/aws/rds/rds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package rds

import (
"github.com/aquasecurity/cfsec/internal/app/cfsec/parser"
"github.com/aquasecurity/defsec/provider/aws/rds"
"github.com/aquasecurity/defsec/types"
)

func Adapt(cfFile parser.FileContext) rds.RDS {
clusters, orphans := getClustersAndInstances(cfFile)
return rds.RDS{
Instances: orphans,
Clusters: clusters,
Classic: getClassic(cfFile),
}
}

func getClustersAndInstances(ctx parser.FileContext) (clusters []rds.Cluster,
orphans []rds.Instance) {

clusterMap := getClusters(ctx)

for _, instanceResource := range ctx.GetResourceByType("AWS::RDS::DBInstance") {

var instance rds.Instance
instance.Metadata = instanceResource.Metadata()

if backupProp := instanceResource.GetProperty("BackupRetentionPeriod"); backupProp.IsInt() {
instance.BackupRetentionPeriodDays = backupProp.AsIntValue()
} else {
instance.BackupRetentionPeriodDays = types.IntDefault(1, instanceResource.Metadata())
}

if replicaProp := instanceResource.GetProperty("SourceDBInstanceIdentifier"); replicaProp.IsString() {
instance.ReplicationSourceARN = replicaProp.AsStringValue()
} else {
instance.ReplicationSourceARN = types.StringDefault("", instanceResource.Metadata())
}

if piProp := instanceResource.GetProperty("EnablePerformanceInsights"); piProp.IsBool() {
instance.PerformanceInsights.Enabled = piProp.AsBoolValue()
} else {
instance.PerformanceInsights.Enabled = types.BoolDefault(false, instanceResource.Metadata())
}

if insightsKeyProp := instanceResource.GetProperty("PerformanceInsightsKMSKeyId"); insightsKeyProp.IsString() {
instance.PerformanceInsights.KMSKeyID = insightsKeyProp.AsStringValue()
} else {
instance.PerformanceInsights.KMSKeyID = types.StringDefault("", instanceResource.Metadata())
}

if publicProp := instanceResource.GetProperty("PubliclyAccessible"); publicProp.IsBool() {
instance.PublicAccess = publicProp.AsBoolValue()
} else {
instance.PublicAccess = types.BoolDefault(true, instanceResource.Metadata())
}

if encryptedProp := instanceResource.GetProperty("StorageEncrypted"); encryptedProp.IsBool() {
instance.Encryption.EncryptStorage = encryptedProp.AsBoolValue()
} else {
instance.Encryption.EncryptStorage = types.BoolDefault(false, instanceResource.Metadata())
}

if keyProp := instanceResource.GetProperty("KmsKeyId"); keyProp.IsString() {
instance.Encryption.KMSKeyID = keyProp.AsStringValue()
} else {
instance.Encryption.KMSKeyID = types.StringDefault("", instanceResource.Metadata())
}

if clusterID := instanceResource.GetProperty("DBClusterIdentifier"); clusterID.IsString() {
var found bool
for key, cluster := range clusterMap {
if key == clusterID.AsString() {
cluster.Instances = append(cluster.Instances, rds.ClusterInstance(instance))
clusterMap[key] = cluster
found = true
break
}
}
if found {
continue
}
}

orphans = append(orphans, instance)
}

for _, cluster := range clusterMap {
clusters = append(clusters, cluster)
}

return clusters, orphans
}

func getClusters(ctx parser.FileContext) (clusters map[string]rds.Cluster) {
clusters = make(map[string]rds.Cluster)
for _, clusterResource := range ctx.GetResourceByType("AWS::RDS::DBCluster") {
var cluster rds.Cluster
cluster.Metadata = clusterResource.Metadata()
if backupProp := clusterResource.GetProperty("BackupRetentionPeriod"); backupProp.IsInt() {
cluster.BackupRetentionPeriodDays = backupProp.AsIntValue()
} else {
cluster.BackupRetentionPeriodDays = types.IntDefault(1, clusterResource.Metadata())
}

if replicaProp := clusterResource.GetProperty("SourceDBInstanceIdentifier"); replicaProp.IsString() {
cluster.ReplicationSourceARN = replicaProp.AsStringValue()
} else {
cluster.ReplicationSourceARN = types.StringDefault("", clusterResource.Metadata())
}

if piProp := clusterResource.GetProperty("EnablePerformanceInsights"); piProp.IsBool() {
cluster.PerformanceInsights.Enabled = piProp.AsBoolValue()
} else {
cluster.PerformanceInsights.Enabled = types.BoolDefault(false, clusterResource.Metadata())
}

if insightsKeyProp := clusterResource.GetProperty("PerformanceInsightsKMSKeyId"); insightsKeyProp.IsString() {
cluster.PerformanceInsights.KMSKeyID = insightsKeyProp.AsStringValue()
} else {
cluster.PerformanceInsights.KMSKeyID = types.StringDefault("", clusterResource.Metadata())
}

if encryptedProp := clusterResource.GetProperty("StorageEncrypted"); encryptedProp.IsBool() {
cluster.Encryption.EncryptStorage = encryptedProp.AsBoolValue()
} else {
cluster.Encryption.EncryptStorage = types.BoolDefault(false, clusterResource.Metadata())
}

if keyProp := clusterResource.GetProperty("KmsKeyId"); keyProp.IsString() {
cluster.Encryption.KMSKeyID = keyProp.AsStringValue()
} else {
cluster.Encryption.KMSKeyID = types.StringDefault("", clusterResource.Metadata())
}

clusters[clusterResource.ID()] = cluster
}
return clusters
}

func getClassic(ctx parser.FileContext) rds.Classic {
return rds.Classic{
DBSecurityGroups: getClassicSecurityGroups(ctx),
}
}

func getClassicSecurityGroups(ctx parser.FileContext) (groups []rds.DBSecurityGroup) {
for _, dbsgResource := range ctx.GetResourceByType("AWS::RDS::DBSecurityGroup") {
var group rds.DBSecurityGroup
group.Metadata = dbsgResource.Metadata()
groups = append(groups, group)
}
return groups
}
1 change: 1 addition & 0 deletions internal/app/cfsec/adapter/aws/redshift/redshift.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func getClusters(ctx parser.FileContext) (clusters []redshift.Cluster) {
func getSecurityGroups(ctx parser.FileContext) (groups []redshift.SecurityGroup) {
for _, groupResource := range ctx.GetResourceByType("AWS::Redshift::ClusterSecurityGroup") {
var group redshift.SecurityGroup
group.Metadata = groupResource.Metadata()
if descProp := groupResource.GetProperty("Description"); descProp.IsString() {
group.Description = descProp.AsStringValue()
} else {
Expand Down
1 change: 1 addition & 0 deletions internal/app/cfsec/adapter/aws/sns/sns.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func Adapt(cfFile parser.FileContext) sns.SNS {
func getTopics(ctx parser.FileContext) (topics []sns.Topic) {
for _, topicResource := range ctx.GetResourceByType("AWS::SNS::Topic") {
var topic sns.Topic
topic.Metadata = topicResource.Metadata()
if kmsProp := topicResource.GetProperty("KmsMasterKeyId"); kmsProp.IsString() {
topic.Encryption.KMSKeyID = kmsProp.AsStringValue()
} else {
Expand Down
1 change: 1 addition & 0 deletions internal/app/cfsec/adapter/aws/sqs/sqs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func Adapt(cfFile parser.FileContext) sqs.SQS {
func getQueues(ctx parser.FileContext) (queues []sqs.Queue) {
for _, queueResource := range ctx.GetResourceByType("AWS::SQS::Queue") {
var queue sqs.Queue
queue.Metadata = queueResource.Metadata()
if kmsProp := queueResource.GetProperty("KmsMasterKeyId"); kmsProp.IsString() {
queue.Encryption.KMSKeyID = kmsProp.AsStringValue()
} else {
Expand Down
1 change: 1 addition & 0 deletions internal/app/cfsec/adapter/aws/ssm/ssm.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func Adapt(cfFile parser.FileContext) ssm.SSM {
func getSecrets(ctx parser.FileContext) (secrets []ssm.Secret) {
for _, secretResource := range ctx.GetResourceByType("AWS::SecretsManager::Secret") {
var secret ssm.Secret
secret.Metadata = secretResource.Metadata()
if prop := secretResource.GetProperty("KmsKeyId"); prop.IsString() {
secret.KMSKeyID = prop.AsStringValue()
} else {
Expand Down
22 changes: 0 additions & 22 deletions internal/app/cfsec/rules/aws/iam/iam.yaml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package rds

import (
"github.com/aquasecurity/cfsec/internal/app/cfsec/rule"
"github.com/aquasecurity/cfsec/internal/app/cfsec/scanner"
"github.com/aquasecurity/defsec/rules/aws/rds"
)

func init() {
scanner.RegisterCheckRule(rule.Rule{

BadExample: []string{
`---
AWSTemplateFormatVersion: 2010-09-09
Description: Bad example
Resources:
Queue:
Type: AWS::RDS::DBInstance
Properties:
EnablePerformanceInsights: false
`,
},

GoodExample: []string{
`---
AWSTemplateFormatVersion: 2010-09-09
Description: Good example
Resources:
Queue:
Type: AWS::RDS::DBInstance
Properties:
EnablePerformanceInsights: true
PerformanceInsightsKMSKeyId: "something"
`,
},
Base: rds.CheckEnablePerformanceInsights,
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package rds

import (
"testing"

"github.com/aquasecurity/cfsec/internal/app/cfsec/test"
)

func Test_RDS_EnablePI_FailureExamples(t *testing.T) {
expectedCode := "aws-rds-enable-performance-insights"
test.RunFailureExamplesTest(t, expectedCode)
}

func Test_RDS_EnablePI_SuccessExamples(t *testing.T) {
expectedCode := "aws-rds-enable-performance-insights"
test.RunPassingExamplesTest(t, expectedCode)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package rds

import (
"github.com/aquasecurity/cfsec/internal/app/cfsec/rule"
"github.com/aquasecurity/cfsec/internal/app/cfsec/scanner"
"github.com/aquasecurity/defsec/rules/aws/rds"
)

func init() {
scanner.RegisterCheckRule(rule.Rule{

BadExample: []string{
`---
AWSTemplateFormatVersion: 2010-09-09
Description: Bad example of rds sgr
Resources:
Cluster:
Type: AWS::RDS::DBCluster
Properties:
StorageEncrypted: false
`,
},

GoodExample: []string{
`---
AWSTemplateFormatVersion: 2010-09-09
Description: Good example of rds sgr
Resources:
Cluster:
Type: AWS::RDS::DBCluster
Properties:
StorageEncrypted: true
KmsKeyId: "something"
`,
},
Base: rds.CheckEncryptClusterStorageData,
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package rds

import (
"testing"

"github.com/aquasecurity/cfsec/internal/app/cfsec/test"
)

func Test_RDS_EncryptCluster_FailureExamples(t *testing.T) {
expectedCode := "aws-rds-encrypt-cluster-storage-data"
test.RunFailureExamplesTest(t, expectedCode)
}

func Test_RDS_EncryptCluster_SuccessExamples(t *testing.T) {
expectedCode := "aws-rds-encrypt-cluster-storage-data"
test.RunPassingExamplesTest(t, expectedCode)
}
Loading

0 comments on commit caa673d

Please sign in to comment.