Last active
April 27, 2024 22:04
-
-
Save niski84/d4fd4dc2d0d320e464a97d57d5fc7501 to your computer and use it in GitHub Desktop.
find orphaned databases
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"encoding/json" | |
"fmt" | |
"net/url" | |
"os" | |
"strings" | |
"time" | |
"github.com/aws/aws-sdk-go-v2/aws" | |
"github.com/aws/aws-sdk-go-v2/config" | |
"github.com/aws/aws-sdk-go-v2/service/secretsmanager" | |
) | |
type ( | |
DBConnectionDetails struct { | |
Hostname string | |
DBName string | |
} | |
DatabaseInfo struct { | |
Hostname string | |
Databases map[string]bool | |
} | |
RDSDatabase struct { | |
Hostname string | |
Databases []string | |
} | |
) | |
func ParseDBConnectionString(connStr string) (DBConnectionDetails, error) { | |
dbURL, err := url.Parse(connStr) | |
if err != nil { | |
return DBConnectionDetails{}, fmt.Errorf("failed to parse connection string: %s, error: %v", connStr, err) | |
} | |
details := DBConnectionDetails{ | |
Hostname: dbURL.Hostname(), | |
} | |
pathSegments := strings.Split(dbURL.Path, "/") | |
if len(pathSegments) > 1 { | |
details.DBName = pathSegments[1] | |
} | |
return details, nil | |
} | |
func GetActiveSecretsDatabases() ([]DatabaseInfo, error) { | |
cfg, err := config.LoadDefaultConfig(context.Background()) | |
if err != nil { | |
return nil, fmt.Errorf("failed to load AWS config: %v", err) | |
} | |
svc := secretsmanager.NewFromConfig(cfg) | |
dbMap := make(map[string]*DatabaseInfo) | |
paginator := secretsmanager.NewListSecretsPaginator(svc, &secretsmanager.ListSecretsInput{}) | |
for paginator.HasMorePages() { | |
page, err := paginator.NextPage(context.Background()) | |
if err != nil { | |
return nil, fmt.Errorf("failed to paginate secrets: %v", err) | |
} | |
for _, secret := range page.SecretList { | |
// Skip secrets based on path suffix | |
if strings.HasSuffix(*secret.Name, "/cl") || strings.HasSuffix(*secret.Name, "/cp") || strings.HasSuffix(*secret.Name, "/Palos") { | |
fmt.Printf("Skipping secret %s\n", *secret.Name) | |
continue | |
} | |
time.Sleep(3 * time.Second) // 3-second pause for tracing | |
fmt.Printf("Processing secret: %s\n", *secret.Name) | |
result, err := svc.GetSecretValue(context.Background(), &secretsmanager.GetSecretValueInput{ | |
SecretId: aws.String(*secret.Name), | |
}) | |
if err != nil { | |
fmt.Printf("Error retrieving secret %s: %v\n", *secret.Name, err) | |
continue | |
} | |
var secretMap map[string]interface{} | |
if err := json.Unmarshal([]byte(*result.SecretString), &secretMap); err != nil { | |
fmt.Printf("Error unmarshaling secret %s: %v\n", *secret.Name, err) | |
continue | |
} | |
for key, value := range secretMap { | |
if strings.HasPrefix(key, "dbconnectionstring") && value != nil { | |
connStr, ok := value.(string) | |
if !ok { | |
fmt.Printf("Non-string DB connection string for key %s in secret %s\n", key, *secret.Name) | |
continue | |
} | |
dbDetails, err := ParseDBConnectionString(connStr) | |
if err != nil { | |
fmt.Printf("Error parsing DB connection string for key %s in secret %s: %v\n", key, *secret.Name, err) | |
continue | |
} | |
fmt.Printf("Parsed Hostname: %s, DBName: %s\n", dbDetails.Hostname, dbDetails.DBName) | |
if dbInfo, exists := dbMap[dbDetails.Hostname]; !exists { | |
dbMap[dbDetails.Hostname] = &DatabaseInfo{ | |
Hostname: dbDetails.Hostname, | |
Databases: map[string]bool{dbDetails.DBName: true}, | |
} | |
} else { | |
dbInfo.Databases[dbDetails.DBName] = true | |
} | |
} | |
} | |
} | |
} | |
var databases []DatabaseInfo | |
for _, dbInfo := range dbMap { | |
databases = append(databases, *dbInfo) | |
} | |
return databases, nil | |
} | |
func main() { | |
databases, err := GetActiveSecretsDatabases() | |
if err != nil { | |
fmt.Println("Error getting active databases:", err) | |
os.Exit(1) | |
} | |
fmt.Println("Active databases collected successfully:") | |
for _, dbInfo := range databases { | |
fmt.Printf("Hostname: %s, Databases: %v\n", dbInfo.Hostname, dbInfo.Databases) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment