Skip to content

Commit

Permalink
Switched RDS database command from instances to clusters, and since i…
Browse files Browse the repository at this point in the history
…t grabs Neptune and DocsDB clusters, we don't need to run those api calls. (they all return the same data). Also added back port info and added role info to the RDS clusters in -o wide mode
  • Loading branch information
sethsec-bf committed Feb 23, 2024
1 parent ca437d3 commit 59afbb3
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 25 deletions.
67 changes: 45 additions & 22 deletions aws/databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type Database struct {
Protocol string
Public string
Size string
Roles string
}

func (m *DatabasesModule) PrintDatabases(outputDirectory string, verbosity int) {
Expand Down Expand Up @@ -113,7 +114,8 @@ func (m *DatabasesModule) PrintDatabases(outputDirectory string, verbosity int)
"Size",
"UserName",
"Endpoint",
//"Port",
"Port",
"Roles",
//"Protocol",
//"Public",

Expand All @@ -140,6 +142,8 @@ func (m *DatabasesModule) PrintDatabases(outputDirectory string, verbosity int)
"Size",
"UserName",
"Endpoint",
"Port",
"Roles",
}
// Otherwise, use the default columns.
} else {
Expand All @@ -151,6 +155,7 @@ func (m *DatabasesModule) PrintDatabases(outputDirectory string, verbosity int)
"Size",
"UserName",
"Endpoint",
"Port",
}
}

Expand All @@ -167,7 +172,8 @@ func (m *DatabasesModule) PrintDatabases(outputDirectory string, verbosity int)
m.Databases[i].Size,
m.Databases[i].UserName,
m.Databases[i].Endpoint,
// strconv.Itoa(int(m.Databases[i].Port)),
strconv.Itoa(int(m.Databases[i].Port)),
m.Databases[i].Roles,
// m.Databases[i].Protocol,
// m.Databases[i].Public,
},
Expand Down Expand Up @@ -221,11 +227,11 @@ func (m *DatabasesModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
serviceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
m.executeRdsCheck(r, wg, semaphore, dataReceiver, serviceMap)
m.executeRdsCheck(r, wg, semaphore, dataReceiver, serviceMap) // Also returns Neptune and DocDB databases
m.executeRedshiftCheck(r, wg, semaphore, dataReceiver, serviceMap)
m.executeDynamoDbCheck(r, wg, semaphore, dataReceiver, serviceMap)
m.executeDocDbCheck(r, wg, semaphore, dataReceiver, serviceMap)
m.executeNeptuneCheck(r, wg, semaphore, dataReceiver, serviceMap)
//m.executeDocDbCheck(r, wg, semaphore, dataReceiver, serviceMap)
//m.executeNeptuneCheck(r, wg, semaphore, dataReceiver, serviceMap)
}

