Compare commits

..
30 Commits
Author SHA1 Message Date
Bastien Faure 599ddc247d Merge main 2023-07-01 17:40:50 -07:00
Bastien Faure 9bedfcb4de Cosmetics 2023-06-28 00:56:52 -07:00
Bastien Faure afbcab6652 Clarified GCP resource selection options in the CLI 2023-06-28 00:50:18 -07:00
Bastien Faure 3ec90f51d2 Improve resource selection logic in GCP by prepopulating Projects and Folders in the client for later use 2023-06-28 00:48:57 -07:00
Bastien Faure 1343060c4b Finish the resource selection logic implementation 2023-06-26 22:01:16 -07:00
Bastien Faure bbc26e0a23 Implement basic support of inventory command 2023-06-26 00:24:33 -07:00
Bastien Faure 8518b7678d Improve buckets module logging 2023-06-26 00:24:11 -07:00
Bastien Faure 07cd08ccc2 Improve data visualization in GCP resource tree 2023-06-25 23:24:08 -07:00
Bastien Faure 4ffc02c285 Implement tree structure in internal package, improved GCP Hierarchy command logic 2023-06-25 23:02:58 -07:00
Bastien Faure f61dd2bfb1 Included orphaned projects in the hierarchy module, improve logging 2023-06-25 16:27:13 -07:00
Bastien Faure 5365206a49 Update README with correct number of available GCP commands 2023-06-25 13:54:26 -07:00
Bastien Faure fc390b763e Fix bug in GCP profile selection logic, remove unnecessary new lines in GCP modules' logging 2023-06-25 13:53:38 -07:00
Bastien Faure a2140f1ef1 Implement definitive logic for GCP Profile interation and module calling 2023-06-25 02:27:51 -07:00
Bastien Faure 48f92dd4f8 Remove GCP development/test command, updated README with usable/current commands 2023-06-25 00:48:48 -07:00
Bastien Faure 139e4d391f Remove GCP development/test command, updated README with usable/current commands 2023-06-25 00:48:05 -07:00
Bastien Faure 6251b76a12 Bypass GCP profile parsing logic for commands that don't require authentication 2023-06-25 00:40:59 -07:00
Bastien Faure 48c4928767 Implement default profile detection in GCP 2023-06-24 23:21:26 -07:00
Bastien Faure 7578d4299d Implemented a logger to be used by cloudfox providers, moved version to globals 2023-06-24 23:10:54 -07:00
Bastien Faure b08ca87e6b Continue profile management implementation for GCP 2023-06-24 21:15:56 -07:00
Bastien Faure 5f029319a6 Continue GCP implementation, including multiple profile selection on CLI 2023-06-24 20:34:13 -07:00
Bastien Faure 42a32bb8e3 Added hierarchy command, aiming to display a resource tree, started decomissioning whoami 2023-06-22 22:14:47 -07:00
Bastien Faure c397f858db Added an internal function to list 'usable' credentials 2023-06-22 17:29:14 -07:00
Bastien Faure 980e28bc9d Implemented access-tokens commands for GCP to enumerate local tokens in a detailed manner 2023-06-22 12:35:48 -07:00
David 9b752ce4e6 saving work 2023-06-22 10:31:05 -04:00
Bastien Faure c102ea8d17 Started working around local GCP credentials and added profiles and inventory command stubs 2023-06-22 00:07:48 -07:00
Bastien Faure ba04dade7a Mimick AWS structure for GCP CLI args and modules 2023-06-21 13:20:14 -07:00
Bastien Faure 61cb727a64 Remove GCP debug 2023-06-20 22:40:22 -07:00
Bastien Faure 25fb66d6a1 Moved GCP helpers to separate file 2023-06-20 22:39:35 -07:00
Bastien Faure 82adab9863 Updated README with GCP documentation 2023-06-20 13:25:28 -07:00
Bastien Faure 02026c7a78 Initial commit for GCP implementation 2023-06-20 13:17:40 -07:00
17 changed files with 1378 additions and 14 deletions

No files matched your search

