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: adds strike for checking automated backups against a db instance #2

Merged
merged 3 commits into from
Oct 21, 2023
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
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ var (
AvailableStrikes = map[string][]raidengine.Strike{
"CCC-Taxonomy": {
Strikes.SQLFeatures,
Strikes.AutomatedBackups,
// Strikes.VerticalScaling,
// Strikes.Replication,
// Strikes.MultiRegion,
// Strikes.AutomatedBackup,
// Strikes.BackupRecovery,
// Strikes.Encryption,
// Strikes.RBAC,
Expand Down
21 changes: 15 additions & 6 deletions example-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@ loglevel: Debug
WriteDirectory: test_output
raids:
RDS:
config:
database: test
host: localhost
password: password
port: 3306
user: root
aws:
creds:
aws_access_key: access
aws_secret_key: supersecret
aws_session_key: ""
aws_region: us-east-1
config:
instance_identifier: unique-id-name
database: test
host: localhost
password: password
port: 3306
user: root
# google
# azure
tactics:
- CCC-Taxonomy
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ module github.com/krumIO/raid-rds
go 1.14

require (
github.com/aws/aws-sdk-go-v2 v1.21.2
github.com/aws/aws-sdk-go-v2/config v1.19.0
github.com/aws/aws-sdk-go-v2/credentials v1.13.43
github.com/aws/aws-sdk-go-v2/service/rds v1.57.0
github.com/hashicorp/go-hclog v1.2.0
github.com/privateerproj/privateer-sdk v0.0.6
github.com/spf13/cobra v1.4.0
Expand Down
31 changes: 31 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,32 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA=
github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM=
github.com/aws/aws-sdk-go-v2/config v1.19.0 h1:AdzDvwH6dWuVARCl3RTLGRc4Ogy+N7yLFxVxXe1ClQ0=
github.com/aws/aws-sdk-go-v2/config v1.19.0/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE=
github.com/aws/aws-sdk-go-v2/credentials v1.13.43 h1:LU8vo40zBlo3R7bAvBVy/ku4nxGEyZe9N8MqAeFTzF8=
github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 h1:PIktER+hwIG286DqXyvVENjgLTAwGgoeriLDD5C+YlQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 h1:nFBQlGtkbPzp/NjZLuFxRqmT91rLJkgvsEQs68h962Y=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 h1:JRVhO25+r3ar2mKGP7E0LDl8K9/G36gjlqca5iQbaqc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 h1:hze8YsjSh8Wl1rYa1CJpRmXP21BvOBuc76YhW0HsuQ4=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 h1:WWZA/I2K4ptBS1kg0kV1JbBtG/umed0vwHRrmcr9z7k=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37/go.mod h1:vBmDnwWXWxNPFRMmG2m/3MKOe+xEcMDo1tanpaWCcck=
github.com/aws/aws-sdk-go-v2/service/rds v1.57.0 h1:kUCf6QowN4v8Jz1LRCr9ar3vcrKJu5YtbAbdXUGvvF4=
github.com/aws/aws-sdk-go-v2/service/rds v1.57.0/go.mod h1:NNx09yR8B7z4I5xTt2rUq+5h2lmA9T9bbm7NME/74Ac=
github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 h1:JuPGc7IkOP4AaqcZSIcyqLpFSqBWK32rM9+a1g6u73k=
github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 h1:HFiiRkf1SdaAmV3/BHOFZ9DjFynPHj8G/UIO1lQS+fk=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3/go.mod h1:a7bHA82fyUXOm+ZSWKU6PIoBxrjSprdLoM8xPYvzYVg=
github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwFYTCZVhlsSSBvlbU=
github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ=
github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8=
github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
Expand Down Expand Up @@ -596,6 +622,10 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
Expand Down Expand Up @@ -1319,6 +1349,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
101 changes: 101 additions & 0 deletions strikes/AutomatedBackups.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package strikes

import (
"context"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/rds"
"github.com/privateerproj/privateer-sdk/raidengine"
"github.com/privateerproj/privateer-sdk/utils"
)

// Todo/Roadmap: Features to evaluate implementing
// AutomatedBackup.go - AWS CLI - check backup interval

// This creates a database table
func (a *Strikes) AutomatedBackups() (strikeName string, result raidengine.StrikeResult) {
strikeName = "AutomatedBackups"
result = raidengine.StrikeResult{
Passed: false,
Description: "Check for automated backups against the specified RDS instance",
DocsURL: "https://www.github.com/krumIO/raid-rds",
ControlID: "CCC-Taxonomy-1",
Movements: make(map[string]raidengine.MovementResult),
}

// Movement
cfg, err := getAWSConfig()
if err != nil {
result.Message = err.Error()
return
}

rdsInstanceMovement := checkRDSInstanceMovement(cfg)
result.Movements["CheckForDBInstance"] = rdsInstanceMovement
if !rdsInstanceMovement.Passed {
result.Message = rdsInstanceMovement.Message
return
}

autmatedBackupsMovement := checkRDSAutomatedBackupMovement(cfg)
result.Movements["CheckForDBInstanceAutomatedBackups"] = autmatedBackupsMovement
if !autmatedBackupsMovement.Passed {
result.Message = autmatedBackupsMovement.Message
return
}

result.Passed = true
result.Message = "Completed Successfully"
return
}

func checkRDSInstanceMovement(cfg aws.Config) (result raidengine.MovementResult) {
// check if the instance is available
result = raidengine.MovementResult{
Description: "Check if the instance is available/exists",
Function: utils.CallerPath(0),
}

rdsClient := rds.NewFromConfig(cfg)
identifier, _ := getDBInstanceIdentifier()

input := &rds.DescribeDBInstancesInput{
DBInstanceIdentifier: aws.String(identifier),
}

instances, err := rdsClient.DescribeDBInstances(context.TODO(), input)
if err != nil {
// Handle error
result.Message = err.Error()
result.Passed = false
return
}
result.Passed = len(instances.DBInstances) > 0
return
}

func checkRDSAutomatedBackupMovement(cfg aws.Config) (result raidengine.MovementResult) {

result = raidengine.MovementResult{
Description: "Check if the instance has automated backups enabled",
Function: utils.CallerPath(0),
}

rdsClient := rds.NewFromConfig(cfg)
identifier, _ := getDBInstanceIdentifier()

input := &rds.DescribeDBInstanceAutomatedBackupsInput{
DBInstanceIdentifier: aws.String(identifier),
}

backups, err := rdsClient.DescribeDBInstanceAutomatedBackups(context.TODO(), input)
if err != nil {
result.Message = err.Error()
result.Passed = false
return
}

// Loop through the instances and print information
result.Passed = len(backups.DBInstanceAutomatedBackups) > 0
return
}
32 changes: 32 additions & 0 deletions strikes/AutomatedBackups_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package strikes

import (
"encoding/json"
"fmt"
"testing"

"github.com/spf13/viper"
)

func TestAutomatedBackup(t *testing.T) {
viper.AddConfigPath("../")
viper.SetConfigName("config")
viper.SetConfigType("yaml")
err := viper.ReadInConfig()

if err != nil {
fmt.Println("Config file not found...")
return
}

strikes := Strikes{}
strikeName, result := strikes.AutomatedBackups()

fmt.Println(strikeName)
b, err := json.MarshalIndent(result, "", " ")
if err != nil {
fmt.Println(err)
}
fmt.Print(string(b))
fmt.Println()
}
20 changes: 1 addition & 19 deletions strikes/SQLFeatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ import (
// Monitoring.go - check for enabled, req API/CLI
// Alerting.go - check for enabled, req API/CLI

func (a *Strikes) SetLogger(loggerName string) {
a.Log = raidengine.GetLogger(loggerName, false)
}

// This creates a database table
func (a *Strikes) SQLFeatures() (strikeName string, result raidengine.StrikeResult) {
strikeName = "SQLFeatures"
Expand Down Expand Up @@ -61,26 +57,12 @@ func (a *Strikes) SQLFeatures() (strikeName string, result raidengine.StrikeResu
return
}

func connectToDb() (result raidengine.MovementResult) {
result = raidengine.MovementResult{
Description: "The database host must be available and accepting connections",
Function: utils.CallerPath(0),
}
_, err := getConfig()
if err != nil {
result.Message = err.Error()
return
}
result.Passed = true
return
}

func createTable() (result raidengine.MovementResult) {
result = raidengine.MovementResult{
Description: "A table can be created in the database",
Function: utils.CallerPath(0),
}
name, err := getConfig()
name, err := getDBConfig()
if err != nil {
result.Message = err.Error()
return
Expand Down
54 changes: 49 additions & 5 deletions strikes/common.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package strikes

import (
"context"
"errors"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
hclog "github.com/hashicorp/go-hclog"
"github.com/privateerproj/privateer-sdk/raidengine"
"github.com/privateerproj/privateer-sdk/utils"
"github.com/spf13/viper"
)

Expand All @@ -15,12 +21,50 @@ type Movement struct {
Strike string
}

func getConfig() (string, error) {
if viper.IsSet("raids.RDS.config") && viper.IsSet("raids.RDS.config.database") {
func (a *Strikes) SetLogger(loggerName string) {
a.Log = raidengine.GetLogger(loggerName, false)
}

// Todo: return full config
// return viper.GetString("raids.RDS.config.database.host"), nil
func getDBConfig() (string, error) {
if viper.IsSet("raids.RDS.aws.config.host") && viper.IsSet("raids.RDS.aws.config.database") {
return "database_host_placeholder", nil
}
return "", errors.New("Database URL must be set in the config file (raids.RDS.config.database.host)")
return "", errors.New("database url must be set in the config file")
}

func getDBInstanceIdentifier() (string, error) {
if viper.IsSet("raids.RDS.aws.config.instance_identifier") {
return viper.GetString("raids.RDS.aws.config.instance_identifier"), nil
}
return "", errors.New("database instance identifier must be set in the config file")
}

func getAWSConfig() (cfg aws.Config, err error) {
if viper.IsSet("raids.RDS.aws.creds") &&
viper.IsSet("raids.RDS.aws.creds.aws_access_key") &&
viper.IsSet("raids.RDS.aws.creds.aws_secret_key") {

access_key := viper.GetString("raids.RDS.aws.creds.aws_access_key")
secret_key := viper.GetString("raids.RDS.aws.creds.aws_secret_key")
session_key := viper.GetString("raids.RDS.aws.creds.aws_session_key")
region := viper.GetString("raids.RDS.aws.creds.aws_region")

creds := credentials.NewStaticCredentialsProvider(access_key, secret_key, session_key)
cfg, err = config.LoadDefaultConfig(context.TODO(), config.WithCredentialsProvider(creds), config.WithRegion(region))
}
return
}

func connectToDb() (result raidengine.MovementResult) {
result = raidengine.MovementResult{
Description: "The database host must be available and accepting connections",
Function: utils.CallerPath(0),
}
_, err := getDBConfig()
if err != nil {
result.Message = err.Error()
return
}
result.Passed = true
return
}
Loading