type check struct {
Expand Down Expand Up @@ -358,43 +364,56 @@ func (m *DatabasesModule) getRdsClustersPerRegion(r string, wg *sync.WaitGroup,
m.CommandCounter.Pending--
m.CommandCounter.Executing++

DBInstances, err := sdk.CachedRDSDescribeDBInstances(m.RDSClient, aws.ToString(m.Caller.Account), r)
DBClusters, err := sdk.CachedRDSDescribeDBClusters(m.RDSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
return
}

var public string
for _, instance := range DBInstances {
if instance.Endpoint == nil || isNeptune(instance.Engine) {
for _, cluster := range DBClusters {
var public string
var service string
var roles string
if cluster.Endpoint == nil {
continue
}

name := aws.ToString(instance.DBInstanceIdentifier)
port := instance.Endpoint.Port
endpoint := aws.ToString(instance.Endpoint.Address)
engine := aws.ToString(instance.Engine)
name := aws.ToString(cluster.DBClusterIdentifier)
port := cluster.Port
endpoint := aws.ToString(cluster.Endpoint)
engine := aws.ToString(cluster.Engine)

if aws.ToBool(instance.PubliclyAccessible) {
if aws.ToBool(cluster.PubliclyAccessible) {
public = "True"
} else {
public = "False"
}

if isNeptune(cluster.Engine) {
service = "Neptune"
} else if isDocDB(cluster.Engine) {
service = "DocsDB"
} else {
service = "RDS"
}

associatedRoles := cluster.AssociatedRoles
for _, role := range associatedRoles {
roles = roles + aws.ToString(role.RoleArn) + " "
}

dataReceiver <- Database{
AWSService: "RDS",
AWSService: service,
Region: r,
Name: name,
Engine: engine,
Endpoint: endpoint,
UserName: aws.ToString(instance.MasterUsername),
UserName: aws.ToString(cluster.MasterUsername),
Port: aws.ToInt32(port),
Protocol: aws.ToString(instance.Engine),
Protocol: aws.ToString(cluster.Engine),
Public: public,
Roles: roles,
}
}
}
Expand Down Expand Up @@ -432,19 +451,19 @@ func (m *DatabasesModule) getRedshiftDatabasesPerRegion(r string, wg *sync.WaitG
name := aws.ToString(cluster.DBName)
//id := workspace.Id
endpoint := aws.ToString(cluster.Endpoint.Address)
port := aws.ToInt32(cluster.Endpoint.Port)

if aws.ToBool(cluster.PubliclyAccessible) {
public = "True"
} else {
public = "False"
}
port := cluster.Endpoint.Port
dataReceiver <- Database{
AWSService: awsService,
Region: r,
Name: name,
Endpoint: endpoint,
Port: aws.ToInt32(port),
Port: port,
Protocol: protocol,
Public: public,
}
Expand Down Expand Up @@ -586,3 +605,7 @@ func (m *DatabasesModule) getNeptuneDatabasesPerRegion(r string, wg *sync.WaitGr
func isNeptune(engine *string) bool {
return *engine == "neptune"
}

func isDocDB(engine *string) bool {
return *engine == "docdb"
}
2 changes: 1 addition & 1 deletion aws/sdk/docdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type DocDBClientInterface interface {

func init() {
gob.Register([]docdbTypes.GlobalCluster{})
gob.Register([]docdbTypes.DBCluster{})
//gob.Register([]docdbTypes.DBCluster{})
//gob.Register([]docdbTypes.DBInstance{})

}
Expand Down
3 changes: 1 addition & 2 deletions aws/sdk/neptune.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package sdk

import (
"context"
"encoding/gob"
"fmt"

"github.com/BishopFox/cloudfox/internal"
Expand All @@ -17,7 +16,7 @@ type NeptuneClientInterface interface {
}

func init() {
gob.RegisterName("neptune.DBCluster", []neptuneTypes.DBCluster{})
//gob.RegisterName("neptune.DBCluster", []neptuneTypes.DBCluster{})
}

func CachedNeptuneDescribeDBClusters(client NeptuneClientInterface, accountID string, region string) ([]neptuneTypes.DBCluster, error) {
Expand Down
39 changes: 39 additions & 0 deletions aws/sdk/rds.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ import (

type RDSClientInterface interface {
DescribeDBInstances(context.Context, *rds.DescribeDBInstancesInput, ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error)
DescribeDBClusters(context.Context, *rds.DescribeDBClustersInput, ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error)
}

func init() {
gob.Register([]rdsTypes.DBInstance{})
gob.Register([]rdsTypes.DBCluster{})

}

func CachedRDSDescribeDBInstances(client RDSClientInterface, accountID string, region string) ([]rdsTypes.DBInstance, error) {
Expand Down Expand Up @@ -55,3 +58,39 @@ func CachedRDSDescribeDBInstances(client RDSClientInterface, accountID string, r
internal.Cache.Set(cacheKey, instances, cache.DefaultExpiration)
return instances, nil
}

func CachedRDSDescribeDBClusters(client RDSClientInterface, accountID string, region string) ([]rdsTypes.DBCluster, error) {
var PaginationControl *string
var clusters []rdsTypes.DBCluster
cacheKey := fmt.Sprintf("%s-rds-DescribeDBClusters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
return cached.([]rdsTypes.DBCluster), nil
}
for {
DescribeDBClusters, err := client.DescribeDBClusters(
context.TODO(),
&rds.DescribeDBClustersInput{
Marker: PaginationControl,
},
func(o *rds.Options) {
o.Region = region
},
)

if err != nil {
return clusters, err
}

clusters = append(clusters, DescribeDBClusters.DBClusters...)

//pagination
if DescribeDBClusters.Marker == nil {
break
}
PaginationControl = DescribeDBClusters.Marker
}

internal.Cache.Set(cacheKey, clusters, cache.DefaultExpiration)
return clusters, nil
}
50 changes: 50 additions & 0 deletions aws/sdk/rds_mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,53 @@ func (m *MockedRDSClient) DescribeDBInstances(ctx context.Context, input *rds.De
},
}, nil
}

func (m *MockedRDSClient) DescribeDBClusters(ctx context.Context, input *rds.DescribeDBClustersInput, options ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error) {
return &rds.DescribeDBClustersOutput{
DBClusters: []rdsTypes.DBCluster{
{
DBClusterIdentifier: aws.String("db1"),
Engine: aws.String("aurora-postgresql"),
EngineVersion: aws.String("13.3"),
Endpoint: aws.String("db1.cluster-123456789012.us-west-2.rds.amazonaws.com"),
ClusterCreateTime: aws.Time(time.Now()),
MasterUsername: aws.String("postgres"),
Port: aws.Int32(5432),
AssociatedRoles: nil,
},
{
DBClusterIdentifier: aws.String("db2"),
Engine: aws.String("aurora-postgresql"),
EngineVersion: aws.String("13.3"),
Endpoint: aws.String("db2.cluster-123456789012.us-west-2.rds.amazonaws.com"),
ClusterCreateTime: aws.Time(time.Now()),
MasterUsername: aws.String("postgres"),
Port: aws.Int32(5432),
AssociatedRoles: nil,
},
{
DBClusterIdentifier: aws.String("db3"),
Engine: aws.String("neptune"),
EngineVersion: aws.String("1.2.1.0"),
Endpoint: aws.String("db3.cluster-123456789012.us-west-2.neptune.amazonaws.com"),
MasterUsername: aws.String("neptune"),
Port: aws.Int32(8182),
AssociatedRoles: []rdsTypes.DBClusterRole{
{
RoleArn: aws.String("arn:aws:iam::123456789012:role/NeptuneRole"),
Status: aws.String("active"),
},
},
},
{
DBClusterIdentifier: aws.String("db4"),
Engine: aws.String("docsdb"),
EngineVersion: aws.String("4.0.0"),
Endpoint: aws.String("db4.cluster-123456789012.us-west-2.docdb.amazonaws.com"),
MasterUsername: aws.String("docsdb"),
Port: aws.Int32(27017),
AssociatedRoles: nil,
},
},
}, nil
}

0 comments on commit 59afbb3

Please sign in to comment.