+9 -9
View File
@@ -1,20 +1,20 @@
run:
go run main.go
/home/marauder/Downloads/go/bin/go run main.go
windows:
GOOS=windows GOARCH=386 go build
GOOS=windows GOARCH=386 /home/marauder/Downloads/go/bin/go build
sha1sum cloudfox.exe > sha1sum-win.txt
zip cloudfox-win.zip cloudfox.exe sha1sum-win.txt
rm cloudfox.exe sha1sum-win.txt
linux:
GOOS=linux GOARCH=386 go build
GOOS=linux GOARCH=386 /home/marauder/Downloads/go/bin/go build
sha1sum cloudfox > sha1sum-linux.txt
zip cloudfox-linux.zip cloudfox sha1sum-linux.txt
rm cloudfox sha1sum-linux.txt
macos:
GOOS=darwin GOARCH=amd64 go build
GOOS=darwin GOARCH=amd64 /home/marauder/Downloads/go/bin/go build
sha1sum cloudfox > sha1sum-mac.txt
zip cloudfox-mac.zip cloudfox sha1sum-mac.txt
rm cloudfox sha1sum-mac.txt
@@ -25,21 +25,21 @@ all: windows linux macos
release: clean
mkdir -p ./cloudfox
mkdir -p ./cloudfox
GOOS=windows GOARCH=amd64 go build -o ./cloudfox/cloudfox.exe .
GOOS=windows GOARCH=amd64 /home/marauder/Downloads/go/bin/go build -o ./cloudfox/cloudfox.exe .
zip ./cloudfox/cloudfox-windows-amd64.zip ./cloudfox/cloudfox.exe
rm -rf ./cloudfox/cloudfox.exe
GOOS=linux GOARCH=amd64 go build -o ./cloudfox/cloudfox .
GOOS=linux GOARCH=amd64 /home/marauder/Downloads/go/bin/go build -o ./cloudfox/cloudfox .
zip ./cloudfox/cloudfox-linux-amd64.zip ./cloudfox/cloudfox .
rm -rf ./cloudfox/cloudfox
GOOS=darwin GOARCH=amd64 go build -o ./cloudfox/cloudfox .
GOOS=darwin GOARCH=amd64 /home/marauder/Downloads/go/bin/go build -o ./cloudfox/cloudfox .
zip ./cloudfox/cloudfox-macos-amd64.zip ./cloudfox/cloudfox
rm -rf ./cloudfox/cloudfox
GOOS=darwin GOARCH=arm64 go build -o ./cloudfox/cloudfox .
GOOS=darwin GOARCH=arm64 /home/marauder/Downloads/go/bin/go build -o ./cloudfox/cloudfox .
zip ./cloudfox/cloudfox-macos-arm64.zip ./cloudfox/cloudfox
rm -rf ./cloudfox/cloudfox
clean:
rm -rf ./cloudfox
rm -rf ./cloudfox
+15 -2
View File
@@ -41,7 +41,7 @@ For the full documentation please refer to our [wiki](https://github.com/BishopF
| - | - |
| AWS | 30 |
| Azure | 4 |
| GCP | Support Planned |
| GCP | 4 |
| Kubernetes | Support Planned |
@@ -79,7 +79,12 @@ Additional policy notes (as of 09/2022):
| `arn:aws:iam::aws:policy/AdministratorAccess` | This will work just fine with CloudFox, but if you were handed this level of access as a penetration tester, that should probably be a finding in itself :) |
### Azure
* Viewer or similar permissions applied.
* Viewer or similar permissions applied.
### GCP
* `gcloud` CLI installed
* Proper SDK credentials available (`gcloud auth application-default login`)
* Viewer or similar permissions applied.
# AWS Commands
| Provider | Command Name | Description
@@ -122,6 +127,14 @@ Additional policy notes (as of 09/2022):
| Azure | [rbac](https://github.com/BishopFox/cloudfox/wiki/Azure-Commands#rbac) | Lists Azure RBAC role assignments at subscription or tenant level |
| Azure | [storage](https://github.com/BishopFox/cloudfox/wiki/Azure-Commands#storage) | The storage command is still under development. Currently it only displays limited data about the storage accounts |
# GCP Commands
| Provider | Command Name | Description
| - | - | - |
| GCP | [access-tokens](https://github.com/BishopFox/cloudfox/wiki/GCP-Commands#access-tokens) | Displays handy information about existing GCP credentials on your local machine |
| GCP | [hierarchy](https://github.com/BishopFox/cloudfox/wiki/GCP-Commands#hierarchy) Displays information on the projects available to your current Gcloud SDK credentials. This is useful to provide situation awareness on what organizations, folders and projects to use with the other sub commands.|
| GCP | [inventory](https://github.com/BishopFox/cloudfox/wiki/GCP-Commands#inventory) Gain a rough understanding of size of the available organizations |
| GCP | [buckets](https://github.com/BishopFox/cloudfox/wiki/GCP-Commands#buckets) Lists the buckets in the available organizations and gives you handy commands for inspecting them further. |
# Authors
* [Carlos Vendramini](https://github.com/carlosvendramini-bf)
* [Seth Art (@sethsec](https://twitter.com/sethsec))
+232
View File
@@ -0,0 +1,232 @@
package cli
import (
"log"
"fmt"
"os"
"github.com/BishopFox/cloudfox/gcp"
internal_gcp "github.com/BishopFox/cloudfox/internal/gcp"
"github.com/BishopFox/cloudfox/internal"
"github.com/BishopFox/cloudfox/globals"
"github.com/spf13/cobra"
)
var (
// GCP resources filtering options
GCPOrganizations []string
GCPProjectIDs []string
GCPFolderIDs []string
// Output formatting options
GCPOutputFormat string
GCPOutputDirectory string
GCPVerbosity int
GCPWrapTable bool
GCPProfilesList string
GCPAllProfiles bool
GCPProfiles []string
// misc options
GCPConfirm bool
GCPSkipAdminCheck bool
GCPIgnoreCache bool
// command specific options
GCPTreeFormat string
// logger
GCPLogger = internal.NewLogger()
GCPCommands = &cobra.Command{
Use: "gcp",
Aliases: []string{"gcloud"},
Long: `See "Available Commands" for GCP Modules below`,
Short: "See \"Available Commands\" for GCP Modules below",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
GCPInventoryCommand = &cobra.Command{
Use: "inventory",
Aliases: []string{},
Short: "Display all available GCP resources",
Long: `
Display available GCP resources:
./cloudfox gcp inventory`,
Run: runGCPInventoryCommand,
}
GCPAccessTokensCommand = &cobra.Command{
Use: "access-tokens",
Aliases: []string{},
Short: "Display all available local gcloud access tokens",
Long: `
Display available gcloud access tokens:
./cloudfox gcp access-tokens`,
Run: runGCPAccessTokensCommand,
}
GCPBucketsCommand = &cobra.Command{
Use: "buckets",
Aliases: []string{},
Short: "Display GCP bucket information",
Args: cobra.MinimumNArgs(0),
Long: `
Display available bucket information:
./cloudfox gcp buckets [project [project...]]`,
Run: runGCPBucketsCommand,
}
HierarchyIncludeIDs bool
GCPHierarchyCommand = &cobra.Command{
Use: "hierarchy",
Aliases: []string{},
Short: "Display GCP resources hierarchy",
Long: `
Display available resources' hierarchy:
./cloudfox gcp hierarchy`,
Run: runGCPHierarchyCommand,
}
)
func initGCPProfiles() {
// bypass profile selection logic for commands that don't require authentication
if GCPAccessTokensCommand.CalledAs() != "" {
return
} else if GCPAccessTokensCommand.CalledAs() != "" {
return
}
// Ensure that profile selection is consistent
if (len(GCPProfiles) != 0 || GCPProfilesList != "") && GCPAllProfiles {
GCPLogger.Fatal("Error specifying GCP profiles. Choose only one of -p/--profile, -a/--all-profiles, -l/--profiles-list")
}
// at this point, GCPProfiles only contains the profiles submitted over the CLI
// if the --all-profiles option is submitted, replacing the profiles with all existing ones
if GCPAllProfiles {
GCPProfiles = internal_gcp.GetAllGCPProfiles()
}
// if --profiles-list option is submitted, adding the profiles from the list to the existing ones
if GCPProfilesList != "" {
GCPProfiles = append(GCPProfiles, internal_gcp.GetSelectedGCPProfiles(GCPProfilesList)...)
}
// remove duplicate
GCPProfiles = internal.RemoveDuplicateStr(GCPProfiles)
if (len(GCPProfiles) == 0) {
GCPLogger.Info("No GCP profile selection submitted, trying to find the default profile...")
var allProfiles = internal_gcp.GetAllGCPProfiles()
if len(allProfiles) > 0 {
GCPProfiles = append(GCPProfiles, allProfiles[len(allProfiles) - 1])
} else {
GCPLogger.Fatal("Could not find any usable GCP profile")
}
}
if !GCPConfirm {
result := internal_gcp.ConfirmSelectedProfiles(GCPProfiles)
if !result {
os.Exit(1)
}
}
}
func runGCPHierarchyCommand(cmd *cobra.Command, args []string) {
for _, profile := range GCPProfiles {
var client = internal_gcp.NewGCPClient(profile)
m := gcp.HierarchyModule{
Organizations: GCPOrganizations,
Projects: GCPProjectIDs,
Folders: GCPFolderIDs,
Client: *client,
}
err := m.DisplayHierarchy(GCPTreeFormat)
if err != nil {
GCPLogger.ErrorM(fmt.Sprintf("Error running %s module on profile %s", globals.GCP_HIERARCHY_MODULE_NAME, profile), globals.GCP_HIERARCHY_MODULE_NAME)
}
}
}
func runGCPBucketsCommand(cmd *cobra.Command, args []string) {
for _, profile := range GCPProfiles {
var client = internal_gcp.NewGCPClient(profile)
m := gcp.BucketsModule{
Organizations: GCPOrganizations,
Projects: GCPProjectIDs,
Folders: GCPFolderIDs,
Client: *client,
}
err := m.ListBuckets(args)
if err != nil {
GCPLogger.ErrorM(fmt.Sprintf("Error running %s module on profile %s", globals.GCP_BUCKETS_MODULE_NAME, profile), globals.GCP_BUCKETS_MODULE_NAME)
}
}
}
func runGCPAccessTokensCommand(cmd *cobra.Command, args []string) {
m := gcp.AccessTokensModule{
Organizations: GCPOrganizations,
Projects: GCPProjectIDs,
Folders: GCPFolderIDs,
}
err := m.PrintAccessTokens(GCPOutputFormat, GCPOutputDirectory, Verbosity)
if err != nil {
log.Fatal(err)
}
}
func runGCPInventoryCommand(cmd *cobra.Command, args []string) {
for _, profile := range GCPProfiles {
var client = internal_gcp.NewGCPClient(profile)
m := gcp.InventoryModule{
Organizations: GCPOrganizations,
Projects: GCPProjectIDs,
Folders: GCPFolderIDs,
Client: *client,
}
err := m.PrintInventory(GCPOutputFormat, GCPOutputDirectory, Verbosity)
if err != nil {
GCPLogger.ErrorM(fmt.Sprintf("Error running %s module on profile %s: %v", globals.GCP_INVENTORY_MODULE_NAME, profile, err), globals.GCP_INVENTORY_MODULE_NAME)
}
}
}
func init() {
cobra.OnInitialize(initGCPProfiles)
// Globals flags for the GCP modules
GCPCommands.PersistentFlags().StringArrayVar(&GCPProfiles, "profile", []string{}, "GCloud CLI Profile Name")
GCPCommands.PersistentFlags().StringVarP(&GCPProfilesList, "profiles-list", "l", "", "File containing a list of GCP CLI profile names separated by newlines")
GCPCommands.PersistentFlags().BoolVarP(&GCPAllProfiles, "all-profiles", "a", false, "Use all available and valid GCP CLI profiles")
// Resource filtering options
GCPCommands.PersistentFlags().StringArrayVarP(&GCPOrganizations, "organization", "o", []string{}, "Organization name or number, repetable")
GCPCommands.PersistentFlags().StringArrayVarP(&GCPProjectIDs, "projectid", "p", []string{}, "Project slug or number, repeatable")
GCPCommands.PersistentFlags().StringArrayVarP(&GCPFolderIDs, "folderid", "f", []string{}, "Folder name or number, repeatable")
// Global flags for the GCP modules
GCPCommands.PersistentFlags().BoolVarP(&GCPConfirm, "yes", "y", false, "Non-interactive mode (like apt/yum)")
GCPCommands.PersistentFlags().StringVarP(&GCPOutputFormat, "output", "", "brief", "[\"brief\" | \"wide\" ]")
GCPCommands.PersistentFlags().IntVarP(&Verbosity, "verbosity", "v", 1, "1 = Print control messages only\n2 = Print control messages, module output\n3 = Print control messages, module output, and loot file output\n")
GCPCommands.PersistentFlags().StringVar(&GCPOutputDirectory, "outdir", defaultOutputDir, "Output Directory ")
GCPCommands.PersistentFlags().IntVarP(&Goroutines, "max-goroutines", "g", 30, "Maximum number of concurrent goroutines")
GCPCommands.PersistentFlags().BoolVar(&GCPSkipAdminCheck, "skip-admin-check", false, "Skip check to determine if role is an Admin")
GCPCommands.PersistentFlags().BoolVarP(&GCPWrapTable, "wrap", "w", false, "Wrap table to fit in terminal (complicates grepping)")
GCPCommands.PersistentFlags().BoolVar(&GCPIgnoreCache, "ignore-cache", false, "Disable loading of cached data. Slower, but important if changes have been recently made")
GCPHierarchyCommand.Flags().BoolVarP(&HierarchyIncludeIDs, "ids", "i", false, "Use this flag to display resources IDs in the hierarchy tree")
GCPHierarchyCommand.Flags().StringVar(&GCPTreeFormat, "tree", "horizontal", "[\"horizontal\" | \"vertical\" ]")
GCPCommands.AddCommand(
GCPAccessTokensCommand,
GCPHierarchyCommand,
GCPInventoryCommand,
GCPBucketsCommand,
)
}
+92
View File
@@ -0,0 +1,92 @@
package gcp
import (
"fmt"
"strings"
"time"
"github.com/fatih/color"
"github.com/BishopFox/cloudfox/internal/gcp"
"github.com/BishopFox/cloudfox/internal"
"github.com/BishopFox/cloudfox/globals"
)
type AccessTokensModule struct {
// Filtering data
Organizations []string
Folders []string
Projects []string
}
func (m *AccessTokensModule) PrintAccessTokens(outputFormat string, outputDirectory string, verbosity int) error {
GCPLogger.InfoM(fmt.Sprintf("Enumerating GCP local access tokens (%s, %s)...", color.CyanString("default user token"), color.RedString("application-default token")), globals.GCP_ACCESSTOKENS_MODULE_NAME)
tokens := gcp.ReadRefreshTokens()
accessTokens := gcp.ReadAccessTokens()
applicationdefaulthash := gcp.GetDefaultApplicationHash()
activeAccount := gcp.GetActiveAccount()
var tableHead = []string{"Account", "Credential Type", "Validity", "Refresh Token", "Refresh Token needs password"}
var tableBody [][]string
for _, accessToken := range accessTokens {
// prepare token's associated ID (email or hash)
var emailinfo string
if (accessToken.AccountID == activeAccount) {
emailinfo = color.BlueString(accessToken.AccountID)
} else {
emailinfo = accessToken.AccountID
}
// format expiration time
Exp, _ := time.Parse(time.RFC3339, accessToken.TokenExpiry)
var timeinfo string
if Exp.After(time.Now()) {
timeinfo = Exp.Format(time.RFC1123)
} else {
timeinfo = "EXPIRED"
}
// display token type, user or application credential
var tokentype string
if (strings.Contains(accessToken.AccountID, "@")) {
tokentype = "User"
} else {
tokentype = "Application"
}
// is there an associated refres htoken ?
var refreshtokeninfo string
refreshtokeninfo = "No"
for _, refreshtoken := range tokens {
if (accessToken.AccountID == refreshtoken.Email) {
refreshtokeninfo = "Yes"
} else if (accessToken.AccountID == applicationdefaulthash) {
refreshtokeninfo = "Yes"
emailinfo = color.RedString(emailinfo)
}
}
// is there a proof of reauthentication to use the refresh
// token ? If not, password is needed
var raptinfo string
if refreshtokeninfo == "No" {
raptinfo = "-"
} else if accessToken.RaptToken.Valid {
raptinfo = "No"
} else {
if (tokentype == "Application") {
raptinfo = "TBD"
} else {
raptinfo = "Yes"
}
}
tableBody = append(
tableBody,
[]string{
emailinfo,
tokentype,
timeinfo,
refreshtokeninfo,
raptinfo,
})
}
internal.PrintTableToScreen(tableHead, tableBody, false)
return nil
}
+134
View File
@@ -0,0 +1,134 @@
package gcp
import (
"context"
"log"
"fmt"
"sort"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal/gcp"
"github.com/BishopFox/cloudfox/internal"
"google.golang.org/api/option"
"cloud.google.com/go/storage"
"google.golang.org/api/iterator"
)
var (
GCPLogger = internal.NewLogger()
)
type BucketsModule struct {
Client gcp.GCPClient
StorageClient *storage.Client
// Filtering data
Organizations []string
Folders []string
Projects []string
}
type ObjectInfo struct {
ObjectName string `json:"objecttName"`
ObjectSizeBytes float64 `json:"objectSizeBytes"`
IsPublic bool `json:"isPublic"`
}
type BucketInfo struct {
BucketName string `json:"bucketName"`
BucketSizeMB float64 `json:"bucketSizeMB"`
Objects []ObjectInfo `json:"objectInfo"`
}
func (m *BucketsModule) ListBuckets(projects []string) error {
// retrieve all resource and do filtering
m.Client.GetResourcesRoots(m.Organizations, m.Folders, m.Projects)
GCPLogger.InfoM(fmt.Sprintf("Enumerating GCP buckets with account %s...", m.Client.Name), globals.GCP_BUCKETS_MODULE_NAME)
ctx := context.Background()
var err error
m.StorageClient, err = storage.NewClient(ctx, option.WithHTTPClient(m.Client.HTTPClient))
if err != nil {
GCPLogger.ErrorM("Could not create GCP storage client...", globals.GCP_BUCKETS_MODULE_NAME)
return err
}
if len(projects) > 0 {
for _, project := range projects {
m.ListBucketsInProject(project)
}
} else {
for _, project := range m.Client.Projects {
m.ListBucketsInProject(project)
}
}
return nil
}
func (m *BucketsModule) ListBucketsInProject(project string) error {
bucketInfos := make(map[string][]BucketInfo)
ctx := context.Background()
GCPLogger.InfoM(fmt.Sprintf("Iterating through project %s...", project), globals.GCP_BUCKETS_MODULE_NAME)
buckets := m.StorageClient.Buckets(ctx, project)
for {
bucketAttrs, err := buckets.Next()
if err == iterator.Done {
break
}
if err != nil {
GCPLogger.ErrorM(fmt.Sprintf("Failed to list buckets : %v", err), globals.GCP_BUCKETS_MODULE_NAME)
return err
}
bucketName := bucketAttrs.Name
GCPLogger.InfoM(fmt.Sprintf("Enumerating bucket %s...", bucketName), globals.GCP_BUCKETS_MODULE_NAME)
// List all objects in the bucket and calculate total size
totalSize := int64(0)
var objects []ObjectInfo
it := m.StorageClient.Bucket(bucketName).Objects(ctx, nil)
for {
objectAttrs, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Failed to list objects: %v", err)
GCPLogger.ErrorM(fmt.Sprintf("Failed to list objects : %v", err), globals.GCP_BUCKETS_MODULE_NAME)
break
}
// Get size
objectSize := objectAttrs.Size
totalSize += objectSize
// Check if public
isPublic := false
for _, rule := range objectAttrs.ACL {
if rule.Entity == storage.AllUsers {
isPublic = true
break
}
}
objects = append(objects, ObjectInfo{ObjectName: objectAttrs.Name, ObjectSizeBytes: float64(objectSize), IsPublic: isPublic})
if totalSize > 3221225472 { // 3 GiB in bytes
GCPLogger.InfoM(fmt.Sprintf("%s bucket is over 3 GiB. Skipping remaining objects in this bucket...", bucketName), globals.GCP_BUCKETS_MODULE_NAME)
break
}
}
bucketSizeMB := float64(totalSize) / 1024 / 1024
bucketInfos[project] = append(bucketInfos[project], BucketInfo{BucketName: bucketName, BucketSizeMB: bucketSizeMB, Objects: objects})
}
log.Printf("Sorting resulting list of buckets in descending order %s", project)
sort.Slice(bucketInfos[project], func(i, j int) bool {
return bucketInfos[project][i].BucketSizeMB > bucketInfos[project][j].BucketSizeMB
})
log.Printf("Done with project %s", project)
return nil
}
+38
View File
@@ -0,0 +1,38 @@
package gcp
import (
"fmt"
"github.com/BishopFox/cloudfox/internal/gcp"
"github.com/BishopFox/cloudfox/globals"
// tree stuff
"github.com/shivamMg/ppds/tree"
)
type HierarchyModule struct {
Client gcp.GCPClient
// Filtering data
Organizations []string
Folders []string
Projects []string
}
func (m *HierarchyModule) DisplayHierarchy(format string) error {
GCPLogger.InfoM(fmt.Sprintf("Fetching GCP resources and hierarchy with account %s...", m.Client.Name), globals.GCP_HIERARCHY_MODULE_NAME)
var roots = m.Client.GetResourcesRoots(m.Organizations, m.Folders, m.Projects)
for _, root := range roots {
if (format == "horizontal") {
tree.PrintHr(root)
} else if (format == "vertical") {
tree.Print(root)
} else {
GCPLogger.ErrorM(fmt.Sprintf("Unknown tree format '%s'", format), globals.GCP_HIERARCHY_MODULE_NAME)
}
}
return nil
}
+30
View File
@@ -0,0 +1,30 @@
package gcp
import (
"fmt"
"github.com/BishopFox/cloudfox/internal/gcp"
"github.com/BishopFox/cloudfox/globals"
)
type InventoryModule struct {
Client gcp.GCPClient
// Filtering data
Organizations []string
Folders []string
Projects []string
}
func (m *InventoryModule) PrintInventory(outputFormat string, outputDirectory string, verbosity int) error {
GCPLogger.InfoM(fmt.Sprintf("Enumerating GCP resources with account %s...", m.Client.Name), globals.GCP_INVENTORY_MODULE_NAME)
for _, project := range m.Projects {
searchAllResponse, err := m.Client.ResourcesService.SearchAll(fmt.Sprintf("projects/%s", project)).Do()
if (err != nil) {
GCPLogger.ErrorM(fmt.Sprintf("Could not list resource within scope: %v", err), globals.GCP_INVENTORY_MODULE_NAME)
continue
}
for _, resource := range searchAllResponse.Results {
fmt.Printf("%s - %s\n", resource.DisplayName, resource.AssetType)
}
}
return nil
}
+12
View File
@@ -0,0 +1,12 @@
package globals
// Module names
const GCP_WHOAMI_MODULE_NAME = "whoami"
const GCP_HIERARCHY_MODULE_NAME = "hierarchy"
const GCP_INVENTORY_MODULE_NAME = "inventory"
const GCP_ACCESSTOKENS_MODULE_NAME = "access-tokens"
const GCP_BUCKETS_MODULE_NAME = "buckets"
const GCP_GCLOUD_REFRESH_TOKENS_DB_PATH = ".config/gcloud/credentials.db"
const GCP_GCLOUD_ACCESS_TOKENS_DB_PATH = ".config/gcloud/access_tokens.db"
const GCP_GCLOUD_DEFAULT_CONFIG_PATH = ".config/gcloud/configurations/config_default"
const GCP_GCLOUD_APPLICATION_DEFAULT_PATH = ".config/gcloud/application_default_credentials.json"
+1
View File
@@ -4,3 +4,4 @@ const CLOUDFOX_USER_AGENT = "cloudfox"
const CLOUDFOX_LOG_FILE_DIR_NAME = ".cloudfox"
const CLOUDFOX_BASE_DIRECTORY = ".cloudfox/cloudfox-output"
const LOOT_DIRECTORY_NAME = "loot"
const CLOUDFOX_VERSION = "1.11.2"
+44
View File
@@ -3,6 +3,8 @@ module github.com/BishopFox/cloudfox
go 1.20
require (
cloud.google.com/go/resourcemanager v1.7.0
cloud.google.com/go/storage v1.28.1
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1
@@ -56,10 +58,52 @@ require (
github.com/jedib0t/go-pretty v4.3.0+incompatible
github.com/kyokomi/emoji v2.2.4+incompatible
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/shivamMg/ppds v0.0.1
github.com/sirupsen/logrus v1.9.3
github.com/spf13/afero v1.9.5
github.com/spf13/cobra v1.7.0
golang.org/x/crypto v0.9.0
golang.org/x/oauth2 v0.8.0
google.golang.org/api v0.127.0
gopkg.in/ini.v1 v1.67.0
modernc.org/sqlite v1.23.1
)
require (
cloud.google.com/go v0.110.0 // indirect
cloud.google.com/go/compute v1.19.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v0.13.0 // indirect
cloud.google.com/go/longrunning v0.4.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect
github.com/googleapis/gax-go/v2 v2.10.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/tools v0.9.1 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/grpc v1.55.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.22.5 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)
require (
+116 -1
View File
@@ -17,24 +17,38 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys=
cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds=
cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k=
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM=
cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/resourcemanager v1.7.0 h1:NRM0p+RJkaQF9Ee9JMnUV9BQ2QBIOq/v8M+Pbv/wmCs=
cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI=
cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@@ -81,6 +95,7 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkM
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aquasecurity/table v1.8.0 h1:9ntpSwrUfjrM6/YviArlx/ZBGd6ix8W+MtojQcM7tv0=
github.com/aquasecurity/table v1.8.0/go.mod h1:eqOmvjjB7AhXFgFqpJUEE/ietg7RrMSJZXyTN8E/wZw=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
@@ -200,6 +215,7 @@ github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J
github.com/bishopfox/awsservicemap v1.0.2 h1:+NnuInVcQkja6y6h6eGseneU3m5Nzp9O++gR1s+FiyM=
github.com/bishopfox/awsservicemap v1.0.2/go.mod h1:oy9Fyqh6AozQjShSx+zRNouTlp7k3z3YEMoFkN8rquc=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -207,6 +223,10 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -217,14 +237,18 @@ github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dominikbraun/graph v0.22.2 h1:rFtrufgqXJy7daEMTxHIQWQc12Y1XHelXi2Heo1Bfho=
github.com/dominikbraun/graph v0.22.2/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -240,6 +264,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@@ -261,6 +287,10 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -272,12 +302,17 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@@ -288,13 +323,21 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.2.4 h1:uGy6JWR/uMIILU8wbf+OkstIrNiMjGpEIyhx8f6W7s4=
github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.10.0 h1:ebSgKfMxynOdxw8QQuFOKMgomqeLGPqNLQox2bo42zg=
github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -309,6 +352,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
@@ -327,6 +372,8 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -344,11 +391,17 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shivamMg/ppds v0.0.1 h1:idK2dpaen652zOO+OmcwmyoPNncBNqfHjF/14eS5JIk=
github.com/shivamMg/ppds v0.0.1/go.mod h1:hb39VqUO6qfkb9zBBQPTIV1vWBtI7yQsG0wr3pN78fM=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
@@ -367,6 +420,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
@@ -388,6 +442,9 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -396,6 +453,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
@@ -435,6 +493,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -463,6 +523,7 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@@ -480,6 +541,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -492,6 +555,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -549,6 +613,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
@@ -603,10 +668,14 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -626,12 +695,15 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.127.0 h1:v7rj0vA0imM3Ou81k1eyFxQNScLzn71EyGnJDr+V/XI=
google.golang.org/api v0.127.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -656,6 +728,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
@@ -669,6 +742,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao=
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -682,9 +761,14 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -695,11 +779,18 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -712,6 +803,30 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+12
View File
@@ -31,3 +31,15 @@ func Contains(element string, array []string) bool {
}
return false
}
func RemoveDuplicateStr(strSlice []string) []string {
allKeys := make(map[string]bool)
list := []string{}
for _, item := range strSlice {
if _, value := allKeys[item]; !value {
allKeys[item] = true
list = append(list, item)
}
}
return list
}
+238
View File
@@ -0,0 +1,238 @@
package gcp
import (
"log"
"database/sql"
"crypto/sha256"
"fmt"
"strings"
"time"
"encoding/json"
_ "modernc.org/sqlite"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
//"google.golang.org/api/option"
//goauth2 "google.golang.org/api/oauth2/v2"
//"google.golang.org/api/cloudresourcemanager/v1"
//"google.golang.org/api/cloudasset/v1p1beta1"
"os"
"io/ioutil"
"os/user"
"gopkg.in/ini.v1"
"path/filepath"
"github.com/BishopFox/cloudfox/globals"
//"github.com/aws/smithy-go/ptr"
)
type ApplicationCredential struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
RefreshToken string `json:"refresh_token"`
Type string `json:"authorized_user"`
Scopes []string `json:"scopes"`
}
type RefreshToken struct {
Email string
JSON string
}
// CREATE TABLE IF NOT EXISTS "access_tokens" (account_id TEXT PRIMARY KEY, access_token TEXT, token_expiry TIMESTAMP, rapt_token TEXT, id_token TEXT);
type Token struct {
AccountID string
AccessToken string
TokenExpiry string
RaptToken sql.NullString
IdentityToken string
}
type GCloudProfile struct {
Name string
oauth_conf oauth2.Config
initial_token oauth2.Token
}
func listAllProfiles() []GCloudProfile {
var (
profiles []GCloudProfile
access_tokens []Token
refresh_tokens []RefreshToken
exp time.Time
data ApplicationCredential
)
access_tokens = ReadAccessTokens()
refresh_tokens = ReadRefreshTokens()
for _, access_token := range access_tokens {
if (strings.Contains(access_token.AccountID, "@")) {
exp, _ = time.Parse(time.RFC3339, access_token.TokenExpiry)
for _, refresh_token := range refresh_tokens {
if (refresh_token.Email == access_token.AccountID) {
json.Unmarshal([]byte(refresh_token.JSON), &data)
profiles = append(
profiles,
GCloudProfile{
Name: access_token.AccountID,
oauth_conf: oauth2.Config{
ClientID: data.ClientID,
ClientSecret: data.ClientSecret,
Scopes: data.Scopes,
Endpoint: google.Endpoint,
},
initial_token: oauth2.Token{
AccessToken: access_token.AccessToken,
Expiry: exp,
},
},
)
}
}
}
}
return profiles
}
/* The active gcloud CLI profile is stored in INI configuration file */
func GetActiveAccount() string {
configPath := GetDefaultConfigPath()
cfg, err := ini.Load(configPath)
if err != nil {
fmt.Printf("Fail to read %s: %v", configPath, err)
os.Exit(1)
}
account := cfg.Section("core").Key("account").String()
return account
}
/* Access tokens are stored in the access_tokens.db database, along with the user ID
*/
func ReadAccessTokens() []Token{
db, err := sql.Open("sqlite", GetAccessTokensDBPath())
if err != nil {
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query("SELECT * from access_tokens;")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var tokens []Token
for rows.Next() {
var (
AccountID string
AccessToken string
TokenExpiry string
RaptToken sql.NullString
IdentityToken string
)
err = rows.Scan(&AccountID, &AccessToken, &TokenExpiry, &RaptToken, &IdentityToken)
if err != nil {
log.Fatal(err)
}
tokens = append(
tokens,
Token{
AccountID: AccountID,
AccessToken: AccessToken,
TokenExpiry: TokenExpiry,
RaptToken: RaptToken,
IdentityToken: IdentityToken,
})
}
return tokens
}
/* The application default access tokens are not stored the same way as the user ones
The access_tokens.db does not contain the associated user id, but the sha256 digest of the refresh token
stored in the application default json file
*/
func GetDefaultApplicationHash() string {
var (
err error
jsonFile string
)
jsonFile, err = GetApplicationDefaultPath()
if (err != nil) {
return "invalid"
}
var applicationcred ApplicationCredential
byteValue, _ := ioutil.ReadFile(jsonFile)
json.Unmarshal(byteValue, &applicationcred)
sum := sha256.Sum256([]byte(applicationcred.RefreshToken))
return fmt.Sprintf("%x", sum)
}
/* The refresh tokens are stored in a separate database called credentials.db
*/
func ReadRefreshTokens() []RefreshToken{
db, err := sql.Open("sqlite", GetRefreshTokensDBPath())
if err != nil {
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query("SELECT * from credentials;")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var tokens []RefreshToken
for rows.Next() {
var accountName string
var JSON string
err = rows.Scan(&accountName, &JSON)
if err != nil {
log.Fatal(err)
}
tokens = append(tokens, RefreshToken{Email: accountName, JSON: JSON})
}
return tokens
}
// This function returns the path to gcloud credentials
func GetRefreshTokensDBPath() string {
user, _ := user.Current()
credspath := filepath.Join(user.HomeDir, globals.GCP_GCLOUD_REFRESH_TOKENS_DB_PATH)
if _, err := os.Stat(credspath); os.IsNotExist(err) {
log.Fatalf("[-] Failed to read gcloud refresh tokens database")
}
return credspath
}
func GetAccessTokensDBPath() string {
user, _ := user.Current()
credspath := filepath.Join(user.HomeDir, globals.GCP_GCLOUD_ACCESS_TOKENS_DB_PATH)
if _, err := os.Stat(credspath); os.IsNotExist(err) {
log.Fatalf("[-] Failed to read gcloud access tokens database")
}
return credspath
}
func GetDefaultConfigPath() string {
user, _ := user.Current()
credspath := filepath.Join(user.HomeDir, globals.GCP_GCLOUD_DEFAULT_CONFIG_PATH)
if _, err := os.Stat(credspath); os.IsNotExist(err) {
log.Fatalf("[-] Failed to read gcloud default config")
}
return credspath
}
func GetApplicationDefaultPath() (string, error) {
user, _ := user.Current()
credspath := filepath.Join(user.HomeDir, globals.GCP_GCLOUD_APPLICATION_DEFAULT_PATH)
var err error
if _, err := os.Stat(credspath); os.IsNotExist(err) {
log.Printf("[-] Default application credentials not set")
}
return credspath, err
}
+321
View File
@@ -0,0 +1,321 @@
package gcp
import (
"context"
"log"
"net/http"
"os"
"fmt"
"bufio"
"strings"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/option"
goauth2 "google.golang.org/api/oauth2/v2"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/storage/v1"
"google.golang.org/api/cloudasset/v1p1beta1"
"github.com/BishopFox/cloudfox/internal"
"github.com/BishopFox/cloudfox/globals"
resourcemanager "cloud.google.com/go/resourcemanager/apiv3"
resourcemanagerpb "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb"
"google.golang.org/api/iterator"
)
var (
logger = internal.NewLogger()
)
type GCPClient struct {
Name string
HTTPClient *http.Client
Logger internal.Logger
TokenSource *oauth2.TokenSource
TokenInfo *goauth2.Tokeninfo
CloudresourcemanagerService *cloudresourcemanager.Service
OrganizationsService *cloudresourcemanager.OrganizationsService
OrganizationsClient *resourcemanager.OrganizationsClient
FoldersClient *resourcemanager.FoldersClient
ProjectsClient *resourcemanager.ProjectsClient
StorageService *storage.Service
FoldersService *cloudresourcemanager.FoldersService
ProjectsService *cloudresourcemanager.ProjectsService
CloudAssetService *cloudasset.Service
ResourcesService *cloudasset.ResourcesService
IamPoliciesService *cloudasset.IamPoliciesService
// user resource selectors
selectedOrganizations []string
selectedFolders []string
selectedProjects []string
// final resources for module usage
ResourceRoots []*internal.Node
Organizations []string
Folders []string
Projects []string
}
func (g *GCPClient) init(profile string) {
g.Logger = internal.NewLogger()
ctx := context.Background()
var (
profiles []GCloudProfile
client_profile *GCloudProfile
err error
)
profiles = listAllProfiles()
for _, p := range profiles {
if (p.Name == profile) {
client_profile = &p
g.Name = profile
break
}
}
// Initiate an http.Client. The following GET request will be
// authorized and authenticated on the behalf of the SDK user.
g.HTTPClient = client_profile.oauth_conf.Client(ctx, &(client_profile.initial_token))
// Create all the clients
g.OrganizationsClient, err = resourcemanager.NewOrganizationsRESTClient(ctx, option.WithHTTPClient(g.HTTPClient))
if (err != nil){
g.Logger.Fatal(fmt.Sprintf("Could not initiate GCP Organization Client: %v", err))
}
g.FoldersClient, err = resourcemanager.NewFoldersRESTClient(ctx, option.WithHTTPClient(g.HTTPClient))
if (err != nil){
g.Logger.Fatal(fmt.Sprintf("Could not initiate GCP Folders Client: %v", err))
}
g.ProjectsClient, err = resourcemanager.NewProjectsRESTClient(ctx, option.WithHTTPClient(g.HTTPClient))
if (err != nil){
g.Logger.Fatal(fmt.Sprintf("Could not initiate GCP Projects Client: %v", err))
}
ts, err := google.DefaultTokenSource(ctx)
if err != nil {
log.Fatal(err)
}
g.TokenSource = &ts
oauth2Service, err := goauth2.NewService(ctx, option.WithHTTPClient(g.HTTPClient))
tokenInfo, err := oauth2Service.Tokeninfo().Do()
if err != nil {
log.Fatal(err)
}
g.TokenInfo = tokenInfo
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx, option.WithHTTPClient(g.HTTPClient))
if err != nil {
log.Fatal(err)
}
g.CloudresourcemanagerService = cloudresourcemanagerService
cloudassetService, err := cloudasset.NewService(ctx, option.WithHTTPClient(g.HTTPClient))
if err != nil {
log.Fatal(err)
}
g.CloudAssetService = cloudassetService
storageService, err := storage.NewService(ctx, option.WithHTTPClient(g.HTTPClient))
g.StorageService = storageService
g.ResourcesService = cloudasset.NewResourcesService(cloudassetService)
g.IamPoliciesService = cloudasset.NewIamPoliciesService(cloudassetService)
g.OrganizationsService = cloudresourcemanager.NewOrganizationsService(cloudresourcemanagerService)
g.FoldersService = cloudresourcemanager.NewFoldersService(cloudresourcemanagerService)
g.ProjectsService = cloudresourcemanager.NewProjectsService(cloudresourcemanagerService)
}
func (g *GCPClient) GetResourcesRoots(organizations []string, folders []string, projects []string) []*internal.Node {
var (
root internal.Node
current *internal.Node
selected bool
)
// make user selectors available to whole client
g.selectedOrganizations = organizations
g.selectedFolders = folders
g.selectedProjects = projects
ctx := context.Background()
// define root node, labelled with current profile name
root = internal.Node{ID: g.Name}
// by default, don't select organization
selected = false
// if a no selector is submitted, all the resources will have to be included
if len(organizations) == 0 && len(folders) == 0 && len(projects) == 0 {
selected = true
}
// now look for resources (projects) that do not have a parent and that live in the user' account directly
// might need to investigate later but it looks like we can't have folders under a user account
projectsListResponse, _ := g.CloudresourcemanagerService.Projects.List().Do()
for _, project := range projectsListResponse.Projects {
if project.Parent == nil {
if selected {
g.Projects = append(g.Projects, project.ProjectId)
}
// if project is selected, add a new root node
for _, filterProject := range g.selectedProjects {
if (project.ProjectId == filterProject || fmt.Sprint(project.ProjectNumber) == filterProject) {
g.ResourceRoots = append(g.ResourceRoots, current)
break
}
}
current = &internal.Node{ID: fmt.Sprintf("p:%s (%s - %d)", project.Name, project.ProjectId, project.ProjectNumber)}
root.Add(*current)
}
}
// iterate over available organizations
organizationIterator := g.OrganizationsClient.SearchOrganizations(ctx, &resourcemanagerpb.SearchOrganizationsRequest{})
for {
organization, err := organizationIterator.Next()
if err == iterator.Done {
break
}
if err != nil {
g.Logger.FatalM(fmt.Sprintf("An error occurred when listing organizations: %v", err), globals.GCP_HIERARCHY_MODULE_NAME)
}
current = &internal.Node{ID: fmt.Sprintf("%s (%s)", organization.DisplayName, organization.Name[14:])}
// if organization is selected, add a new root node
for _, filterOrg := range organizations {
if (organization.DisplayName == filterOrg || organization.Name[14:] == filterOrg) {
g.Organizations = append(g.Organizations, organization.DisplayName)
g.ResourceRoots = append(g.ResourceRoots, current)
selected = true
break
}
}
// get childs (projects & folders) within current orgnization
g.getChilds(current, organization.Name, selected)
// add the folder as a child to the root node
root.Add(*current)
}
// if no resource root has been found through filtering, add the default root, which is the current user account
if len(g.ResourceRoots) == 0 {
g.Logger.InfoM("Could not find resources with resources selectors, default root resource", globals.GCP_HIERARCHY_MODULE_NAME)
g.ResourceRoots = append(g.ResourceRoots, &root)
}
return g.ResourceRoots
}
func (g *GCPClient) getChilds(parent *internal.Node, parentName string, selected bool){
//GCPLogger.Success(fmt.Sprintf("Listing stuff in parent %s", parentName))
var (
current *internal.Node
)
ctx := context.Background()
folderIterator := g.FoldersClient.SearchFolders(ctx, &resourcemanagerpb.SearchFoldersRequest{Query: fmt.Sprintf("parent=%s", parentName)})
for {
folder, err := folderIterator.Next()
if err == iterator.Done {
break
}
if err != nil {
g.Logger.FatalM(fmt.Sprintf("An error occurred when listing folders in parent %s: %v", parentName, err), globals.GCP_HIERARCHY_MODULE_NAME)
}
current = &internal.Node{ID: fmt.Sprintf("f:%s (%s)", folder.DisplayName, folder.Name[8:])}
if !selected {
for _, filterFolder := range g.selectedFolders {
if (folder.DisplayName == filterFolder || folder.Name[8:] == filterFolder) {
g.Folders = append(g.Folders, folder.DisplayName)
g.ResourceRoots = append(g.ResourceRoots, current)
break
}
}
}
g.getChilds(current, folder.Name, selected)
(*parent).Add(*current)
}
projectIterator := g.ProjectsClient.SearchProjects(ctx, &resourcemanagerpb.SearchProjectsRequest{Query: fmt.Sprintf("parent=%s", parentName)})
for {
project, err := projectIterator.Next()
if err == iterator.Done {
break
}
if err != nil {
g.Logger.FatalM(fmt.Sprintf("An error occurred when listing projects in parent %s: %v", parentName, err), globals.GCP_HIERARCHY_MODULE_NAME)
}
current = &internal.Node{ID: fmt.Sprintf("p:%s (%s - %s)", project.DisplayName, project.ProjectId, project.Name[9:])}
if !selected {
for _, filterProject := range g.selectedProjects {
if (project.ProjectId == filterProject || project.Name[9:] == filterProject) {
g.Projects = append(g.Projects, project.ProjectId)
g.ResourceRoots = append(g.ResourceRoots, current)
break
}
}
}
(*parent).Add(*current)
}
}
func NewGCPClient(profileName string) *GCPClient {
client := new(GCPClient)
client.init(profileName)
return client
}
/*
Get all usable GCP Profiles
We are using only non expired user-tokens
*/
func GetAllGCPProfiles() []string {
var (
GCPProfiles []string
accessTokens []Token
)
accessTokens = ReadAccessTokens()
for _, accessToken := range accessTokens {
if (!strings.Contains(accessToken.AccountID, "@")) {
continue
}
exp, _ := time.Parse(time.RFC3339, accessToken.TokenExpiry)
if exp.After(time.Now()) {
GCPProfiles = append(GCPProfiles, accessToken.AccountID)
}
}
return GCPProfiles
}
func ConfirmSelectedProfiles(GCPProfiles []string) bool {
reader := bufio.NewReader(os.Stdin)
logger.Info("Identified profiles:\n")
for _, profile := range GCPProfiles {
fmt.Printf("\t* %s\n", profile)
}
fmt.Printf("\n")
logger.Info(fmt.Sprintf("Are you sure you'd like to run this command against the [%d] listed profile(s)? (Y\\n): ", len(GCPProfiles)))
text, _ := reader.ReadString('\n')
switch text {
case "\n", "Y\n", "y\n":
return true
}
return false
}
func GetSelectedGCPProfiles(GCPProfilesListPath string) []string {
GCPProfilesListFile, err := internal.UtilsFs.Open(GCPProfilesListPath)
internal.CheckErr(err, fmt.Sprintf("could not open given file %s", GCPProfilesListPath))
if err != nil {
fmt.Printf("\nError loading profiles. Could not open file at location[%s]\n", GCPProfilesListPath)
os.Exit(1)
}
defer GCPProfilesListFile.Close()
var GCPProfiles []string
scanner := bufio.NewScanner(GCPProfilesListFile)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
profile := strings.TrimSpace(scanner.Text())
if len(profile) != 0 {
GCPProfiles = append(GCPProfiles, profile)
}
}
return GCPProfiles
}
+55
View File
@@ -3,12 +3,16 @@ package internal
import (
"log"
"os"
"fmt"
"os/user"
"path/filepath"
"github.com/BishopFox/cloudfox/globals"
"github.com/aws/smithy-go/ptr"
"github.com/jedib0t/go-pretty/text"
"github.com/kyokomi/emoji"
"github.com/fatih/color"
"github.com/sirupsen/logrus"
)
func init() {
@@ -28,3 +32,54 @@ func GetLogDirPath() *string {
}
return ptr.String(dir)
}
type Logger struct {
version string
txtLog *logrus.Logger
}
func NewLogger() Logger {
var logger = Logger{
version: globals.CLOUDFOX_VERSION,
txtLog: TxtLog,
}
return logger
}
func (l *Logger) Info(text string){
l.InfoM(text, "config")
}
func (l *Logger) InfoM(text string, module string) {
var cyan = color.New(color.FgCyan).SprintFunc()
fmt.Printf("[%s][%s] %s\n", cyan(emoji.Sprintf(":fox:cloudfox %s :fox:", l.version)), cyan(module), text)
}
func (l *Logger) Success(text string){
l.SuccessM(text, "config")
}
func (l *Logger) SuccessM(text string, module string) {
var green = color.New(color.FgGreen).SprintFunc()
fmt.Printf("[%s][%s] %s\n", green(emoji.Sprintf(":fox:cloudfox %s :fox:", l.version)), green(module), text)
}
func (l *Logger) Error(text string){
l.ErrorM(text, "config")
}
func (l *Logger) ErrorM(text string, module string) {
var red = color.New(color.FgRed).SprintFunc()
fmt.Printf("[%s][%s] %s\n", red(emoji.Sprintf(":fox:cloudfox %s :fox:", l.version)), red(module), text)
l.txtLog.Printf("[%s] %s", module, text)
}
func (l *Logger) Fatal(text string){
l.FatalM(text, "config")
}
func (l *Logger) FatalM(text string, module string) {
var red = color.New(color.FgRed).SprintFunc()
l.txtLog.Printf("[%s] %s", module, text)
fmt.Printf("[%s][%s] %s\n", red(emoji.Sprintf(":fox:cloudfox %s :fox:", l.version)), red(module), text)
os.Exit(1)
}
+26
View File
@@ -0,0 +1,26 @@
package internal
import (
"github.com/shivamMg/ppds/tree"
)
type Node struct {
ID string
c []*Node
}
func (n *Node) Data() interface{} {
return n.ID
}
func (n *Node) Children() (children []tree.Node) {
for _, c := range n.c {
children = append(children, tree.Node(c))
}
return
}
func (n *Node) Add(child Node) {
n.c = append(n.c, &child)
return
}
+3 -2
View File
@@ -4,17 +4,18 @@ import (
"os"
"github.com/BishopFox/cloudfox/cli"
"github.com/BishopFox/cloudfox/globals"
"github.com/spf13/cobra"
)
var (
rootCmd = &cobra.Command{
Use: os.Args[0],
Version: "1.11.2",
Version: globals.CLOUDFOX_VERSION,
}
)
func main() {
rootCmd.AddCommand(cli.AWSCommands, cli.AzCommands)
rootCmd.AddCommand(cli.AWSCommands, cli.AzCommands, cli.GCPCommands)
rootCmd.Execute()
}