Compare commits

...
91 Commits
Author SHA1 Message Date
jbarciabf b994b42708 Merge pull request #115 from BishopFox/fix/makefile-tab-signed3
fixed makefile
2025-12-17 13:01:58 -05:00
jbarciabf 52c12855a1 fixed makefile 2025-12-17 11:21:28 -05:00
jbarciabf 70037750c5 Merge pull request #109 from sethsec/fix_regions_error
Fix awsservicemap download, added more logging to all commands/sdk calls
2025-12-17 10:45:11 -05:00
Seth Art 1bb8576a27 Added logging for all successfull API calls to cloudfox-info.log 2025-12-15 13:33:55 -05:00
Seth Art 16b3c66624 Unified logging around logrus. removed standard logging lines. 2025-12-15 13:33:54 -05:00
Seth Art 3dbb98ffc6 Added split level logging to logrus 2025-12-15 13:33:54 -05:00
Seth Art b3a03ec7bd Fixed small bug with inventory where it was counting total resources incorrectly 2025-12-15 13:33:54 -05:00
Seth Art 521cf7e4f4 Reduced the number of times awsservicemap calls out to get the AWS json 2025-12-15 13:33:54 -05:00
jbarciabf 5115f849f5 Update CODEOWNERS 2025-08-05 15:57:12 -04:00
jbarciabf 9e42b53d22 Merge pull request #104 from sethsec/main
v1.16.0 - Addes multiple resource types to resource-trusts command thanks to @edops973
2025-08-05 15:50:49 -04:00
Bastien Faure b28ed6a3fd Update CODEOWNERS 2025-08-05 10:07:55 -04:00
Seth Art 0e7b006cde Merge branch 'main' into main 2025-04-21 11:49:06 -04:00
Seth Art 2cc97f508b Update version to 1.16.0 2025-04-21 11:43:07 -04:00
Seth Art 031d666c63 Merge pull request #6 from edops973/feature/add-opensearch-to-resource-trusts-command
feat: Add opensearch to resource trusts command
2025-04-21 10:19:43 -04:00
Seth Art d0de59dbe4 update opensearch mod 2025-04-21 10:19:06 -04:00
Seth Art 00b49aa33c Merge branch 'main' into feature/add-opensearch-to-resource-trusts-command 2025-04-16 19:15:07 -04:00
Seth Art 12ee6c292a Merge pull request #5 from edops973/feature/add-vpcendpoint-to-resource-trusts-command
feat: Add vpcendpoint to resource trusts command
2025-04-16 19:11:35 -04:00
Seth Art 4584774ec1 updated arn column to print full arn 2025-04-16 17:10:59 -06:00
Seth Art d558e1cf55 Update supported services banner 2025-04-16 16:56:11 -06:00
Seth Art 19b825cfa6 Merge remote-tracking branch 'origin' into feature/add-vpcendpoint-to-resource-trusts-command 2025-04-16 16:48:21 -06:00
Seth Art 698458cf92 Merge pull request #4 from edops973/feature/add-apigateway-service-to-resource-trusts-command
feat: Add apigateway service to resource trusts command
2025-04-16 18:43:00 -04:00
edops973 dfed0491f2 Ignore public apigateway in resource trusts command 2025-03-27 20:43:43 +07:00
edops973 7671e7e717 Add opensearch unittest 2025-03-15 22:53:01 +07:00
edops973 0c858e6cd4 Add missing method in codebuild_mocks.go 2025-03-15 22:47:53 +07:00
edops973 0deb568e41 Get open search policies 2025-03-15 22:47:43 +07:00
edops973 2806f7ea08 Merge conflict 2025-03-15 22:45:10 +07:00
edops973 e54ffe8ce7 Merge conflict 2025-03-15 22:43:21 +07:00
edops973 56e64d8e62 Merge conflict 2025-03-15 22:41:45 +07:00
edops973 43fe99e832 Merge conflict 2025-03-15 22:35:23 +07:00
edops973 5d2f2616af Merge conflict 2025-03-15 22:33:21 +07:00
edops973 d8e4157e93 Fix resource-trusts unittest 2025-03-15 22:15:04 +07:00
edops973 a104639354 Merge conflict 2025-03-15 22:01:17 +07:00
edops973 296710c474 Merge conflict 2025-03-15 21:56:19 +07:00
Seth Art 278e2658ee Merge pull request #2 from edops973/feature/add-kms-service-to-resource-trusts-command
feat: Add kms service to resource trusts command
2025-03-15 10:39:58 -04:00
Seth Art 6b45f54699 Removed block that ran kms even without feature flag. Also edited supported serviecs line to account for feature flag use 2025-03-15 10:38:38 -04:00
Seth Art 2391bb7802 merge updates 2025-03-15 10:31:23 -04:00
Seth Art 68d68fc75d fix typo in utils.go 2025-03-15 10:19:31 -04:00
edops973 7d6d16a4f1 Merge branch 'main' into feature/add-kms-service-to-resource-trusts-command 2025-03-14 06:04:02 -05:00
edops973 caaf399e9d Add feature flag for KMS service in resource-trusts command 2025-03-14 18:02:13 +07:00
edops973 1f4f128a7a Add checksum to the release packages 2025-03-14 18:02:12 +07:00
Seth Art 16c0f4dfe9 Bump version to v1.16.0-prerelease 2025-03-14 18:02:11 +07:00
edops973 7e6439924a Remove task definition column in env-vars command 2025-03-14 18:02:11 +07:00
edops973 d3c042c1e3 Add task definition column to env-vars command 2025-03-14 18:02:07 +07:00
edops973 cda06fff7a Add container name column to ecs-tasks command 2025-03-14 18:02:05 +07:00
edops973 e49402991a Fix the order of input parameters when fetching KMS policy 2025-03-14 18:01:59 +07:00
edops973 cae31fbf21 fix kms client nil when running all-checks command 2025-03-14 18:01:52 +07:00
edops973 4e75b1151b Add resource-trusts KMS unit test 2025-03-14 18:01:43 +07:00
edops973 831198c42d Support kms service for command resource-trusts 2025-03-14 18:01:35 +07:00
Bastien Faure 2cb5ad2b83 Merge pull request #97 from DominicBreuker/route53-bugfix
AWS Route53 Alias Record Support
2025-03-13 19:04:21 -04:00
Bastien Faure efe95c02ee Merge pull request #102 from crahan/linux-arm64
Add support for building Linux Arm64 binaries
2025-03-13 19:02:27 -04:00
CraHan 13bd04d3e4 Add support for building Linux Arm64 2025-03-13 19:01:26 -04:00
Seth Art b8d9d8093c Merge pull request #3 from edops973/feature/add-checksum-to-release
feat: Add checksum to the release packages
2025-03-12 16:26:11 -04:00
Seth Art b139513244 Merge pull request #1 from edops973/feature/add-taskdefinition-to-ecs-tasks-and-env-vars-command
feat: Add taskdefinition to ecs tasks and env vars command
2025-03-12 16:23:08 -04:00
Seth Art f058e1c57d Bump version to v1.16.0-prerelease 2025-03-12 16:21:54 -04:00
edops973 a94bdc1853 Remove task definition column in env-vars command 2025-03-13 02:45:39 +07:00
edops973 89b3492399 Fix the order of input parameters when fetching KMS policy 2025-03-13 00:00:16 +07:00
edops973 67b84f0c74 fix kms client nil when running all-checks command 2025-03-10 23:09:21 +07:00
edops973 8eec1c331b Add checksum to the release packages 2025-03-09 00:51:00 +07:00
edops973 5e0eb15f7d Add resource-trusts KMS unit test 2025-03-07 18:18:05 +07:00
edops973 ec497faba4 Support kms service for command resource-trusts 2025-03-07 15:25:53 +07:00
edops973 ed8e0a229c Add task definition column to env-vars command 2025-03-05 15:50:58 +07:00
edops973 b60f479c2d Add container name column to ecs-tasks command 2025-03-05 15:50:32 +07:00
Dominic Breuker ab4866fcbf fix bug with route53 alias record processing 2024-11-13 21:24:17 +01:00
Dominic Breuker 00fe4fdce3 add support for Route53 Alias records in route53 command 2024-10-30 21:22:22 +01:00
Bastien Faure f7d1cbcdb6 Merge pull request #96 from BishopFox/aws-principals-with-admin-check
Bug fixes and small feature updates
2024-10-17 10:47:11 +02:00
Seth Art b3c25bb5d0 spelling fix 2024-10-15 16:28:04 -04:00
Seth Art 9076beb111 Bumped version to 1.15.0 2024-10-15 16:26:04 -04:00
Seth Art 878d7ec0c4 Fixed bug in cape where files did not exist crash. Fixed bug that duplicated edges because of magenta. 2024-10-15 16:16:31 -04:00
Seth Art ebf9985d40 Fix for #92 2024-10-10 19:14:09 -04:00
Seth Art 8e1e8d0c0a Fix for cape that also makes edges for cross-account explicit trusts. Also added a new flag to ignore certain edges entirely. 2024-10-10 18:23:54 -04:00
Seth Art a88e98aedd Removed AWSSSO-ACCOUNTID entries from cape table as they are redundant 2024-09-30 16:05:49 -04:00
Seth Art 85b9b11798 Bumped version to 1.43.3 2024-09-24 16:17:49 -04:00
Seth Art 6b0970ebd7 Fix for cape in regards to permission expansion 2024-09-24 16:15:49 -04:00
Seth Art e0dc71b414 updated the adminActionNames check actions to remove ssm get documents and replace with ssm get parameters 2024-09-23 13:48:28 -04:00
Seth Art b31f36746b added the the --admin-check-only flag to iam-simulator command 2024-09-23 13:47:07 -04:00
Seth Art 0a95240b7f added admin/pmapper logic to principals command 2024-09-23 13:45:59 -04:00
David 785b69316a Merge pull request #93 from BishopFox/imds-fix
Fix for IMDS not working due to breaking change in aws-sdk-go-v2.
2024-08-09 00:19:47 -04:00
Seth Art 547c48a249 Merge branch 'main' into imds-fix 2024-08-07 21:42:54 -04:00
Seth Art aed3c0abdb bump version 2024-08-07 13:27:14 -04:00
Seth Art 0184e1520d Fix for IMDS not working due to breaking change in aws-sdk-go-v2. 2024-08-06 23:45:04 -04:00
David 70a050a973 Merge pull request #90 from BishopFox/add-386-binary-to-release
Update Makefile to include 386 linux binary for release action
2024-07-03 22:39:48 -04:00
David 738085dc78 fix typo from codespell 2024-07-03 17:59:19 -04:00
Seth Art 0ac24e3aa1 Update utils.go
bumping the version so that once this is merged and we can create a new tag and release on the new version
2024-07-02 11:48:36 -04:00
Seth Art 5ba8b087ff Update Makefile to include 386 linux binary for release action 2024-07-02 11:45:44 -04:00
Bastien Faure b02ad612f0 Merge pull request #89 from BishopFox/aws-databases-rds-fix
Aws databases rds fix
2024-06-03 19:47:52 -07:00
Bastien Faure 3759d2c57d Merge pull request #87 from testwill/close_file
fix: close input file
2024-06-03 19:46:25 -07:00
Seth Art 0b88bcac56 Updated tests to make sure that RDS instances without clusters are checked for 2024-05-29 11:30:49 -04:00
Seth Art 91f5f14f0e Added RDS database instances back into output. I think it's ok to have both clusters and instances in the output 2024-05-29 10:07:02 -04:00
guangwu ca810a00d7 fix: close input file 2024-05-11 20:43:07 +08:00
David d9cbefd911 Merge pull request #84 from BishopFox/graph
v1.14.0, cape
2024-04-16 14:41:05 -04:00
Seth Art bfa95acafe Merge pull request #81 from BishopFox/bastien_directoryservice_aws
Add Directory Service support for AWS
2024-04-16 14:14:32 -04:00
103 changed files with 3987 additions and 1023 deletions

No files matched your search

+1 -1
View File
@@ -1 +1 @@
* @bishopfaure @dbravo-bishopfox
* @bishopfaure @jbarciabf @msperling-bf
+34 -14
View File
@@ -13,6 +13,12 @@ linux:
zip cloudfox-linux.zip cloudfox sha1sum-linux.txt
rm cloudfox sha1sum-linux.txt
linux-arm64:
GOOS=linux GOARCH=arm64 go build
sha1sum cloudfox > sha1sum-linux-arm64.txt
zip cloudfox-linux-arm64.zip cloudfox sha1sum-linux-arm64.txt
rm cloudfox sha1sum-linux-arm64.txt
macos:
GOOS=darwin GOARCH=amd64 go build
sha1sum cloudfox > sha1sum-mac.txt
@@ -24,22 +30,36 @@ all: windows linux macos
.PHONY: release
release: clean
mkdir -p ./cloudfox
mkdir -p ./cloudfox
GOOS=windows GOARCH=amd64 go build -o ./cloudfox/cloudfox.exe .
zip ./cloudfox/cloudfox-windows-amd64.zip ./cloudfox/cloudfox.exe
rm -rf ./cloudfox/cloudfox.exe
sha1sum ./cloudfox/cloudfox.exe > ./cloudfox/sha1sum.txt
zip ./cloudfox/cloudfox-windows-amd64.zip ./cloudfox/cloudfox.exe ./cloudfox/sha1sum.txt
rm -rf ./cloudfox/cloudfox.exe ./cloudfox/sha1sum.txt
GOOS=linux GOARCH=amd64 go build -o ./cloudfox/cloudfox .
zip ./cloudfox/cloudfox-linux-amd64.zip ./cloudfox/cloudfox .
rm -rf ./cloudfox/cloudfox
sha1sum ./cloudfox/cloudfox > ./cloudfox/sha1sum.txt
zip ./cloudfox/cloudfox-linux-amd64.zip ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
rm -rf ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
GOOS=linux GOARCH=386 go build -o ./cloudfox/cloudfox .
sha1sum ./cloudfox/cloudfox > ./cloudfox/sha1sum.txt
zip ./cloudfox/cloudfox-linux-386.zip ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
rm -rf ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
GOOS=linux GOARCH=arm64 go build -o ./cloudfox/cloudfox .
sha1sum ./cloudfox/cloudfox > ./cloudfox/sha1sum.txt
zip ./cloudfox/cloudfox-linux-arm64.zip ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
rm -rf ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
GOOS=darwin GOARCH=amd64 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 .
zip ./cloudfox/cloudfox-macos-arm64.zip ./cloudfox/cloudfox
rm -rf ./cloudfox/cloudfox
sha1sum ./cloudfox/cloudfox > ./cloudfox/sha1sum.txt
zip ./cloudfox/cloudfox-macos-amd64.zip ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
rm -rf ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
clean:
rm -rf ./cloudfox
GOOS=darwin GOARCH=arm64 go build -o ./cloudfox/cloudfox .
sha1sum ./cloudfox/cloudfox > ./cloudfox/sha1sum.txt
zip ./cloudfox/cloudfox-macos-arm64.zip ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
rm -rf ./cloudfox/cloudfox ./cloudfox/sha1sum.txt
clean:
rm -rf ./cloudfox
+1 -1
View File
@@ -133,7 +133,7 @@ Additional policy notes (as of 09/2022):
| AWS | [pmapper](https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#pmapper) | Looks for pmapper data stored on the local filesystem, [in the locations defined here](https://github.com/nccgroup/PMapper/wiki/Frequently-Asked-Questions#where-does-pmapper-store-its-data). If pmapper data has been found (you already ran `pmapper graph create`), then this command will use this data to build a graph in cloudfox memory let you know who can privesc to admin.
| AWS | [principals](https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#principals) | Enumerates IAM users and Roles so you have the data at your fingertips. |
| AWS | [ram](https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#ram) | List all resources in this account that are shared with other accounts, or resources from other accounts that are shared with this account. Useful for cross-account attack paths. |
| AWS | [resource-trusts](https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#resource-trusts) | Looks through multiple services that support resource policies and helps you find any overly permissive resource trusts.|
| AWS | [resource-trusts](https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#resource-trusts) | Looks through multiple services that support resource policies and helps you find any overly permissive resource trusts. KMS is supported but disabled by default. To include KMS resource policies in the output, add this flag to the command: `cloudfox aws resource-trusts --include-kms`.|
| AWS | [role-trusts](https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#role-trusts) | Enumerates IAM role trust policies so you can look for overly permissive role trusts or find roles that trust a specific service. |
| AWS | [route53](https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#route53) | Enumerate all records from all route53 managed zones. Use this for application and service enumeration. |
| AWS | [secrets](https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#secrets) | List secrets from SecretsManager and SSM. Look for interesting secrets in the list and then see who has access to them using use `cloudfox iam-simulator` and/or `pmapper`. |
+8 -3
View File
@@ -30,6 +30,7 @@ type ApiGwModule struct {
Goroutines int
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
Gateways []ApiGateway
@@ -178,10 +179,14 @@ func (m *ApiGwModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan
// <-semaphore
// }()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("apigateway", r)
res, err := servicemap.IsServiceInRegion("api-gateway", r)
if err != nil {
m.modLog.Error(err)
}
+7
View File
@@ -10,11 +10,17 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/sts"
"github.com/aws/smithy-go/ptr"
"github.com/bishopfox/awsservicemap"
"github.com/spf13/afero"
)
func TestApiGw(t *testing.T) {
// Create a service map that downloads from AWS
serviceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
m := ApiGwModule{
AWSProfile: "unittesting",
AWSRegions: []string{"us-east-1"},
@@ -26,6 +32,7 @@ func TestApiGw(t *testing.T) {
WrapTable: false,
APIGatewayClient: &sdk.MockedAWSAPIGatewayClient{},
APIGatewayv2Client: &sdk.MockedAWSAPIGatewayv2Client{},
ServiceMap: serviceMap,
}
fs := internal.MockFileSystem(true)
+1 -1
View File
@@ -301,7 +301,7 @@ func preloadData(filePaths []string) (*AllAccountData, error) {
for _, filePath := range filePaths {
fileRecords, err := loadFileRecords(filePath)
if err != nil {
if err != nil {
return nil, err
}
appData.Files[filePath] = fileRecords
+73 -5
View File
@@ -1,7 +1,9 @@
package aws
import (
"bufio"
"fmt"
"os"
"path/filepath"
"strings"
@@ -200,7 +202,12 @@ func (m *CapeCommand) findPathsToThisDestination(allGlobalNodes map[string]map[s
s, sourceVertexWithProperties, _ := m.GlobalGraph.VertexWithProperties(source)
//for the source vertex, we only want to deal with the ones that are NOT in this account
if sourceVertexWithProperties.Attributes["AccountID"] != aws.ToString(m.Caller.Account) {
// skip if the source Name contains AWSSSO-
if strings.Contains(sourceVertexWithProperties.Attributes["Name"], "AWSSSO-") {
continue
}
// now let's see if there is a path from this source to our destination
path, _ := graph.ShortestPath(m.GlobalGraph, s, d)
// if we have a path, then lets document this source as having a path to our destination
if path != nil {
@@ -235,7 +242,7 @@ func (m *CapeCommand) findPathsToThisDestination(allGlobalNodes map[string]map[s
privescPathsBody = append(privescPathsBody, []string{
aws.ToString(m.Caller.Account),
s,
magenta(d),
d,
magenta(destinationVertexWithProperties.Attributes["IsAdminString"]),
paths})
} else {
@@ -289,7 +296,7 @@ func ConvertIAMRoleToNode(role types.Role, vendors *knownawsaccountslookup.Vendo
TrustedPrincipals = append(TrustedPrincipals, TrustedPrincipal{
TrustedPrincipal: principal,
ExternalID: statement.Condition.StringEquals.StsExternalID,
ExternalID: strings.Join(statement.Condition.StringEquals.StsExternalID, "\n"),
VendorName: vendorName,
//IsAdmin: false,
//CanPrivEscToAdmin: false,
@@ -650,6 +657,48 @@ func (a *Node) MakeRoleEdges(GlobalGraph graph.Graph[string, string]) {
}
}
// if the role trusts a principal in another account explicitly, then the principal can assume the role
if thisAccount != trustedPrincipalAccount {
// make a CAN_ASSUME relationship between the trusted principal and this role
err := GlobalGraph.AddEdge(
TrustedPrincipal.TrustedPrincipal,
a.Arn,
//graph.EdgeAttribute("AssumeRole", "Cross account explicit trust"),
graph.EdgeAttribute("AssumeRole", "can assume (because of an explicit cross account trust) "),
)
if err != nil {
//fmt.Println(err)
//fmt.Println(TrustedPrincipal.TrustedPrincipal + a.Arn + "Cross account explicit trust")
if err == graph.ErrEdgeAlreadyExists {
// update the edge by copying the existing graph.Edge with attributes and add the new attributes
//fmt.Println("Edge already exists")
// get the existing edge
existingEdge, _ := GlobalGraph.Edge(TrustedPrincipal.TrustedPrincipal, a.Arn)
// get the map of attributes
existingProperties := existingEdge.Properties
// add the new attributes to attributes map within the properties struct
// Check if the Attributes map is initialized, if not, initialize it
if existingProperties.Attributes == nil {
existingProperties.Attributes = make(map[string]string)
}
// Add or update the attribute
existingProperties.Attributes["AssumeRole"] = "can assume (because of an explicit cross account trust) "
err = GlobalGraph.UpdateEdge(
TrustedPrincipal.TrustedPrincipal,
a.Arn,
graph.EdgeAttributes(existingProperties.Attributes),
)
if err != nil {
fmt.Println(err)
}
}
}
}
// If the role trusts a principal in this account or another account using the :root notation, then we need to iterate over all of the rows in AllPermissionsRows to find the principals that have sts:AssumeRole permissions on this role
// if the role we are looking at trusts root in it's own account
@@ -667,6 +716,7 @@ func (a *Node) MakeRoleEdges(GlobalGraph graph.Graph[string, string]) {
if PermissionsRowAccount == thisAccount {
// lets only look for rows that have sts:AssumeRole permissions
if policy.MatchesAfterExpansion(PermissionsRow.Action, "sts:AssumeRole") {
// lets only focus on rows that have an effect of Allow
if strings.EqualFold(PermissionsRow.Effect, "Allow") {
// if the resource is * or the resource is this role arn, then this principal can assume this role
@@ -820,10 +870,10 @@ func (a *Node) MakeRoleEdges(GlobalGraph graph.Graph[string, string]) {
fmt.Sprintf("Could not get account number from this PermissionsRow%s", PermissionsRow.Arn)
}
if PermissionsRowAccount == trustedPrincipalAccount {
// lets only look for rows that have sts:AssumeRole permissions
if policy.MatchesAfterExpansion(PermissionsRow.Action, "sts:AssumeRole") {
// lets only look for rows that have sts:AssumeRole permis sions
if policy.MatchesAfterExpansion("sts:AssumeRole", PermissionsRow.Action) {
// if strings.EqualFold(PermissionsRow.Action, "sts:AssumeRole") ||
// strings.EqualFold(PermissionsRow.Action, "*") ||
// strings.EqualFold(PermissionsRow.Action, "*") {
// strings.EqualFold(PermissionsRow.Action, "sts:Assume*") ||
// strings.EqualFold(PermissionsRow.Action, "sts:*") {
// lets only focus on rows that have an effect of Allow
@@ -979,3 +1029,21 @@ func (a *Node) MakeRoleEdges(GlobalGraph graph.Graph[string, string]) {
}
}
// function to read file specified in CapeArnIgnoreList which is separated by newlines, and convert it to a slice of strings with each line as an entry in the slice.
// the function accepts a string with the filename
func ReadArnIgnoreListFile(filename string) ([]string, error) {
var arnIgnoreList []string
file, err := os.Open(filename)
if err != nil {
return arnIgnoreList, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
arnIgnoreList = append(arnIgnoreList, scanner.Text())
}
return arnIgnoreList, scanner.Err()
}
+2
View File
@@ -17,6 +17,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/sns"
"github.com/aws/aws-sdk-go-v2/service/sqs"
"github.com/aws/aws-sdk-go-v2/service/sts"
"github.com/sirupsen/logrus"
)
func InitIamCommandClient(iamSimPPClient sdk.AWSIAMClientInterface, caller sts.GetCallerIdentityOutput, AWSProfile string, Goroutines int) IamSimulatorModule {
@@ -26,6 +27,7 @@ func InitIamCommandClient(iamSimPPClient sdk.AWSIAMClientInterface, caller sts.G
Caller: caller,
AWSProfileProvided: AWSProfile,
Goroutines: Goroutines,
modLog: internal.TxtLog.WithFields(logrus.Fields{"module": "iam-simulator"}),
}
return iamSimMod
+7 -2
View File
@@ -28,6 +28,7 @@ type CloudformationModule struct {
WrapTable bool
AWSOutputType string
AWSTableCols string
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
CFStacks []CFStack
@@ -192,8 +193,12 @@ func (m *CloudformationModule) PrintCloudformationStacks(outputDirectory string,
func (m *CloudformationModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan CFStack) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
serviceRegions, err := servicemap.GetRegionsForService("cloudformation")
if err != nil {
+7 -2
View File
@@ -29,6 +29,7 @@ type CodeBuildModule struct {
AWSProfile string
SkipAdminCheck bool
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
pmapperMod PmapperModule
pmapperError error
iamSimClient IamSimulatorModule
@@ -211,8 +212,12 @@ func (m *CodeBuildModule) PrintCodeBuildProjects(outputDirectory string, verbosi
func (m *CodeBuildModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Project) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("codebuild", r)
if err != nil {
+85 -2
View File
@@ -30,6 +30,7 @@ type DatabasesModule struct {
Goroutines int
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
Databases []Database
CommandCounter internal.CommandCounter
@@ -231,8 +232,12 @@ func (m *DatabasesModule) Receiver(receiver chan Database, receiverDone chan boo
func (m *DatabasesModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Database) {
defer wg.Done()
serviceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
serviceMap := m.ServiceMap
if serviceMap == nil {
serviceMap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
m.executeRdsCheck(r, wg, semaphore, dataReceiver, serviceMap) // Also returns Neptune and DocDB
m.executeRedshiftCheck(r, wg, semaphore, dataReceiver, serviceMap)
@@ -271,6 +276,15 @@ func (m *DatabasesModule) executeRdsCheck(r string, wg *sync.WaitGroup, semaphor
service: "rds",
executor: m.getRdsClustersPerRegion,
})
m.executeCheck(check{
region: r,
wg: wg,
semaphore: semaphore,
dataReceiver: dataReceiver,
serviceMap: servicemap,
service: "rds",
executor: m.getRdsInstancesPerRegion,
})
}
func (m *DatabasesModule) executeRedshiftCheck(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Database, servicemap *awsservicemap.AwsServiceMap) {
@@ -395,6 +409,75 @@ func (m *DatabasesModule) getRdsClustersPerRegion(r string, wg *sync.WaitGroup,
}
}
func (m *DatabasesModule) getRdsInstancesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Database) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
wg.Done()
}()
semaphore <- struct{}{}
defer func() {
<-semaphore
}()
m.CommandCounter.Pending--
m.CommandCounter.Executing++
DBInstances, err := sdk.CachedRDSDescribeDBInstances(m.RDSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
return
}
for _, instance := range DBInstances {
var public string
var service string
var roles string
if instance.Endpoint == nil {
continue
}
name := aws.ToString(instance.DBInstanceIdentifier)
port := instance.Endpoint.Port
endpoint := aws.ToString(instance.Endpoint.Address)
engine := aws.ToString(instance.Engine)
if aws.ToBool(instance.PubliclyAccessible) {
public = "True"
} else {
public = "False"
}
if isNeptune(instance.Engine) {
service = "Neptune"
} else if isDocDB(instance.Engine) {
service = "DocsDB"
} else {
service = "RDS"
}
associatedRoles := instance.AssociatedRoles
for _, role := range associatedRoles {
roles = roles + aws.ToString(role.RoleArn) + " "
}
dataReceiver <- Database{
AWSService: service,
Region: r,
Name: name,
Engine: engine,
Endpoint: endpoint,
UserName: aws.ToString(instance.MasterUsername),
Port: aws.ToInt32(port),
Protocol: aws.ToString(instance.Engine),
Public: public,
Roles: roles,
}
}
}
func (m *DatabasesModule) getRedshiftDatabasesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Database) {
defer func() {
m.CommandCounter.Executing--
+5 -4
View File
@@ -42,10 +42,11 @@ func TestDatabasesCommand(t *testing.T) {
}
expectedResults := []string{
"db1.cluster-123456789012.us-west-2.rds.amazonaws.com",
"db2.cluster-123456789012.us-west-2.rds.amazonaws.com",
"db3.cluster-123456789012.us-west-2.neptune.amazonaws.com",
"db4.cluster-123456789012.us-west-2.docdb.amazonaws.com",
"db1.cluster-123456789012.us-west-2.rds.amazonaws.com", // make sure it includes the Aurora clusters
"db2.cluster-123456789012.us-west-2.rds.amazonaws.com", // make sure it includes the Aurora clusters
"db3.cluster-123456789012.us-west-2.neptune.amazonaws.com", // make sure it includes the Neptune instances
"db4.cluster-123456789012.us-west-2.docdb.amazonaws.com", // make sure it includes the DocumentDB instances
"db1-instances-1.blah.us-west-2.rds.amazonaws.com", // make sure it includes the RDS instances
}
for _, expected := range expectedResults {
+8 -3
View File
@@ -31,7 +31,8 @@ type DirectoryModule struct {
AWSProfileProvided string
AWSProfileStub string
CloudFoxVersion string
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
Directories []Directory
CommandCounter internal.CommandCounter
output internal.OutputData2
@@ -190,8 +191,12 @@ func (m *DirectoryModule) PrintDirectories(outputDirectory string, verbosity int
func (m *DirectoryModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Directory) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("clouddirectory", r)
if err != nil {
+7 -2
View File
@@ -30,6 +30,7 @@ type ECRModule struct {
Goroutines int
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
Repositories []Repository
@@ -197,8 +198,12 @@ func (m *ECRModule) PrintECR(outputDirectory string, verbosity int) {
func (m *ECRModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Repository) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("ecr", r)
if err != nil {
+25 -4
View File
@@ -35,6 +35,7 @@ type ECSTasksModule struct {
Goroutines int
SkipAdminCheck bool
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
pmapperMod PmapperModule
pmapperError error
iamSimClient IamSimulatorModule
@@ -50,6 +51,7 @@ type MappedECSTask struct {
Cluster string
TaskDefinitionName string
TaskDefinitionContent string
ContainerName string
LaunchType string
ID string
ExternalIP string
@@ -145,6 +147,7 @@ func (m *ECSTasksModule) printECSTaskData(outputDirectory string, dataReceiver c
"Account",
"Cluster",
"TaskDefinition",
"ContainerName",
"LaunchType",
"ID",
"External IP",
@@ -171,6 +174,7 @@ func (m *ECSTasksModule) printECSTaskData(outputDirectory string, dataReceiver c
"Account",
"Cluster",
"TaskDefinition",
"ContainerName",
"LaunchType",
"ID",
"External IP",
@@ -184,6 +188,7 @@ func (m *ECSTasksModule) printECSTaskData(outputDirectory string, dataReceiver c
tableCols = []string{
"Cluster",
"TaskDefinition",
"ContainerName",
"LaunchType",
"External IP",
"Internal IP",
@@ -206,6 +211,7 @@ func (m *ECSTasksModule) printECSTaskData(outputDirectory string, dataReceiver c
aws.ToString(m.Caller.Account),
ecsTask.Cluster,
ecsTask.TaskDefinitionName,
ecsTask.ContainerName,
ecsTask.LaunchType,
ecsTask.ID,
ecsTask.ExternalIP,
@@ -302,8 +308,12 @@ func (m *ECSTasksModule) writeLoot(outputDirectory string) {
func (m *ECSTasksModule) executeChecks(r string, wg *sync.WaitGroup, dataReceiver chan MappedECSTask) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("ecs", r)
if err != nil {
@@ -368,7 +378,7 @@ func (m *ECSTasksModule) loadTasksData(clusterARN string, taskARNs []string, reg
return
}
eniIDs := []string{}
var eniIDs []string
for _, task := range Tasks {
eniID := getElasticNetworkInterfaceIDOfECSTask(task)
if eniID != "" {
@@ -394,6 +404,7 @@ func (m *ECSTasksModule) loadTasksData(clusterARN string, taskARNs []string, reg
Cluster: getNameFromARN(clusterARN),
TaskDefinitionName: getNameFromARN(aws.ToString(task.TaskDefinitionArn)),
TaskDefinitionContent: getTaskDefinitionContent(taskDefinition),
ContainerName: getContainerNamesFromECSTask(task),
LaunchType: string(task.LaunchType),
ID: getIDFromECSTask(aws.ToString(task.TaskArn)),
PrivateIP: getPrivateIPv4AddressFromECSTask(task),
@@ -505,8 +516,18 @@ func getIDFromECSTask(arn string) string {
return tokens[2]
}
func getContainerNamesFromECSTask(task types.Task) string {
var names []string
for _, container := range task.Containers {
names = append(names, aws.ToString(container.Name))
}
return strings.Join(names, "|")
}
func getPrivateIPv4AddressFromECSTask(task types.Task) string {
ips := []string{}
var ips []string
for _, attachment := range task.Attachments {
if aws.ToString(attachment.Type) != "ElasticNetworkInterface" || aws.ToString(attachment.Status) != "ATTACHED" {
+8 -5
View File
@@ -23,7 +23,6 @@ func TestECSTasks(t *testing.T) {
outputDirectory: ".",
verbosity: 2,
testModule: ECSTasksModule{
AWSProfile: "default",
AWSRegions: []string{"us-east-1", "us-west-1"},
Caller: sts.GetCallerIdentityOutput{Arn: aws.String("arn:aws:iam::123456789012:user/cloudfox_unit_tests")},
@@ -33,10 +32,11 @@ func TestECSTasks(t *testing.T) {
ECSClient: &sdk.MockedECSClient{},
},
expectedResult: []MappedECSTask{{
Cluster: "MyCluster",
ID: "74de0355a10a4f979ac495c14EXAMPLE",
ExternalIP: "203.0.113.12",
Role: "test123",
Cluster: "MyCluster",
ID: "74de0355a10a4f979ac495c14EXAMPLE",
ContainerName: "web",
ExternalIP: "203.0.113.12",
Role: "test123",
}},
},
}
@@ -48,6 +48,9 @@ func TestECSTasks(t *testing.T) {
if expectedTask.Cluster != subtest.testModule.MappedECSTasks[index].Cluster {
log.Fatal("Cluster name does not match expected value")
}
if expectedTask.ContainerName != subtest.testModule.MappedECSTasks[index].ContainerName {
log.Fatal("Container name does not match expected value")
}
}
})
}
+7 -2
View File
@@ -32,6 +32,7 @@ type EKSModule struct {
AWSProfile string
SkipAdminCheck bool
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
pmapperMod PmapperModule
pmapperError error
iamSimClient IamSimulatorModule
@@ -242,8 +243,12 @@ func (m *EKSModule) EKS(outputDirectory string, verbosity int) {
func (m *EKSModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Cluster) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("eks", r)
if err != nil {
+7 -2
View File
@@ -27,6 +27,7 @@ type ElasticNetworkInterfacesModule struct {
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
MappedENIs []MappedENI
CommandCounter internal.CommandCounter
@@ -233,8 +234,12 @@ func (m *ElasticNetworkInterfacesModule) writeLoot(outputDirectory string) {
func (m *ElasticNetworkInterfacesModule) executeChecks(r string, wg *sync.WaitGroup, dataReceiver chan MappedENI) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("ec2", r)
if err != nil {
+46 -51
View File
@@ -63,6 +63,7 @@ type EndpointsModule struct {
Goroutines int
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
Endpoints []Endpoint
@@ -105,7 +106,7 @@ func (m *EndpointsModule) PrintEndpoints(outputDirectory string, verbosity int)
semaphore := make(chan struct{}, m.Goroutines)
// Create a channel to signal the spinner aka task status goroutine to finish
spinnerDone := make(chan bool)
//fire up the the task status spinner/updated
//fire up the task status spinner/updated
go internal.SpinUntil(m.output.CallingModule, &m.CommandCounter, spinnerDone, "tasks")
//create a channel to receive the objects
@@ -267,8 +268,12 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
// <-semaphore
// }()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("lambda", r)
if err != nil {
@@ -328,7 +333,7 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
wg.Add(1)
go m.getELBListenersPerRegion(r, wg, semaphore, dataReceiver)
}
res, err = servicemap.IsServiceInRegion("apigateway", r)
res, err = servicemap.IsServiceInRegion("api-gateway", r)
if err != nil {
m.modLog.Error(err)
}
@@ -447,7 +452,7 @@ func (m *EndpointsModule) getLambdaFunctionsPerRegion(r string, wg *sync.WaitGro
FunctionDetails, err := sdk.CachedLambdaGetFunctionUrlConfig(m.LambdaClient, aws.ToString(m.Caller.Account), r, name)
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -503,7 +508,7 @@ func (m *EndpointsModule) getEksClustersPerRegion(r string, wg *sync.WaitGroup,
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -576,7 +581,7 @@ func (m *EndpointsModule) getMqBrokersPerRegion(r string, wg *sync.WaitGroup, se
)
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -629,36 +634,27 @@ func (m *EndpointsModule) getOpenSearchPerRegion(r string, wg *sync.WaitGroup, s
for _, domainName := range DomainNames {
name := aws.ToString(domainName.DomainName)
//TODO: convert this to cacehd function
DomainNameDetails, err := m.OpenSearchClient.DescribeDomain(
context.TODO(),
&(opensearch.DescribeDomainInput{
DomainName: &name,
}),
func(o *opensearch.Options) {
o.Region = r
},
)
DomainStatus, err := sdk.CachedOpenSearchDescribeDomain(m.OpenSearchClient, aws.ToString(m.Caller.Account), r, name)
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
return
}
raw_endpoint := DomainNameDetails.DomainStatus.Endpoint
rawEndpoint := DomainStatus.Endpoint
var endpoint string
var kibana_endpoint string
var kibanaEndpoint string
// This exits the function if an opensearch domain exists but there is no endpoint
if raw_endpoint == nil {
if rawEndpoint == nil {
return
} else {
endpoint = fmt.Sprintf("https://%s", aws.ToString(raw_endpoint))
kibana_endpoint = fmt.Sprintf("https://%s/_plugin/kibana/", aws.ToString(raw_endpoint))
endpoint = fmt.Sprintf("https://%s", aws.ToString(rawEndpoint))
kibanaEndpoint = fmt.Sprintf("https://%s/_plugin/kibana/", aws.ToString(rawEndpoint))
}
//fmt.Println(endpoint)
@@ -689,7 +685,7 @@ func (m *EndpointsModule) getOpenSearchPerRegion(r string, wg *sync.WaitGroup, s
AWSService: "OpenSearch",
Region: r,
Name: name,
Endpoint: kibana_endpoint,
Endpoint: kibanaEndpoint,
Port: 443,
Protocol: "https",
Public: public,
@@ -788,7 +784,7 @@ func (m *EndpointsModule) getELBv2ListenersPerRegion(r string, wg *sync.WaitGrou
)
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -943,7 +939,7 @@ func (m *EndpointsModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGrou
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -956,7 +952,7 @@ func (m *EndpointsModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGrou
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -1005,7 +1001,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGateway(r string, api apigatewayType
name := aws.ToString(api.Name)
id := aws.ToString(api.Id)
raw_endpoint := fmt.Sprintf("https://%s.execute-api.%s.amazonaws.com", id, r)
rawEndpoint := fmt.Sprintf("https://%s.execute-api.%s.amazonaws.com", id, r)
var port int32 = 443
protocol := "https"
@@ -1021,7 +1017,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGateway(r string, api apigatewayType
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -1031,11 +1027,10 @@ func (m *EndpointsModule) getEndpointsPerAPIGateway(r string, api apigatewayType
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
}
for _, stage := range GetStages.Item {
@@ -1044,7 +1039,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGateway(r string, api apigatewayType
if len(resource.ResourceMethods) != 0 {
path := aws.ToString(resource.Path)
endpoint := fmt.Sprintf("%s/%s%s", raw_endpoint, stageName, path)
endpoint := fmt.Sprintf("%s/%s%s", rawEndpoint, stageName, path)
endpoints = append(endpoints, Endpoint{
AWSService: awsService,
@@ -1120,7 +1115,7 @@ func (m *EndpointsModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGr
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -1133,7 +1128,7 @@ func (m *EndpointsModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGr
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -1185,7 +1180,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2
var public string
name := aws.ToString(api.Name)
raw_endpoint := aws.ToString(api.ApiEndpoint)
rawEndpoint := aws.ToString(api.ApiEndpoint)
id := aws.ToString(api.ApiId)
var port int32 = 443
protocol := "https"
@@ -1195,7 +1190,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -1213,7 +1208,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -1228,9 +1223,9 @@ func (m *EndpointsModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2
}
var endpoint string
if stage == "" {
endpoint = fmt.Sprintf("%s%s", raw_endpoint, path)
endpoint = fmt.Sprintf("%s%s", rawEndpoint, path)
} else {
endpoint = fmt.Sprintf("%s/%s%s", raw_endpoint, stage, path)
endpoint = fmt.Sprintf("%s/%s%s", rawEndpoint, stage, path)
}
public = "True"
@@ -1267,7 +1262,7 @@ func (m *EndpointsModule) getRdsClustersPerRegion(r string, wg *sync.WaitGroup,
DBInstances, err := sdk.CachedRDSDescribeDBInstances(m.RDSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -1320,12 +1315,12 @@ func (m *EndpointsModule) getRedshiftEndPointsPerRegion(r string, wg *sync.WaitG
awsService := "Redshift"
protocol := "https"
// This for loop exits at the end dependeding on whether the output hits its last page (see pagination control block at the end of the loop).
// This for loop exits at the end depending on whether the output hits its last page (see pagination control block at the end of the loop).
Clusters, err := sdk.CachedRedShiftDescribeClusters(m.RedshiftClient, aws.ToString(m.Caller.Account), r)
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -1453,12 +1448,12 @@ func (m *EndpointsModule) getCloudfrontEndpoints(wg *sync.WaitGroup, semaphore c
m.CommandCounter.Executing++
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
var PaginationControl *string
var awsService string = "Cloudfront"
var protocol string = "https"
var r string = "Global"
var public string = "True"
var awsService = "Cloudfront"
var protocol = "https"
var r = "Global"
var public = "True"
// This for loop exits at the end dependeding on whether the output hits its last page (see pagination control block at the end of the loop).
// This for loop exits at the end depending on whether the output hits its last page (see pagination control block at the end of the loop).
for {
ListDistributions, err := m.CloudfrontClient.ListDistributions(
context.TODO(),
@@ -1468,7 +1463,7 @@ func (m *EndpointsModule) getCloudfrontEndpoints(wg *sync.WaitGroup, semaphore c
)
if err != nil {
if errors.As(err, &oe) {
m.Errors = append(m.Errors, (fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation())))
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s, Service: %s, Operation: %s", r, oe.Service(), oe.Operation()))
}
m.modLog.Error(err.Error())
m.CommandCounter.Error++
@@ -1684,8 +1679,8 @@ func (m *EndpointsModule) getLightsailContainerEndpointsPerRegion(r string, wg *
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
var public string = "True"
var protocol string = "https"
var public = "True"
var protocol = "https"
var port int32 = 443
containerServices, err := sdk.CachedLightsailGetContainerServices(m.LightsailClient, aws.ToString(m.Caller.Account), r)
+51 -44
View File
@@ -43,6 +43,7 @@ type EnvsModule struct {
Goroutines int
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Service Clients
ECSClient *ecs.Client
@@ -62,6 +63,7 @@ type EnvsModule struct {
type EnvironmentVariable struct {
service string
taskDefinition string
name string
region string
environmentVarName string
@@ -166,13 +168,20 @@ func (m *EnvsModule) PrintEnvs(outputDirectory string, verbosity int) {
//Table rows
for _, envVar := range m.EnvironmentVariables {
var finalName string
if envVar.taskDefinition != "" {
finalName = fmt.Sprintf("%s/%s", envVar.name, envVar.taskDefinition)
} else {
finalName = envVar.name
}
if envVar.interesting {
m.output.Body = append(
m.output.Body, []string{
aws.ToString(m.Caller.Account),
envVar.service,
envVar.region,
envVar.name,
finalName,
magenta(envVar.environmentVarName),
magenta(envVar.environmentVarValue),
},
@@ -183,7 +192,7 @@ func (m *EnvsModule) PrintEnvs(outputDirectory string, verbosity int) {
aws.ToString(m.Caller.Account),
envVar.service,
envVar.region,
envVar.name,
finalName,
envVar.environmentVarName,
envVar.environmentVarValue,
},
@@ -272,8 +281,12 @@ func (m *EnvsModule) Receiver(receiver chan EnvironmentVariable, receiverDone ch
func (m *EnvsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan EnvironmentVariable) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, _ := servicemap.IsServiceInRegion("ecs", r)
if res {
@@ -355,7 +368,7 @@ func (m *EnvsModule) getECSEnvironmentVariablesPerRegion(region string, wg *sync
break
}
for _, containerDefinition := range DescribeTaskDefinition.TaskDefinition.ContainerDefinitions {
m.getECSEnvironmentVariablesPerDefinition(containerDefinition, region, dataReceiver)
m.getECSEnvironmentVariablesPerDefinition(*DescribeTaskDefinition.TaskDefinition, containerDefinition, region, dataReceiver)
}
}
}
@@ -394,12 +407,13 @@ func (m *EnvsModule) getTaskDefinitionFamilies(region string) []string {
}
func (m *EnvsModule) getECSEnvironmentVariablesPerDefinition(containerDefinition ecsTypes.ContainerDefinition, region string, dataReceiver chan EnvironmentVariable) {
func (m *EnvsModule) getECSEnvironmentVariablesPerDefinition(taskDefinition ecsTypes.TaskDefinition, containerDefinition ecsTypes.ContainerDefinition, region string, dataReceiver chan EnvironmentVariable) {
if containerDefinition.Environment != nil {
for _, x := range containerDefinition.Environment {
dataReceiver <- EnvironmentVariable{
service: "ECS",
taskDefinition: getNameFromARN(aws.ToString(taskDefinition.TaskDefinitionArn)),
name: aws.ToString(containerDefinition.Name),
region: region,
environmentVarName: aws.ToString(x.Name),
@@ -538,25 +552,22 @@ func (m *EnvsModule) getLightsailEnvironmentVariablesPerRegion(r string, wg *syn
return
}
if err == nil {
if len(ContainerServices) > 0 {
if len(ContainerServices) > 0 {
for _, containerService := range ContainerServices {
for _, container := range containerService.CurrentDeployment.Containers {
for k, v := range container.Environment {
name := aws.ToString(containerService.ContainerServiceName)
dataReceiver <- EnvironmentVariable{
service: awsService,
name: name,
region: r,
environmentVarName: k,
environmentVarValue: v,
}
for _, containerService := range ContainerServices {
for _, container := range containerService.CurrentDeployment.Containers {
for k, v := range container.Environment {
name := aws.ToString(containerService.ContainerServiceName)
dataReceiver <- EnvironmentVariable{
service: awsService,
name: name,
region: r,
environmentVarName: k,
environmentVarValue: v,
}
}
}
}
}
}
@@ -675,18 +686,16 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
m.CommandCounter.Error++
break
}
if err == nil {
if len(DescribeTransformJob.Environment) > 0 {
name := fmt.Sprintf("[Transform Job] %s", aws.ToString(DescribeTransformJob.TransformJobName))
for k, v := range DescribeTransformJob.Environment {
dataReceiver <- EnvironmentVariable{
service: awsService,
name: name,
region: r,
environmentVarName: k,
environmentVarValue: v,
}
if len(DescribeTransformJob.Environment) > 0 {
name := fmt.Sprintf("[Transform Job] %s", aws.ToString(DescribeTransformJob.TransformJobName))
for k, v := range DescribeTransformJob.Environment {
dataReceiver <- EnvironmentVariable{
service: awsService,
name: name,
region: r,
environmentVarName: k,
environmentVarValue: v,
}
}
}
@@ -738,20 +747,18 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
m.CommandCounter.Error++
break
}
if err == nil {
if len(DescribeTrainingJob.Environment) > 0 {
name := fmt.Sprintf("[Training Job] %s", aws.ToString(DescribeTrainingJob.TrainingJobName))
for k, v := range DescribeTrainingJob.Environment {
dataReceiver <- EnvironmentVariable{
service: awsService,
name: name,
region: r,
environmentVarName: k,
environmentVarValue: v,
}
if len(DescribeTrainingJob.Environment) > 0 {
name := fmt.Sprintf("[Training Job] %s", aws.ToString(DescribeTrainingJob.TrainingJobName))
for k, v := range DescribeTrainingJob.Environment {
dataReceiver <- EnvironmentVariable{
service: awsService,
name: name,
region: r,
environmentVarName: k,
environmentVarValue: v,
}
}
}
}
+7 -2
View File
@@ -36,6 +36,7 @@ type FilesystemsModule struct {
Goroutines int
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
Filesystems []FilesystemObject
@@ -218,8 +219,12 @@ func (m *FilesystemsModule) Receiver(receiver chan FilesystemObject, receiverDon
func (m *FilesystemsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan FilesystemObject) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("efs", r)
if err != nil {
+1 -1
View File
@@ -331,7 +331,7 @@ func (m *GraphCommand) collectRoleDataForGraph() []models.Role {
TrustedPrincipals = append(TrustedPrincipals, models.TrustedPrincipal{
TrustedPrincipal: principal,
ExternalID: statement.Condition.StringEquals.StsExternalID,
ExternalID: strings.Join(statement.Condition.StringEquals.StsExternalID, "\n"),
VendorName: vendorName,
//IsAdmin: false,
//CanPrivEscToAdmin: false,
+34 -29
View File
@@ -33,8 +33,9 @@ type IamSimulatorModule struct {
WrapTable bool
// Main module data
SimulatorResults []SimulatorResult
CommandCounter internal.CommandCounter
SimulatorResults []SimulatorResult
CommandCounter internal.CommandCounter
IamSimulatorAdminCheckOnly bool
// Used to store output data for pretty printing
output internal.OutputData2
modLog *logrus.Entry
@@ -47,26 +48,23 @@ type SimulatorResult struct {
Decision string
}
var (
defaultActionNames = []string{
"sts:AssumeRole",
"iam:PassRole",
"secretsmanager:GetSecretValue",
"ssm:GetParameter",
"s3:ListBucket",
"s3:GetObject",
"ssm:SendCommand",
"ssm:StartSession",
"ecr:BatchGetImage",
"ecr:GetAuthorizationToken",
"eks:UpdateClusterConfig",
"lambda:ListFunctions",
"ec2:DescribeInstanceAttributeInput",
"sns:Subscribe",
"sqs:SendMessage",
}
TxtLogger = internal.TxtLogger()
)
var defaultActionNames = []string{
"sts:AssumeRole",
"iam:PassRole",
"secretsmanager:GetSecretValue",
"ssm:GetParameter",
"s3:ListBucket",
"s3:GetObject",
"ssm:SendCommand",
"ssm:StartSession",
"ecr:BatchGetImage",
"ecr:GetAuthorizationToken",
"eks:UpdateClusterConfig",
"lambda:ListFunctions",
"ec2:DescribeInstanceAttributeInput",
"sns:Subscribe",
"sqs:SendMessage",
}
func (m *IamSimulatorModule) PrintIamSimulator(principal string, action string, resource string, outputDirectory string, verbosity int) {
@@ -104,6 +102,11 @@ func (m *IamSimulatorModule) PrintIamSimulator(principal string, action string,
go m.Receiver(dataReceiver, receiverDone)
if m.IamSimulatorAdminCheckOnly {
// set defaultActionNames to an empty slice
defaultActionNames = []string{}
}
// This double if/else section is here to handle the cases where --principal or --action (or both) are specified.
if principal != "" {
if action != "" {
@@ -354,7 +357,9 @@ func (m *IamSimulatorModule) getIAMUsers(wg *sync.WaitGroup, actions []string, r
Decision: "",
}
} else {
m.getPolicySimulatorResult(principal, actions, resource, dataReceiver)
if !m.IamSimulatorAdminCheckOnly {
m.getPolicySimulatorResult(principal, actions, resource, dataReceiver)
}
}
}
@@ -394,7 +399,9 @@ func (m *IamSimulatorModule) getIAMRoles(wg *sync.WaitGroup, actions []string, r
Decision: "",
}
} else {
m.getPolicySimulatorResult(principal, actions, resource, dataReceiver)
if !m.IamSimulatorAdminCheckOnly {
m.getPolicySimulatorResult(principal, actions, resource, dataReceiver)
}
}
}
@@ -443,7 +450,7 @@ func (m *IamSimulatorModule) isPrincipalAnAdmin(principal *string) bool {
"iam:PutRolePolicy",
"iam:AttachRolePolicy",
"secretsmanager:GetSecretValue",
"ssm:GetDocument",
"ssm:GetParameters",
}
for {
SimulatePrincipalPolicy, err := m.IAMClient.SimulatePrincipalPolicy(
@@ -456,11 +463,9 @@ func (m *IamSimulatorModule) isPrincipalAnAdmin(principal *string) bool {
},
)
if err != nil {
//m.modLog.Error(err.Error())
TxtLogger.Println(err.Error())
m.modLog.Error(err)
m.CommandCounter.Error++
//m.modLog.Error(fmt.Sprintf("Failed admin check on %s\n\n", aws.ToString(principal)))
TxtLogger.Printf("Failed admin check on %s\n\n", aws.ToString(principal))
m.modLog.Errorf("Failed admin check on %s", aws.ToString(principal))
return false
}
+15 -5
View File
@@ -4,7 +4,6 @@ import (
"context"
"encoding/base64"
"fmt"
"log"
"os"
"path/filepath"
"strconv"
@@ -36,6 +35,7 @@ type InstancesModule struct {
UserDataAttributesOnly bool
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
InstanceProfileToRolesMap map[string][]iamTypes.Role
SkipAdminCheck bool
pmapperMod PmapperModule
@@ -435,13 +435,21 @@ func (m *InstancesModule) writeLoot(outputDirectory string, verbosity int) {
func (m *InstancesModule) executeChecks(instancesToSearch []string, r string, wg *sync.WaitGroup, dataReceiver chan MappedInstance) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
m.modLog.Warn("ServiceMap is nil, creating new instance (this should not happen)")
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("ec2", r)
if err != nil {
m.modLog.Error(err)
m.modLog.Errorf("Error checking if EC2 is available in region %s: %v", r, err)
m.CommandCounter.Error++
return
}
m.modLog.Debugf("ServiceMap check for EC2 in region %s: result=%v, error=%v", r, res, err)
if res {
m.CommandCounter.Total++
m.CommandCounter.Pending--
@@ -449,6 +457,8 @@ func (m *InstancesModule) executeChecks(instancesToSearch []string, r string, wg
m.getDescribeInstances(instancesToSearch, r, dataReceiver)
m.CommandCounter.Executing--
m.CommandCounter.Complete++
} else {
m.modLog.Infof("Skipping region %s: EC2 not available or check failed", r)
}
}
@@ -537,7 +547,7 @@ func (m *InstancesModule) loadInstanceData(instance types.Instance, region strin
// Describe the IAM instance profile
profileOutput, err := sdk.CachedIamGetInstanceProfile(m.IAMClient, aws.ToString(m.Caller.Account), profileName)
if err != nil {
log.Printf("failed to get instance profile for %s, %v", profileArn, err)
m.modLog.Errorf("failed to get instance profile for %s, %v", profileArn, err)
}
for _, role := range profileOutput.Roles {
+9 -13
View File
@@ -90,6 +90,7 @@ type Inventory2Module struct {
Goroutines int
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
RegionResourceCount int
@@ -423,8 +424,12 @@ func (m *Inventory2Module) Receiver(receiver chan GlobalResourceCount2, receiver
func (m *Inventory2Module) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan GlobalResourceCount2) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
// AppRunner is not supported in the aws service region catalog so we have to run it in all regions
@@ -432,7 +437,7 @@ func (m *Inventory2Module) executeChecks(r string, wg *sync.WaitGroup, semaphore
wg.Add(1)
go m.getAppRunnerServicesPerRegion(r, wg, semaphore)
res, err := servicemap.IsServiceInRegion("apigateway", r)
res, err := servicemap.IsServiceInRegion("api-gateway", r)
if err != nil {
m.modLog.Error(err)
}
@@ -791,16 +796,7 @@ func (m *Inventory2Module) executeChecks(r string, wg *sync.WaitGroup, semaphore
}
func (m *Inventory2Module) PrintTotalResources(AWSOutputType string) {
var totalResources int
for _, r := range m.AWSRegions {
if m.totalRegionCounts[r] != 0 {
totalResources = totalResources + m.totalRegionCounts[r]
}
}
for i := range m.GlobalResourceCounts {
totalResources = totalResources + m.GlobalResourceCounts[i].count
}
totalResources := len(m.resources)
fmt.Printf("[%s][%s] %d resources found in the services we looked at. This is NOT the total number of resources in the account.\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), totalResources)
}
+7 -2
View File
@@ -35,6 +35,7 @@ type LambdasModule struct {
AWSProfile string
SkipAdminCheck bool
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
pmapperMod PmapperModule
pmapperError error
PmapperDataBasePath string
@@ -228,8 +229,12 @@ func (m *LambdasModule) PrintLambdas(outputDirectory string, verbosity int) {
func (m *LambdasModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Lambda) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("lambda", r)
if err != nil {
+7 -2
View File
@@ -74,6 +74,7 @@ type NetworkPortsModule struct {
AWSProfile string
WrapTable bool
Verbosity int
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
IPv4_Private []NetworkService
@@ -273,8 +274,12 @@ func (m *NetworkPortsModule) PrintNetworkPorts(outputDirectory string) {
func (m *NetworkPortsModule) executeChecks(r string, wg *sync.WaitGroup, dataReceiver chan NetworkServices) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("ec2", r)
+7 -2
View File
@@ -31,6 +31,7 @@ type OutboundAssumedRolesModule struct {
Goroutines int
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
OutboundAssumeRoleEntries []OutboundAssumeRoleEntry
@@ -294,8 +295,12 @@ func (m *OutboundAssumedRolesModule) Receiver(receiver chan OutboundAssumeRoleEn
func (m *OutboundAssumedRolesModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan OutboundAssumeRoleEntry) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("cloudtrail", r)
if err != nil {
+1 -1
View File
@@ -196,7 +196,7 @@ func (m *IamPermissionsModule) PrintIamPermissions(outputDirectory string, verbo
func (m *IamPermissionsModule) GetGAAD() {
GAAD, err := sdk.CachedIAMGetAccountAuthorizationDetails(m.IAMClient, aws.ToString(m.Caller.Account))
if err != nil {
TxtLogger.Error(err.Error())
m.modLog.Error(err)
m.CommandCounter.Error++
return
}
+41
View File
@@ -26,6 +26,12 @@ type IamPrincipalsModule struct {
AWSProfile string
WrapTable bool
SkipAdminCheck bool
iamSimClient IamSimulatorModule
pmapperMod PmapperModule
pmapperError error
PmapperDataBasePath string
// Main module data
Users []User
Roles []Role
@@ -43,6 +49,8 @@ type User struct {
Name string
AttachedPolicies []string
InlinePolicies []string
Admin string
CanPrivEsc string
}
type Group struct {
@@ -62,6 +70,8 @@ type Role struct {
Name string
AttachedPolicies []string
InlinePolicies []string
Admin string
CanPrivEsc string
}
func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosity int) {
@@ -69,6 +79,7 @@ func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosi
m.output.Verbosity = verbosity
m.output.Directory = outputDirectory
m.output.CallingModule = "principals"
localAdminMap := make(map[string]bool)
m.modLog = internal.TxtLog.WithFields(logrus.Fields{
"module": m.output.CallingModule,
})
@@ -78,6 +89,9 @@ func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosi
fmt.Printf("[%s][%s] Enumerating IAM Users and Roles for account %s.\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), aws.ToString(m.Caller.Account))
m.pmapperMod, m.pmapperError = InitPmapperGraph(m.Caller, m.AWSProfile, m.Goroutines, m.PmapperDataBasePath)
m.iamSimClient = InitIamCommandClient(m.IAMClient, m.Caller, m.AWSProfile, m.Goroutines)
// wg := new(sync.WaitGroup)
// done := make(chan bool)
@@ -101,6 +115,8 @@ func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosi
"Arn",
"AttachedPolicies",
"InlinePolicies",
"IsAdminRole?",
"CanPrivEscToAdmin?",
}
// If the user specified table columns, use those.
@@ -122,6 +138,8 @@ func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosi
"Arn",
//"AttachedPolicies",
//"InlinePolicies",
"IsAdminRole?",
"CanPrivEscToAdmin?",
}
// Otherwise, use the default columns.
@@ -132,11 +150,25 @@ func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosi
"Arn",
// "AttachedPolicies",
// "InlinePolicies",
"IsAdminRole?",
"CanPrivEscToAdmin?",
}
}
// Remove the pmapper row if there is no pmapper data
if m.pmapperError != nil {
sharedLogger.Errorf("%s - %s - No pmapper data found for this account. Skipping the pmapper column in the output table.", m.output.CallingModule, m.AWSProfile)
tableCols = removeStringFromSlice(tableCols, "CanPrivEscToAdmin?")
}
//Table rows
for i := range m.Users {
if m.pmapperError == nil {
m.Users[i].Admin, m.Users[i].CanPrivEsc = GetPmapperResults(m.SkipAdminCheck, m.pmapperMod, &m.Users[i].Arn)
} else {
m.Users[i].Admin, m.Users[i].CanPrivEsc = GetIamSimResult(m.SkipAdminCheck, &m.Users[i].Arn, m.iamSimClient, localAdminMap)
}
m.output.Body = append(
m.output.Body,
[]string{
@@ -146,12 +178,19 @@ func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosi
m.Users[i].Arn,
strings.Join(m.Users[i].AttachedPolicies, " , "),
strings.Join(m.Users[i].InlinePolicies, " , "),
m.Users[i].Admin,
m.Users[i].CanPrivEsc,
},
)
}
for i := range m.Roles {
if m.pmapperError == nil {
m.Roles[i].Admin, m.Roles[i].CanPrivEsc = GetPmapperResults(m.SkipAdminCheck, m.pmapperMod, &m.Roles[i].Arn)
} else {
m.Roles[i].Admin, m.Roles[i].CanPrivEsc = GetIamSimResult(m.SkipAdminCheck, &m.Roles[i].Arn, m.iamSimClient, localAdminMap)
}
m.output.Body = append(
m.output.Body,
[]string{
@@ -161,6 +200,8 @@ func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosi
m.Roles[i].Arn,
strings.Join(m.Roles[i].AttachedPolicies, " , "),
strings.Join(m.Roles[i].InlinePolicies, " , "),
m.Roles[i].Admin,
m.Roles[i].CanPrivEsc,
},
)
+7 -2
View File
@@ -29,6 +29,7 @@ type RAMModule struct {
Goroutines int
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
Resources []Resource
@@ -178,8 +179,12 @@ func (m *RAMModule) PrintRAM(outputDirectory string, verbosity int) {
func (m *RAMModule) executeChecks(r string, wg *sync.WaitGroup, dataReceiver chan Resource) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("ram", r)
if err != nil {
+390 -12
View File
@@ -19,6 +19,11 @@ import (
)
type ResourceTrustsModule struct {
KMSClient *sdk.KMSClientInterface
APIGatewayClient *sdk.APIGatewayClientInterface
EC2Client *sdk.AWSEC2ClientInterface
OpenSearchClient *sdk.OpenSearchClientInterface
// General configuration data
Caller sts.GetCallerIdentityOutput
AWSRegions []string
@@ -31,6 +36,7 @@ type ResourceTrustsModule struct {
AWSProfileProvided string
AWSProfileStub string
CloudFoxVersion string
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
Resources2 []Resource2
CommandCounter internal.CommandCounter
@@ -55,7 +61,7 @@ type Resource2 struct {
HasConditions string
}
func (m *ResourceTrustsModule) PrintResources(outputDirectory string, verbosity int) {
func (m *ResourceTrustsModule) PrintResources(outputDirectory string, verbosity int, includeKms bool) {
// These struct values are used by the output module
m.output.Verbosity = verbosity
m.output.Directory = outputDirectory
@@ -72,13 +78,21 @@ func (m *ResourceTrustsModule) PrintResources(outputDirectory string, verbosity
m.output.FilePath = filepath.Join(outputDirectory, "cloudfox-output", "aws", fmt.Sprintf("%s-%s", m.AWSProfileProvided, aws.ToString(m.Caller.Account)))
fmt.Printf("[%s][%s] Enumerating Resources with resource policies for account %s.\n", cyan(m.output.CallingModule), cyan(m.AWSProfileStub), aws.ToString(m.Caller.Account))
fmt.Printf("[%s][%s] Supported Services: CodeBuild, ECR, EFS, Glue, Lambda, SecretsManager, S3, SNS, SQS\n", cyan(m.output.CallingModule), cyan(m.AWSProfileStub))
// if kms feature flag is enabled include kms in the supported services
if includeKms {
fmt.Printf("[%s][%s] Supported Services: APIGateway, CodeBuild, ECR, EFS, Glue, KMS, Lambda, Opensearch, SecretsManager, S3, SNS, SQS, VpcEndpoint\n",
cyan(m.output.CallingModule), cyan(m.AWSProfileStub))
} else {
fmt.Printf("[%s][%s] Supported Services: APIGateway, CodeBuild, ECR, EFS, Glue, Lambda, Opensearch, SecretsManager, S3, SNS, "+
"SQS, VpcEndpoint (KMS requires --include-kms feature flag)\n",
cyan(m.output.CallingModule), cyan(m.AWSProfileStub))
}
wg := new(sync.WaitGroup)
semaphore := make(chan struct{}, m.Goroutines)
// Create a channel to signal the spinner aka task status goroutine to finish
spinnerDone := make(chan bool)
//fire up the the task status spinner/updated
//fire up the task status spinner/updated
go internal.SpinUntil(m.output.CallingModule, &m.CommandCounter, spinnerDone, "tasks")
//create a channel to receive the objects
@@ -91,7 +105,7 @@ func (m *ResourceTrustsModule) PrintResources(outputDirectory string, verbosity
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
go m.executeChecks(region, wg, semaphore, dataReceiver)
go m.executeChecks(region, wg, semaphore, dataReceiver, includeKms)
}
wg.Add(1)
@@ -186,14 +200,17 @@ func (m *ResourceTrustsModule) PrintResources(outputDirectory string, verbosity
fmt.Printf("[%s][%s] No resource policies found, skipping the creation of an output file.\n", cyan(m.output.CallingModule), cyan(m.AWSProfileStub))
}
fmt.Printf("[%s][%s] For context and next steps: https://github.com/BishopFox/cloudfox/wiki/AWS-Commands#%s\n", cyan(m.output.CallingModule), cyan(m.AWSProfileStub), m.output.CallingModule)
}
func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2, includeKms bool) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("sns", r)
if err != nil {
@@ -234,6 +251,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
wg.Add(1)
m.getCodeBuildResourcePoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
res, err = servicemap.IsServiceInRegion("lambda", r)
if err != nil {
m.modLog.Error(err)
@@ -243,6 +261,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
wg.Add(1)
m.getLambdaPolicyPerRegion(r, wg, semaphore, dataReceiver)
}
res, err = servicemap.IsServiceInRegion("efs", r)
if err != nil {
m.modLog.Error(err)
@@ -252,6 +271,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
wg.Add(1)
m.getEFSfilesystemPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
res, err = servicemap.IsServiceInRegion("secretsmanager", r)
if err != nil {
m.modLog.Error(err)
@@ -261,6 +281,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
wg.Add(1)
m.getSecretsManagerSecretsPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
res, err = servicemap.IsServiceInRegion("glue", r)
if err != nil {
m.modLog.Error(err)
@@ -271,6 +292,53 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.getGlueResourcePoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
if includeKms && m.KMSClient != nil {
res, err = servicemap.IsServiceInRegion("kms", r)
if err != nil {
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
wg.Add(1)
m.getKMSPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
}
if m.APIGatewayClient != nil {
res, err = servicemap.IsServiceInRegion("api-gateway", r)
if err != nil {
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
wg.Add(1)
m.getAPIGatewayPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
}
if m.EC2Client != nil {
res, err = servicemap.IsServiceInRegion("ec2", r)
if err != nil {
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
wg.Add(1)
m.getVPCEndpointPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
}
if m.OpenSearchClient != nil {
res, err = servicemap.IsServiceInRegion("es", r)
if err != nil {
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
wg.Add(1)
m.getOpenSearchPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
}
}
func (m *ResourceTrustsModule) Receiver(receiver chan Resource2, receiverDone chan bool) {
@@ -306,7 +374,7 @@ func (m *ResourceTrustsModule) getSNSTopicsPerRegion(r string, wg *sync.WaitGrou
for _, t := range ListTopics {
var statementSummaryInEnglish string
var isInteresting string = "No"
var isInteresting = "No"
topic, err := cloudFoxSNSClient.getTopicWithAttributes(aws.ToString(t.TopicArn), r)
if err != nil {
m.modLog.Error(err.Error())
@@ -316,9 +384,10 @@ func (m *ResourceTrustsModule) getSNSTopicsPerRegion(r string, wg *sync.WaitGrou
parsedArn, err := arn.Parse(aws.ToString(t.TopicArn))
if err != nil {
topic.Name = aws.ToString(t.TopicArn)
} else {
topic.Name = parsedArn.Resource
topic.Region = parsedArn.Region
}
topic.Name = parsedArn.Resource
topic.Region = parsedArn.Region
// check if topic is public or not
if topic.Policy.IsPublic() {
@@ -846,6 +915,315 @@ func (m *ResourceTrustsModule) getSecretsManagerSecretsPoliciesPerRegion(r strin
}
}
// getKMSPoliciesPerRegion retrieves the resource policies for all KMS keys in a specified region.
// It sends the resulting Resource2 objects to the dataReceiver channel.
// It uses a semaphore to limit the number of concurrent requests and a WaitGroup to wait for all requests to complete.
// It takes the region to search in, the WaitGroup to use, the semaphore to use, and the dataReceiver channel to send results to.
func (m *ResourceTrustsModule) getKMSPoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
wg.Done()
}()
semaphore <- struct{}{}
defer func() { <-semaphore }()
listKeys, err := sdk.CachedKMSListKeys(*m.KMSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
sharedLogger.Error(err.Error())
return
}
for _, key := range listKeys {
var isPublic string
var statementSummaryInEnglish string
var isInteresting = "No"
keyPolicy, err := sdk.CachedKMSGetKeyPolicy(*m.KMSClient, aws.ToString(m.Caller.Account), r, aws.ToString(key.KeyId))
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
continue
}
if keyPolicy.IsPublic() {
isPublic = magenta("Yes")
isInteresting = magenta("Yes")
} else {
isPublic = "No"
}
if !keyPolicy.IsEmpty() {
for i, statement := range keyPolicy.Statement {
prefix := ""
if len(keyPolicy.Statement) > 1 {
prefix = fmt.Sprintf("Statement %d says: ", i)
statementSummaryInEnglish = prefix + statement.GetStatementSummaryInEnglish(*m.Caller.Account) + "\n"
} else {
statementSummaryInEnglish = statement.GetStatementSummaryInEnglish(*m.Caller.Account)
}
statementSummaryInEnglish = strings.TrimSuffix(statementSummaryInEnglish, "\n")
if isResourcePolicyInteresting(statementSummaryInEnglish) {
//magenta(statementSummaryInEnglish)
isInteresting = magenta("Yes")
}
dataReceiver <- Resource2{
AccountID: aws.ToString(m.Caller.Account),
ARN: aws.ToString(key.KeyArn),
ResourcePolicySummary: statementSummaryInEnglish,
Public: isPublic,
Name: aws.ToString(key.KeyId),
Region: r,
Interesting: isInteresting,
}
}
}
}
}
func (m *ResourceTrustsModule) getAPIGatewayPoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
wg.Done()
}()
semaphore <- struct{}{}
defer func() { <-semaphore }()
restAPIs, err := sdk.CachedApiGatewayGetRestAPIs(*m.APIGatewayClient, aws.ToString(m.Caller.Account), r)
if err != nil {
sharedLogger.Error(err.Error())
return
}
for _, restAPI := range restAPIs {
if sdk.IsPublicApiGateway(&restAPI) {
continue
}
var isPublic = "No"
var statementSummaryInEnglish string
var isInteresting = "No"
if restAPI.Policy != nil && *restAPI.Policy != "" {
// remove backslashes from the policy JSON
policyJson := strings.ReplaceAll(aws.ToString(restAPI.Policy), `\"`, `"`)
restAPIPolicy, err := policy.ParseJSONPolicy([]byte(policyJson))
if err != nil {
sharedLogger.Error(fmt.Errorf("parsing policy (%s) as JSON: %s", aws.ToString(restAPI.Name), err))
m.CommandCounter.Error++
continue
}
if !restAPIPolicy.IsEmpty() {
for i, statement := range restAPIPolicy.Statement {
prefix := ""
if len(restAPIPolicy.Statement) > 1 {
prefix = fmt.Sprintf("Statement %d says: ", i)
statementSummaryInEnglish = prefix + statement.GetStatementSummaryInEnglish(*m.Caller.Account) + "\n"
} else {
statementSummaryInEnglish = statement.GetStatementSummaryInEnglish(*m.Caller.Account)
}
statementSummaryInEnglish = strings.TrimSuffix(statementSummaryInEnglish, "\n")
if isResourcePolicyInteresting(statementSummaryInEnglish) {
//magenta(statementSummaryInEnglish)
isInteresting = magenta("Yes")
}
dataReceiver <- Resource2{
AccountID: aws.ToString(m.Caller.Account),
ARN: fmt.Sprintf("arn:aws:execute-api:%s:%s:%s/*", r, *m.Caller.Account, *restAPI.Id),
ResourcePolicySummary: statementSummaryInEnglish,
Public: isPublic,
Name: aws.ToString(restAPI.Name),
Region: r,
Interesting: isInteresting,
}
}
}
} else {
dataReceiver <- Resource2{
AccountID: aws.ToString(m.Caller.Account),
ARN: fmt.Sprintf("arn:aws:execute-api:%s:%s:%s/*", r, *m.Caller.Account, *restAPI.Id),
ResourcePolicySummary: statementSummaryInEnglish,
Public: isPublic,
Name: aws.ToString(restAPI.Name),
Region: r,
Interesting: isInteresting,
}
}
}
}
func (m *ResourceTrustsModule) getVPCEndpointPoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
wg.Done()
}()
semaphore <- struct{}{}
defer func() { <-semaphore }()
vpcEndpoints, err := sdk.CachedEC2DescribeVpcEndpoints(*m.EC2Client, aws.ToString(m.Caller.Account), r)
if err != nil {
sharedLogger.Error(err.Error())
return
}
for _, vpcEndpoint := range vpcEndpoints {
var isPublic = "No"
var statementSummaryInEnglish string
var isInteresting = "No"
if vpcEndpoint.PolicyDocument != nil && *vpcEndpoint.PolicyDocument != "" {
vpcEndpointPolicyJson := aws.ToString(vpcEndpoint.PolicyDocument)
vpcEndpointPolicy, err := policy.ParseJSONPolicy([]byte(vpcEndpointPolicyJson))
if err != nil {
sharedLogger.Error(fmt.Errorf("parsing policy (%s) as JSON: %s", aws.ToString(vpcEndpoint.VpcEndpointId), err))
m.CommandCounter.Error++
continue
}
if !vpcEndpointPolicy.IsEmpty() {
for i, statement := range vpcEndpointPolicy.Statement {
prefix := ""
if len(vpcEndpointPolicy.Statement) > 1 {
prefix = fmt.Sprintf("Statement %d says: ", i)
statementSummaryInEnglish = prefix + statement.GetStatementSummaryInEnglish(*m.Caller.Account) + "\n"
} else {
statementSummaryInEnglish = statement.GetStatementSummaryInEnglish(*m.Caller.Account)
}
statementSummaryInEnglish = strings.TrimSuffix(statementSummaryInEnglish, "\n")
if isResourcePolicyInteresting(statementSummaryInEnglish) {
//magenta(statementSummaryInEnglish)
isInteresting = magenta("Yes")
}
dataReceiver <- Resource2{
AccountID: aws.ToString(m.Caller.Account),
ARN: fmt.Sprintf("arn:aws:ec2:%s:%s:vpc-endpoint/%s", r, aws.ToString(m.Caller.Account), aws.ToString(vpcEndpoint.VpcEndpointId)),
ResourcePolicySummary: statementSummaryInEnglish,
Public: isPublic,
Name: aws.ToString(vpcEndpoint.VpcEndpointId),
Region: r,
Interesting: isInteresting,
}
}
}
} else {
dataReceiver <- Resource2{
AccountID: aws.ToString(m.Caller.Account),
ARN: fmt.Sprintf("arn:aws:ec2:%s:%s:vpc-endpoint/%s", r, aws.ToString(m.Caller.Account), aws.ToString(vpcEndpoint.VpcEndpointId)),
ResourcePolicySummary: statementSummaryInEnglish,
Public: isPublic,
Name: aws.ToString(vpcEndpoint.VpcEndpointId),
Region: r,
Interesting: isInteresting,
}
}
}
}
func (m *ResourceTrustsModule) getOpenSearchPoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
wg.Done()
}()
semaphore <- struct{}{}
defer func() { <-semaphore }()
openSearchDomains, err := sdk.CachedOpenSearchListDomainNames(*m.OpenSearchClient, aws.ToString(m.Caller.Account), r)
if err != nil {
sharedLogger.Error(err.Error())
return
}
for _, openSearchDomain := range openSearchDomains {
var isPublic string
var statementSummaryInEnglish string
var isInteresting = "No"
openSearchDomainConfig, err := sdk.CachedOpenSearchDescribeDomainConfig(*m.OpenSearchClient, aws.ToString(m.Caller.Account), r, aws.ToString(openSearchDomain.DomainName))
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
continue
}
if aws.ToBool(openSearchDomainConfig.AdvancedSecurityOptions.Options.Enabled) {
isPublic = "No"
} else {
isPublic = magenta("Yes")
isInteresting = magenta("Yes")
}
openSearchDomainStatus, err := sdk.CachedOpenSearchDescribeDomain(*m.OpenSearchClient, aws.ToString(m.Caller.Account), r, aws.ToString(openSearchDomain.DomainName))
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
continue
}
if openSearchDomainStatus.AccessPolicies != nil && *openSearchDomainStatus.AccessPolicies != "" {
// remove backslashes from the policy JSON
policyJson := strings.ReplaceAll(aws.ToString(openSearchDomainStatus.AccessPolicies), `\"`, `"`)
openSearchDomainPolicy, err := policy.ParseJSONPolicy([]byte(policyJson))
if err != nil {
sharedLogger.Error(fmt.Errorf("parsing policy (%s) as JSON: %s", aws.ToString(openSearchDomainStatus.ARN), err))
m.CommandCounter.Error++
continue
}
if !openSearchDomainPolicy.IsEmpty() {
for i, statement := range openSearchDomainPolicy.Statement {
prefix := ""
if len(openSearchDomainPolicy.Statement) > 1 {
prefix = fmt.Sprintf("Statement %d says: ", i)
statementSummaryInEnglish = prefix + statement.GetStatementSummaryInEnglish(*m.Caller.Account) + "\n"
} else {
statementSummaryInEnglish = statement.GetStatementSummaryInEnglish(*m.Caller.Account)
}
statementSummaryInEnglish = strings.TrimSuffix(statementSummaryInEnglish, "\n")
if isResourcePolicyInteresting(statementSummaryInEnglish) {
//magenta(statementSummaryInEnglish)
isInteresting = magenta("Yes")
}
dataReceiver <- Resource2{
AccountID: aws.ToString(m.Caller.Account),
ARN: aws.ToString(openSearchDomainStatus.ARN),
ResourcePolicySummary: statementSummaryInEnglish,
Public: isPublic,
Name: aws.ToString(openSearchDomain.DomainName),
Region: r,
Interesting: isInteresting,
}
}
}
} else {
dataReceiver <- Resource2{
AccountID: aws.ToString(m.Caller.Account),
ARN: aws.ToString(openSearchDomainStatus.ARN),
ResourcePolicySummary: statementSummaryInEnglish,
Public: isPublic,
Name: aws.ToString(openSearchDomain.DomainName),
Region: r,
Interesting: isInteresting,
}
}
}
}
func (m *ResourceTrustsModule) getGlueResourcePoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
@@ -905,7 +1283,7 @@ func (m *ResourceTrustsModule) getGlueResourcePoliciesPerRegion(r string, wg *sy
}
func isResourcePolicyInteresting(statementSummaryInEnglish string) bool {
// check if the statement has any of the following items, but make sure the check is case insensitive
// check if the statement has any of the following items, but make sure the check is case-insensitive
// if it does, then return true
// if it doesn't, then return false
+219
View File
@@ -2,6 +2,10 @@ package aws
import (
"testing"
"github.com/BishopFox/cloudfox/aws/sdk"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/sts"
)
func TestIsResourcePolicyInteresting(t *testing.T) {
@@ -41,3 +45,218 @@ func TestIsResourcePolicyInteresting(t *testing.T) {
})
}
}
func TestKMSResourceTrusts(t *testing.T) {
mockedKMSClient := &sdk.MockedKMSClient{}
var kmsClient sdk.KMSClientInterface = mockedKMSClient
testCases := []struct {
outputDirectory string
verbosity int
testModule ResourceTrustsModule
expectedResult []Resource2
}{
{
outputDirectory: ".",
verbosity: 2,
testModule: ResourceTrustsModule{
KMSClient: &kmsClient,
APIGatewayClient: nil,
EC2Client: nil,
AWSRegions: []string{"us-west-2"},
Caller: sts.GetCallerIdentityOutput{
Account: aws.String("123456789012"),
Arn: aws.String("arn:aws:iam::123456789012:user/cloudfox_unit_tests"),
},
Goroutines: 30,
},
expectedResult: []Resource2{
{
Name: "key1",
ARN: "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
},
},
},
}
for _, tc := range testCases {
tc.testModule.PrintResources(tc.outputDirectory, tc.verbosity, true)
for index, expectedResource2 := range tc.expectedResult {
if expectedResource2.Name != tc.testModule.Resources2[index].Name {
t.Fatal("Resource name does not match expected value")
}
if expectedResource2.ARN != tc.testModule.Resources2[index].ARN {
t.Fatal("Resource ARN does not match expected value")
}
}
}
}
func TestAPIGatewayResourceTrusts(t *testing.T) {
mockedAPIGatewayClient := &sdk.MockedAWSAPIGatewayClient{}
var apiGatewayClient sdk.APIGatewayClientInterface = mockedAPIGatewayClient
testCases := []struct {
outputDirectory string
verbosity int
testModule ResourceTrustsModule
expectedResult []Resource2
}{
{
outputDirectory: ".",
verbosity: 2,
testModule: ResourceTrustsModule{
KMSClient: nil,
APIGatewayClient: &apiGatewayClient,
EC2Client: nil,
AWSRegions: []string{"us-west-2"},
Caller: sts.GetCallerIdentityOutput{
Account: aws.String("123456789012"),
Arn: aws.String("arn:aws:iam::123456789012:user/cloudfox_unit_tests"),
},
Goroutines: 30,
},
expectedResult: []Resource2{
{
Name: "api1",
ARN: "arn:aws:execute-api:us-west-2:123456789012:abcdefg/*",
Public: "No",
Interesting: "Yes",
},
},
},
}
for _, tc := range testCases {
tc.testModule.PrintResources(tc.outputDirectory, tc.verbosity, false)
for index, expectedResource2 := range tc.expectedResult {
if expectedResource2.Name != tc.testModule.Resources2[index].Name {
t.Fatal("Resource name does not match expected value")
}
if expectedResource2.ARN != tc.testModule.Resources2[index].ARN {
t.Fatal("Resource ARN does not match expected value")
}
if expectedResource2.Public != tc.testModule.Resources2[index].Public {
t.Fatal("Resource Public does not match expected value")
}
if expectedResource2.Interesting != tc.testModule.Resources2[index].Interesting {
t.Fatal("Resource Interesting does not match expected value")
}
}
}
}
func TestVpcEndpointResourceTrusts(t *testing.T) {
mockedEC2Client := &sdk.MockedEC2Client2{}
var ec2Client sdk.AWSEC2ClientInterface = mockedEC2Client
testCases := []struct {
outputDirectory string
verbosity int
testModule ResourceTrustsModule
expectedResult []Resource2
}{
{
outputDirectory: ".",
verbosity: 2,
testModule: ResourceTrustsModule{
KMSClient: nil,
APIGatewayClient: nil,
EC2Client: &ec2Client,
AWSRegions: []string{"us-west-2"},
Caller: sts.GetCallerIdentityOutput{
Account: aws.String("123456789012"),
Arn: aws.String("arn:aws:iam::123456789012:user/cloudfox_unit_tests"),
},
Goroutines: 30,
},
expectedResult: []Resource2{
{
Name: "vpce-1234567890abcdefg",
ARN: "vpce-1234567890abcdefg",
Public: "No",
},
{
Name: "vpce-1234567890abcdefh",
ARN: "vpce-1234567890abcdefh",
Public: "No",
},
},
},
}
for _, tc := range testCases {
tc.testModule.PrintResources(tc.outputDirectory, tc.verbosity, false)
for index, expectedResource2 := range tc.expectedResult {
if expectedResource2.Name != tc.testModule.Resources2[index].Name {
t.Fatal("Resource name does not match expected value")
}
if expectedResource2.ARN != tc.testModule.Resources2[index].ARN {
t.Fatal("Resource ARN does not match expected value")
}
if expectedResource2.Public != tc.testModule.Resources2[index].Public {
t.Fatal("Resource Public does not match expected value")
}
}
}
}
func TestOpenSearchResourceTrusts(t *testing.T) {
mockedOpenSearchClient := &sdk.MockedOpenSearchClient{}
var openSearchClient sdk.OpenSearchClientInterface = mockedOpenSearchClient
testCases := []struct {
outputDirectory string
verbosity int
testModule ResourceTrustsModule
expectedResult []Resource2
}{
{
outputDirectory: ".",
verbosity: 2,
testModule: ResourceTrustsModule{
KMSClient: nil,
APIGatewayClient: nil,
EC2Client: nil,
OpenSearchClient: &openSearchClient,
AWSRegions: []string{"us-west-2"},
Caller: sts.GetCallerIdentityOutput{
Account: aws.String("123456789012"),
Arn: aws.String("arn:aws:iam::123456789012:user/cloudfox_unit_tests"),
},
Goroutines: 30,
},
expectedResult: []Resource2{
{
Name: "domain1",
ARN: "arn:aws:es:us-east-1:123456789012:domain/domain1",
Public: "No",
},
{
Name: "domain2",
ARN: "arn:aws:es:us-east-1:123456789012:domain/domain2",
Public: "Yes",
},
},
},
}
for _, tc := range testCases {
tc.testModule.PrintResources(tc.outputDirectory, tc.verbosity, false)
for index, expectedResource2 := range tc.expectedResult {
if expectedResource2.Name != tc.testModule.Resources2[index].Name {
t.Fatal("Resource name does not match expected value")
}
if expectedResource2.ARN != tc.testModule.Resources2[index].ARN {
t.Fatal("Resource ARN does not match expected value")
}
if expectedResource2.Public != tc.testModule.Resources2[index].Public {
t.Fatal("Resource Public does not match expected value")
}
}
}
}
+6 -5
View File
@@ -219,9 +219,10 @@ func (m *RoleTrustsModule) printPrincipalTrusts(outputDirectory string) ([]strin
RoleARN: aws.ToString(role.roleARN),
RoleName: GetResourceNameFromArn(aws.ToString(role.roleARN)),
TrustedPrincipal: principal,
ExternalID: statement.Condition.StringEquals.StsExternalID,
IsAdmin: role.Admin,
CanPrivEsc: role.CanPrivEsc,
// if there is more than one externalID concat them using newlines
ExternalID: strings.Join(statement.Condition.StringEquals.StsExternalID, "\n"),
IsAdmin: role.Admin,
CanPrivEsc: role.CanPrivEsc,
}
body = append(body, []string{
aws.ToString(m.Caller.Account),
@@ -281,7 +282,7 @@ func (m *RoleTrustsModule) printPrincipalTrustsRootOnly(outputDirectory string)
for _, role := range m.AnalyzedRoles {
for _, statement := range role.trustsDoc.Statement {
for _, principal := range statement.Principal.AWS {
if strings.Contains(principal, ":root") && statement.Condition.StringEquals.StsExternalID == "" {
if strings.Contains(principal, ":root") && statement.Condition.StringEquals.StsExternalID == nil {
accountID := strings.Split(principal, ":")[4]
vendorName := m.vendors.GetVendorNameFromAccountID(accountID)
if vendorName != "" {
@@ -292,7 +293,7 @@ func (m *RoleTrustsModule) printPrincipalTrustsRootOnly(outputDirectory string)
RoleARN: aws.ToString(role.roleARN),
RoleName: GetResourceNameFromArn(aws.ToString(role.roleARN)),
TrustedPrincipal: principal,
ExternalID: statement.Condition.StringEquals.StsExternalID,
ExternalID: strings.Join(statement.Condition.StringEquals.StsExternalID, "\n"),
IsAdmin: role.Admin,
CanPrivEsc: role.CanPrivEsc,
}
+17 -5
View File
@@ -235,19 +235,31 @@ func (m *Route53Module) getRoute53Records() {
recordName = aws.ToString(record.Name)
recordType = string(record.Type)
for _, resourceRecord := range record.ResourceRecords {
recordValue := resourceRecord.Value
if record.AliasTarget != nil {
m.Records = append(
m.Records,
Record{
AWSService: "Route53",
Name: recordName,
Type: recordType,
Value: aws.ToString(recordValue),
Type: fmt.Sprintf("Alias[%s]", recordType),
Value: aws.ToString(record.AliasTarget.DNSName),
PrivateZone: privateZone,
})
} else {
for _, resourceRecord := range record.ResourceRecords {
recordValue := resourceRecord.Value
m.Records = append(
m.Records,
Record{
AWSService: "Route53",
Name: recordName,
Type: recordType,
Value: aws.ToString(recordValue),
PrivateZone: privateZone,
})
}
}
}
}
+122 -1
View File
@@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/apigateway"
apiGatewayTypes "github.com/aws/aws-sdk-go-v2/service/apigateway/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type APIGatewayClientInterface interface {
@@ -53,15 +54,37 @@ func init() {
gob.Register([]apiGatewayTypes.UsagePlanKey{})
}
// create a CachedApiGatewayGetRestAPIs function that accepts a client, account id, region. Make sure it handles caching, the region option and pagination
func IsPublicApiGateway(ra *apiGatewayTypes.RestApi) bool {
for _, endpointType := range ra.EndpointConfiguration.Types {
if endpointType == apiGatewayTypes.EndpointTypeRegional || endpointType == apiGatewayTypes.EndpointTypeEdge {
return true
}
}
return false
}
// CachedApiGatewayGetRestAPIs function that accepts a client, account id, region. Make sure it handles caching, the region option and pagination
func CachedApiGatewayGetRestAPIs(client APIGatewayClientInterface, accountID string, region string) ([]apiGatewayTypes.RestApi, error) {
var PaginationControl *string
var restAPIs []apiGatewayTypes.RestApi
cacheKey := fmt.Sprintf("%s-apigateway-GetRestApis-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetRestApis",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatewayTypes.RestApi), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetRestApis",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetRestApis, err := client.GetRestApis(
@@ -95,10 +118,24 @@ func CachedApiGatewayGetStages(client APIGatewayClientInterface, accountID strin
cacheKey := fmt.Sprintf("%s-apigateway-GetStages-%s-%s", accountID, region, restAPIID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetStages",
"account": accountID,
"region": region,
"restApiId": restAPIID,
"cache": "hit",
}).Info("AWS API call")
// Convert cached data back to GetStagesOutput before returning
cachedOutput := cached.(*CachedGetStagesOutput) // Ensure this type assertion matches your caching logic
return fromCachedGetStagesOutput(cachedOutput), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetStages",
"account": accountID,
"region": region,
"restApiId": restAPIID,
"cache": "miss",
}).Info("AWS API call")
GetStages, err := client.GetStages(
context.TODO(),
@@ -142,8 +179,22 @@ func CachedApiGatewayGetResources(client APIGatewayClientInterface, accountID st
cacheKey := fmt.Sprintf("%s-apigateway-GetResources-%s-%s", accountID, region, restAPIID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetResources",
"account": accountID,
"region": region,
"restApiId": restAPIID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatewayTypes.Resource), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetResources",
"account": accountID,
"region": region,
"restApiId": restAPIID,
"cache": "miss",
}).Info("AWS API call")
for {
GetResources, err := client.GetResources(
@@ -180,8 +231,20 @@ func CachedApiGatewayGetDomainNames(client APIGatewayClientInterface, accountID
cacheKey := fmt.Sprintf("%s-apigateway-GetDomainNames-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetDomainNames",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatewayTypes.DomainName), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetDomainNames",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetDomainNames, err := client.GetDomainNames(
@@ -217,8 +280,22 @@ func CachedApiGatewayGetBasePathMappings(client APIGatewayClientInterface, accou
cacheKey := fmt.Sprintf("%s-apigateway-GetBasePathMappings-%s-%s", accountID, region, aws.ToString(domain))
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetBasePathMappings",
"account": accountID,
"region": region,
"domainName": aws.ToString(domain),
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatewayTypes.BasePathMapping), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetBasePathMappings",
"account": accountID,
"region": region,
"domainName": aws.ToString(domain),
"cache": "miss",
}).Info("AWS API call")
for {
GetBasePathMappings, err := client.GetBasePathMappings(
@@ -254,10 +331,28 @@ func CachedApiGatewayGetMethod(client APIGatewayClientInterface, accountID strin
cacheKey := fmt.Sprintf("%s-apigateway-GetMethod-%s-%s-%s-%s", accountID, region, restAPIID, resourceID, method)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetMethod",
"account": accountID,
"region": region,
"restApiId": restAPIID,
"resourceId": resourceID,
"httpMethod": method,
"cache": "hit",
}).Info("AWS API call")
// Convert cached data back to GetMethodOutput before returning
cachedOutput := cached.(*CachedGetMethodOutput) // Ensure this type assertion matches your caching logic
return fromCachedGetMethodOutput(cachedOutput), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetMethod",
"account": accountID,
"region": region,
"restApiId": restAPIID,
"resourceId": resourceID,
"httpMethod": method,
"cache": "miss",
}).Info("AWS API call")
GetMethod, err := client.GetMethod(
context.TODO(),
@@ -324,8 +419,20 @@ func CachedApiGatewayGetUsagePlans(client APIGatewayClientInterface, accountID s
cacheKey := fmt.Sprintf("%s-apigateway-GetUsagePlans-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetUsagePlans",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatewayTypes.UsagePlan), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetUsagePlans",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetUsagePlans, err := client.GetUsagePlans(
@@ -362,8 +469,22 @@ func CachedApiGatewayGetUsagePlanKeys(client APIGatewayClientInterface, accountI
cacheKey := fmt.Sprintf("%s-apigateway-GetUsagePlanKeys-%s-%s", accountID, region, usagePlanID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetUsagePlanKeys",
"account": accountID,
"region": region,
"usagePlanId": usagePlanID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatewayTypes.UsagePlanKey), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigateway:GetUsagePlanKeys",
"account": accountID,
"region": region,
"usagePlanId": usagePlanID,
"cache": "miss",
}).Info("AWS API call")
for {
GetUsagePlanKeys, err := client.GetUsagePlanKeys(
+1
View File
@@ -22,6 +22,7 @@ func (m *MockedAWSAPIGatewayClient) GetRestApis(ctx context.Context, input *apig
apiGatewayTypes.EndpointTypePrivate,
},
},
Policy: aws.String("{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"execute-api:Invoke\",\"Resource\":\"arn:aws:execute-api:us-west-2:123456789012:abcdefg/*/*/*\"}]}"),
},
{
Id: aws.String("qwerty"),
+61
View File
@@ -10,6 +10,7 @@ import (
apiGatwayV2Types "github.com/aws/aws-sdk-go-v2/service/apigatewayv2/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type APIGatewayv2ClientInterface interface {
@@ -38,8 +39,20 @@ func CachedAPIGatewayv2GetAPIs(client APIGatewayv2ClientInterface, accountID str
cacheKey := fmt.Sprintf("%s-apigatewayv2-GetApis-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetApis",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatwayV2Types.Api), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetApis",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetApis, err := client.GetApis(
context.TODO(),
@@ -74,8 +87,20 @@ func CachedAPIGatewayv2GetDomainNames(client APIGatewayv2ClientInterface, accoun
cacheKey := fmt.Sprintf("%s-apigatewayv2-GetDomainNames-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetDomainNames",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]domainName), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetDomainNames",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetDomainNames, err := client.GetDomainNames(
context.TODO(),
@@ -114,8 +139,20 @@ func CachedAPIGatewayv2GetApiMappings(client APIGatewayv2ClientInterface, accoun
cacheKey := fmt.Sprintf("%s-apigatewayv2-GetApiMappings-%s-%s", accountID, region, domain)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetApiMappings",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatwayV2Types.ApiMapping), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetApiMappings",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetApiMappings, err := client.GetApiMappings(
context.TODO(),
@@ -151,8 +188,20 @@ func CachedAPIGatewayv2GetStages(client APIGatewayv2ClientInterface, accountID s
cacheKey := fmt.Sprintf("%s-apigatewayv2-GetStages-%s-%s", accountID, region, apiID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetStages",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatwayV2Types.Stage), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetStages",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetStages, err := client.GetStages(
context.TODO(),
@@ -188,8 +237,20 @@ func CachedAPIGatewayv2GetRoutes(client APIGatewayv2ClientInterface, accountID s
cacheKey := fmt.Sprintf("%s-apigatewayv2-GetRoutes-%s-%s", accountID, region, apiID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetRoutes",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apiGatwayV2Types.Route), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apigatewayv2:GetRoutes",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetRoutes, err := client.GetRoutes(
context.TODO(),
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/apprunner"
apprunnerTypes "github.com/aws/aws-sdk-go-v2/service/apprunner/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AppRunnerClientInterface interface {
@@ -26,8 +27,20 @@ func CachedAppRunnerListServices(client AppRunnerClientInterface, accountID stri
cacheKey := fmt.Sprintf("%s-apprunner-ListServices-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "apprunner:ListServices",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]apprunnerTypes.ServiceSummary), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "apprunner:ListServices",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListServices, err := client.ListServices(
context.TODO(),
+27
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/athena"
athenaTypes "github.com/aws/aws-sdk-go-v2/service/athena/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSAthenaClientInterface interface {
@@ -26,8 +27,20 @@ func CachedAthenaListDataCatalogs(client AWSAthenaClientInterface, accountID str
cacheKey := fmt.Sprintf("%s-athena-ListDataCatalogs-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "athena:ListDataCatalogs",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]athenaTypes.DataCatalogSummary), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "athena:ListDataCatalogs",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListDataCatalogs, err := client.ListDataCatalogs(
context.TODO(),
@@ -62,8 +75,22 @@ func CachedAthenaListDatabases(client AWSAthenaClientInterface, accountID string
cacheKey := fmt.Sprintf("%s-athena-ListDatabases-%s-%s", accountID, region, catalogName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "athena:ListDatabases",
"account": accountID,
"region": region,
"catalogName": catalogName,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "athena:ListDatabases",
"account": accountID,
"region": region,
"catalogName": catalogName,
"cache": "miss",
}).Info("AWS API call")
for {
ListDatabases, err := client.ListDatabases(
context.TODO(),
+25
View File
@@ -8,6 +8,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/cloud9"
cloud9Types "github.com/aws/aws-sdk-go-v2/service/cloud9/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSCloud9ClientInterface interface {
@@ -25,8 +26,20 @@ func CachedCloud9ListEnvironments(client AWSCloud9ClientInterface, accountID str
cacheKey := "cloud9-ListEnvironments-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "cloud9:ListEnvironments",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "cloud9:ListEnvironments",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListEnvironments, err := client.ListEnvironments(
context.TODO(),
@@ -60,8 +73,20 @@ func CachedCloud9DescribeEnvironments(client AWSCloud9ClientInterface, accountID
cacheKey := "cloud9-DescribeEnvironments-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "cloud9:DescribeEnvironments",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]cloud9Types.Environment), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "cloud9:DescribeEnvironments",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for _, environmentID := range environmentIDs {
DescribeEnvironments, err := client.DescribeEnvironments(
context.TODO(),
+37
View File
@@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/cloudformation"
cloudFormationTypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type CloudFormationClientInterface interface {
@@ -29,8 +30,20 @@ func CachedCloudFormationDescribeStacks(client CloudFormationClientInterface, ac
cacheKey := fmt.Sprintf("%s-cloudformation-DescribeStacks-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "cloudformation:DescribeStacks",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]cloudFormationTypes.Stack), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "cloudformation:DescribeStacks",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeStacks, err := client.DescribeStacks(
context.TODO(),
@@ -63,8 +76,20 @@ func CachedCloudFormationGetTemplate(client CloudFormationClientInterface, accou
cacheKey := fmt.Sprintf("%s-cloudformation-GetTemplate-%s-%s", accountID, region, stackName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "cloudformation:GetTemplate",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.(string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "cloudformation:GetTemplate",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
GetTemplate, err := client.GetTemplate(
context.TODO(),
@@ -89,8 +114,20 @@ func CachedCloudFormationListStacks(client CloudFormationClientInterface, accoun
cacheKey := fmt.Sprintf("%s-cloudformation-ListStacks-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "cloudformation:ListStacks",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]cloudFormationTypes.StackSummary), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "cloudformation:ListStacks",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListStacks, err := client.ListStacks(
context.TODO(),
+11 -1
View File
@@ -8,6 +8,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/cloudfront"
cloudfrontTypes "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSCloudFrontClientInterface interface {
@@ -25,9 +26,18 @@ func CachedCloudFrontListDistributions(CloudFrontClient AWSCloudFrontClientInter
cacheKey := "cloudfront-ListDistributions-" + accountID
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached CloudFront distributions data")
sharedLogger.WithFields(logrus.Fields{
"api": "cloudfront:ListDistributions",
"account": accountID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]cloudfrontTypes.DistributionSummary), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "cloudfront:ListDistributions",
"account": accountID,
"cache": "miss",
}).Info("AWS API call")
for {
ListDistributions, err := CloudFrontClient.ListDistributions(
+25
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/codeartifact"
codeArtifactTypes "github.com/aws/aws-sdk-go-v2/service/codeartifact/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSCodeArtifactClientInterface interface {
@@ -27,8 +28,20 @@ func CachedCodeArtifactListDomains(client AWSCodeArtifactClientInterface, accoun
cacheKey := fmt.Sprintf("%s-codeartifact-ListDomains-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codeartifact:ListDomains",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]codeArtifactTypes.DomainSummary), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codeartifact:ListDomains",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListDomains, err := client.ListDomains(
context.TODO(),
@@ -63,8 +76,20 @@ func CachedCodeArtifactListRepositories(client AWSCodeArtifactClientInterface, a
cacheKey := fmt.Sprintf("%s-codeartifact-ListRepositories-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codeartifact:ListRepositories",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]codeArtifactTypes.RepositorySummary), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codeartifact:ListRepositories",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListRepositories, err := client.ListRepositories(
context.TODO(),
+37
View File
@@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/codebuild"
codeBuildTypes "github.com/aws/aws-sdk-go-v2/service/codebuild/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type CodeBuildClientInterface interface {
@@ -31,8 +32,20 @@ func CachedCodeBuildListProjects(CodeBuildClient CodeBuildClientInterface, accou
cacheKey := fmt.Sprintf("%s-codebuild-ListProjects", accountID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codebuild:ListProjects",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codebuild:ListProjects",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListProjects, err := CodeBuildClient.ListProjects(
@@ -71,8 +84,20 @@ func CachedCodeBuildBatchGetProjects(CodeBuildClient CodeBuildClientInterface, a
cacheKey := fmt.Sprintf("%s-codebuild-BatchGetProjects-%s-%s", accountID, region, projectID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codebuild:BatchGetProjects",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.(codeBuildTypes.Project), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codebuild:BatchGetProjects",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
BatchGetProjects, err := CodeBuildClient.BatchGetProjects(
context.TODO(),
@@ -97,8 +122,20 @@ func CachedCodeBuildGetResourcePolicy(CodeBuildClient CodeBuildClientInterface,
cacheKey := fmt.Sprintf("%s-codebuild-GetResourcePolicy-%s-%s", accountID, region, projectID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codebuild:GetResourcePolicy",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.(string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codebuild:GetResourcePolicy",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
GetResourcePolicy, err := CodeBuildClient.GetResourcePolicy(
context.TODO(),
+14
View File
@@ -5,6 +5,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/codebuild"
codeBuildTypes "github.com/aws/aws-sdk-go-v2/service/codebuild/types"
)
type MockedCodeBuildClient struct {
@@ -19,6 +20,19 @@ func (m *MockedCodeBuildClient) ListProjects(ctx context.Context, input *codebui
}, nil
}
func (m *MockedCodeBuildClient) BatchGetProjects(ctx context.Context, input *codebuild.BatchGetProjectsInput, options ...func(*codebuild.Options)) (*codebuild.BatchGetProjectsOutput, error) {
return &codebuild.BatchGetProjectsOutput{
Projects: []codeBuildTypes.Project{
{
Name: aws.String("project1"),
},
{
Name: aws.String("project2"),
},
},
}, nil
}
func (m *MockedCodeBuildClient) GetResourcePolicy(ctx context.Context, input *codebuild.GetResourcePolicyInput, options ...func(*codebuild.Options)) (*codebuild.GetResourcePolicyOutput, error) {
return &codebuild.GetResourcePolicyOutput{
Policy: aws.String(`{
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/codecommit"
codeCommitTypes "github.com/aws/aws-sdk-go-v2/service/codecommit/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSCodeCommitClientInterface interface {
@@ -25,8 +26,20 @@ func CachedCodeCommitListRepositories(client AWSCodeCommitClientInterface, accou
cacheKey := fmt.Sprintf("%s-codecommit-ListRepositories-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codecommit:ListRepositories",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]codeCommitTypes.RepositoryNameIdPair), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codecommit:ListRepositories",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListRepositories, err := client.ListRepositories(
context.TODO(),
+79
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/codedeploy"
codeDeployTypes "github.com/aws/aws-sdk-go-v2/service/codedeploy/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSCodeDeployClientInterface interface {
@@ -34,8 +35,20 @@ func CachedCodeDeployListApplications(client AWSCodeDeployClientInterface, accou
cacheKey := fmt.Sprintf("%s-codedeploy-ListApplications-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:ListApplications",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:ListApplications",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListApplications, err := client.ListApplications(
context.TODO(),
@@ -70,8 +83,20 @@ func CachedCodeDeployListDeploymentConfigs(client AWSCodeDeployClientInterface,
cacheKey := fmt.Sprintf("%s-codedeploy-ListDeploymentConfigs-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:ListDeploymentConfigs",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:ListDeploymentConfigs",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListDeploymentConfigs, err := client.ListDeploymentConfigs(
context.TODO(),
@@ -106,8 +131,20 @@ func CachedCodeDeployListDeployments(client AWSCodeDeployClientInterface, accoun
cacheKey := fmt.Sprintf("%s-codedeploy-ListDeployments-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:ListDeployments",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:ListDeployments",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListDeployments, err := client.ListDeployments(
context.TODO(),
@@ -140,8 +177,22 @@ func CachedCodeDeployGetApplication(client AWSCodeDeployClientInterface, account
cacheKey := fmt.Sprintf("%s-codedeploy-GetApplication-%s-%s", accountID, region, applicationName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:GetApplication",
"account": accountID,
"region": region,
"application": applicationName,
"cache": "hit",
}).Info("AWS API call")
return cached.(codeDeployTypes.ApplicationInfo), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:GetApplication",
"account": accountID,
"region": region,
"application": applicationName,
"cache": "miss",
}).Info("AWS API call")
GetApplication, err := client.GetApplication(
context.TODO(),
&codedeploy.GetApplicationInput{
@@ -165,8 +216,22 @@ func CachedCodeDeployGetDeploymentConfig(client AWSCodeDeployClientInterface, ac
cacheKey := fmt.Sprintf("%s-codedeploy-GetDeploymentConfig-%s-%s", accountID, region, deploymentConfigName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:GetDeploymentConfig",
"account": accountID,
"region": region,
"deploymentConfig": deploymentConfigName,
"cache": "hit",
}).Info("AWS API call")
return cached.(codeDeployTypes.DeploymentConfigInfo), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:GetDeploymentConfig",
"account": accountID,
"region": region,
"deploymentConfig": deploymentConfigName,
"cache": "miss",
}).Info("AWS API call")
GetDeploymentConfig, err := client.GetDeploymentConfig(
context.TODO(),
&codedeploy.GetDeploymentConfigInput{
@@ -190,8 +255,22 @@ func CachedCodeDeployGetDeployment(client AWSCodeDeployClientInterface, accountI
cacheKey := fmt.Sprintf("%s-codedeploy-GetDeployment-%s-%s", accountID, region, deploymentID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:GetDeployment",
"account": accountID,
"region": region,
"deployment": deploymentID,
"cache": "hit",
}).Info("AWS API call")
return cached.(codeDeployTypes.DeploymentInfo), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "codedeploy:GetDeployment",
"account": accountID,
"region": region,
"deployment": deploymentID,
"cache": "miss",
}).Info("AWS API call")
GetDeployment, err := client.GetDeployment(
context.TODO(),
&codedeploy.GetDeploymentInput{
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/datapipeline"
dataPipelineTypes "github.com/aws/aws-sdk-go-v2/service/datapipeline/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSDataPipelineClientInterface interface {
@@ -25,8 +26,20 @@ func CachedDataPipelineListPipelines(client AWSDataPipelineClientInterface, acco
cacheKey := fmt.Sprintf("%s-datapipeline-ListPipelines-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "datapipeline:ListPipelines",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]dataPipelineTypes.PipelineIdName), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "datapipeline:ListPipelines",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListPipelines, err := client.ListPipelines(
context.TODO(),
+37 -1
View File
@@ -9,8 +9,8 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/docdb"
docdbTypes "github.com/aws/aws-sdk-go-v2/service/docdb/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type DocDBClientInterface interface {
@@ -32,8 +32,20 @@ func CachedDocDBDescribeGlobalClusters(client DocDBClientInterface, accountID st
cacheKey := fmt.Sprintf("%s-docdb-DescribeGlobalClusters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "docdb:DescribeGlobalClusters",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]docdbTypes.GlobalCluster), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "docdb:DescribeGlobalClusters",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeGlobalClusters, err := client.DescribeGlobalClusters(
context.TODO(),
@@ -68,8 +80,20 @@ func CachedDocDBDescribeDBClusters(client DocDBClientInterface, accountID string
cacheKey := fmt.Sprintf("%s-docdb-DescribeDBClusters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "docdb:DescribeDBClusters",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]docdbTypes.DBCluster), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "docdb:DescribeDBClusters",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeDBClusters, err := client.DescribeDBClusters(
context.TODO(),
@@ -110,8 +134,20 @@ func CachedDocDBDescribeDBInstances(client DocDBClientInterface, accountID strin
cacheKey := fmt.Sprintf("%s-docdb-DescribeDBInstances-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "docdb:DescribeDBInstances",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]docdbTypes.DBInstance), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "docdb:DescribeDBInstances",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeDBInstances, err := client.DescribeDBInstances(
context.TODO(),
+27
View File
@@ -9,6 +9,7 @@ import (
"github.com/BishopFox/cloudfox/internal"
"github.com/aws/aws-sdk-go-v2/service/directoryservice"
dsTypes "github.com/aws/aws-sdk-go-v2/service/directoryservice/types"
"github.com/sirupsen/logrus"
)
type AWSDSClientInterface interface {
@@ -28,8 +29,20 @@ func CachedDSDescribeDirectories(client AWSDSClientInterface, accountID string,
cacheKey := fmt.Sprintf("%s-ds-DescribeDirectories-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "ds:DescribeDirectories",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]dsTypes.DirectoryDescription), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ds:DescribeDirectories",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeDirectories, err := client.DescribeDirectories(
context.TODO(),
@@ -64,8 +77,22 @@ func CachedDSDescribeTrusts(client AWSDSClientInterface, accountID string, regio
cacheKey := fmt.Sprintf("%s-ds-DescribeTrusts-%s-%s", accountID, region, directoryId)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "ds:DescribeTrusts",
"account": accountID,
"region": region,
"directoryId": directoryId,
"cache": "hit",
}).Info("AWS API call")
return cached.([]dsTypes.Trust), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ds:DescribeTrusts",
"account": accountID,
"region": region,
"directoryId": directoryId,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeDirectoryTrusts, err := client.DescribeTrusts(
context.TODO(),
+27
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
dynamoDBTypes "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type DynamoDBClientInterface interface {
@@ -27,8 +28,21 @@ func CachedDynamoDBListTables(client DynamoDBClientInterface, accountID string,
cacheKey := fmt.Sprintf("%s-dynamodb-ListTables-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "dynamodb:ListTables",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "dynamodb:ListTables",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListTables, err := client.ListTables(
context.TODO(),
@@ -62,9 +76,22 @@ func CachedDynamoDBDescribeTable(client DynamoDBClientInterface, accountID strin
cacheKey := fmt.Sprintf("%s-dynamodb-DescribeTable-%s-%s", accountID, region, tableName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "dynamodb:DescribeTable",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.(dynamoDBTypes.TableDescription), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "dynamodb:DescribeTable",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
DescribeTable, err := client.DescribeTable(
context.TODO(),
&dynamodb.DescribeTableInput{
+120 -1
View File
@@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/ec2"
ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSEC2ClientInterface interface {
@@ -19,6 +20,7 @@ type AWSEC2ClientInterface interface {
DescribeVolumes(context.Context, *ec2.DescribeVolumesInput, ...func(*ec2.Options)) (*ec2.DescribeVolumesOutput, error)
DescribeImages(context.Context, *ec2.DescribeImagesInput, ...func(*ec2.Options)) (*ec2.DescribeImagesOutput, error)
DescribeInstanceAttribute(context.Context, *ec2.DescribeInstanceAttributeInput, ...func(*ec2.Options)) (*ec2.DescribeInstanceAttributeOutput, error)
DescribeVpcEndpoints(context.Context, *ec2.DescribeVpcEndpointsInput, ...func(options *ec2.Options)) (*ec2.DescribeVpcEndpointsOutput, error)
}
func init() {
@@ -27,7 +29,7 @@ func init() {
gob.Register([]ec2Types.Snapshot{})
gob.Register([]ec2Types.Volume{})
gob.Register([]ec2Types.Image{})
gob.Register([]ec2Types.VpcEndpoint{})
}
func CachedEC2DescribeInstances(client AWSEC2ClientInterface, accountID string, region string) ([]ec2Types.Instance, error) {
@@ -36,8 +38,20 @@ func CachedEC2DescribeInstances(client AWSEC2ClientInterface, accountID string,
cacheKey := fmt.Sprintf("%s-ec2-DescribeInstances-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeInstances",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]ec2Types.Instance), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeInstances",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeInstances, err := client.DescribeInstances(
context.TODO(),
@@ -72,8 +86,22 @@ func CachedEC2DescribeInstanceAttributeUserData(client AWSEC2ClientInterface, ac
cacheKey := fmt.Sprintf("%s-ec2-DescribeInstanceAttributeUserData-%s-%s", accountID, region, instanceID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeInstanceAttribute",
"account": accountID,
"region": region,
"instance": instanceID,
"cache": "hit",
}).Info("AWS API call")
return cached.(string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeInstanceAttribute",
"account": accountID,
"region": region,
"instance": instanceID,
"cache": "miss",
}).Info("AWS API call")
DescribeInstanceAttribute, err := client.DescribeInstanceAttribute(
context.TODO(),
&ec2.DescribeInstanceAttributeInput{
@@ -98,8 +126,20 @@ func CachedEC2DescribeNetworkInterfaces(client AWSEC2ClientInterface, accountID
cacheKey := fmt.Sprintf("%s-ec2-DescribeNetworkInterfaces-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeNetworkInterfaces",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]ec2Types.NetworkInterface), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeNetworkInterfaces",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeNetworkInterfaces, err := client.DescribeNetworkInterfaces(
context.TODO(),
@@ -131,8 +171,20 @@ func CachedEC2DescribeSnapshots(client AWSEC2ClientInterface, accountID string,
cacheKey := fmt.Sprintf("%s-ec2-DescribeSnapshots-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeSnapshots",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]ec2Types.Snapshot), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeSnapshots",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeSnapshots, err := client.DescribeSnapshots(
context.TODO(),
@@ -165,8 +217,20 @@ func CachedEC2DescribeVolumes(client AWSEC2ClientInterface, accountID string, re
cacheKey := fmt.Sprintf("%s-ec2-DescribeVolumes-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeVolumes",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]ec2Types.Volume), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeVolumes",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeVolumes, err := client.DescribeVolumes(
context.TODO(),
@@ -198,8 +262,20 @@ func CachedEC2DescribeImages(client AWSEC2ClientInterface, accountID string, reg
cacheKey := fmt.Sprintf("%s-ec2-DescribeImages-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeImages",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]ec2Types.Image), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeImages",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeImages, err := client.DescribeImages(
context.TODO(),
@@ -224,5 +300,48 @@ func CachedEC2DescribeImages(client AWSEC2ClientInterface, accountID string, reg
internal.Cache.Set(cacheKey, Images, cache.DefaultExpiration)
return Images, nil
}
func CachedEC2DescribeVpcEndpoints(client AWSEC2ClientInterface, accountID string, region string) ([]ec2Types.VpcEndpoint, error) {
var PaginationControl *string
var VpcEndpoints []ec2Types.VpcEndpoint
cacheKey := fmt.Sprintf("%s-ec2-DescribeVpcEndpoints-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeVpcEndpoints",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]ec2Types.VpcEndpoint), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ec2:DescribeVpcEndpoints",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeVpcEndpoints, err := client.DescribeVpcEndpoints(
context.TODO(),
&(ec2.DescribeVpcEndpointsInput{
NextToken: PaginationControl,
}),
func(o *ec2.Options) {
o.Region = region
},
)
if err != nil {
return VpcEndpoints, err
}
VpcEndpoints = append(VpcEndpoints, DescribeVpcEndpoints.VpcEndpoints...)
if DescribeVpcEndpoints.NextToken == nil {
break
}
PaginationControl = DescribeVpcEndpoints.NextToken
}
internal.Cache.Set(cacheKey, VpcEndpoints, cache.DefaultExpiration)
return VpcEndpoints, nil
}
+44
View File
@@ -25,6 +25,7 @@ type MockedEC2Client2 struct {
describeSnapshots DescribeSnapshots
describeVolumes DescribeVolumes
describeImages DescribeImages
describeVpcEndpoints DescribeVpcEndpoints
}
type DescribeNetworkInterfaces struct {
@@ -271,6 +272,9 @@ type DescribeInstanceAttribute struct {
InstanceID string `json:"InstanceId"`
}
type DescribeVpcEndpoints struct {
}
func (c *MockedEC2Client2) DescribeNetworkInterfaces(ctx context.Context, input *ec2.DescribeNetworkInterfacesInput, f ...func(o *ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error) {
var nics []ec2types.NetworkInterface
err := json.Unmarshal(readTestFile(DESCRIBE_NETWORK_INTEFACES_TEST_FILE), &c.describeNetworkInterfaces)
@@ -386,3 +390,43 @@ func (c *MockedEC2Client2) DescribeInstanceAttribute(ctx context.Context, input
},
}, nil
}
func (c *MockedEC2Client2) DescribeVpcEndpoints(ctx context.Context, input *ec2.DescribeVpcEndpointsInput, f ...func(o *ec2.Options)) (*ec2.DescribeVpcEndpointsOutput, error) {
return &ec2.DescribeVpcEndpointsOutput{
VpcEndpoints: []ec2types.VpcEndpoint{
{
VpcEndpointId: aws.String("vpce-1234567890abcdefg"),
PolicyDocument: aws.String(`{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "*",
"Resource": "*"
}
]
}`),
},
{
VpcEndpointId: aws.String("vpce-1234567890abcdefh"),
PolicyDocument: aws.String(`{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:SourceVpce": "vpce-1234567890abcdefg"
}
}
}
]
}`),
},
},
}, nil
}
+41 -3
View File
@@ -11,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/ecr"
ecrTypes "github.com/aws/aws-sdk-go-v2/service/ecr/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSECRClientInterface interface {
@@ -33,9 +34,20 @@ func CachedECRDescribeRepositories(ECRClient AWSECRClientInterface, accountID st
cacheKey := fmt.Sprintf("%s-ecr-DescribeRepositories-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached ECR repositories data")
sharedLogger.WithFields(logrus.Fields{
"api": "ecr:DescribeRepositories",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]ecrTypes.Repository), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ecr:DescribeRepositories",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeRepositories, err := ECRClient.DescribeRepositories(
@@ -73,9 +85,22 @@ func CachedECRDescribeImages(ECRClient AWSECRClientInterface, accountID string,
cacheKey := fmt.Sprintf("%s-ecr-DescribeImages-%s-%s", accountID, region, strings.ReplaceAll(repositoryName, "/", "-"))
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached Images data")
sharedLogger.WithFields(logrus.Fields{
"api": "ecr:DescribeImages",
"account": accountID,
"region": region,
"repository": repositoryName,
"cache": "hit",
}).Info("AWS API call")
return cached.([]ecrTypes.ImageDetail), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ecr:DescribeImages",
"account": accountID,
"region": region,
"repository": repositoryName,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeImages, err := ECRClient.DescribeImages(
@@ -113,9 +138,22 @@ func CachedECRGetRepositoryPolicy(ECRClient AWSECRClientInterface, accountID str
cacheKey := fmt.Sprintf("%s-ecr-GetRepositoryPolicy-%s-%s", accountID, region, strings.ReplaceAll(repositoryName, "/", "-"))
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached ECR repository policy data")
sharedLogger.WithFields(logrus.Fields{
"api": "ecr:GetRepositoryPolicy",
"account": accountID,
"region": region,
"repository": repositoryName,
"cache": "hit",
}).Info("AWS API call")
return cached.(string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ecr:GetRepositoryPolicy",
"account": accountID,
"region": region,
"repository": repositoryName,
"cache": "miss",
}).Info("AWS API call")
GetRepositoryPolicy, err := ECRClient.GetRepositoryPolicy(
context.TODO(),
+69 -5
View File
@@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/ecs"
ecsTypes "github.com/aws/aws-sdk-go-v2/service/ecs/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSECSClientInterface interface {
@@ -34,9 +35,20 @@ func CachedECSListClusters(ECSClient AWSECSClientInterface, accountID string, re
cacheKey := fmt.Sprintf("%s-ecs-ListClusters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached ECS clusters data")
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:ListClusters",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:ListClusters",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListClusters, err := ECSClient.ListClusters(
@@ -77,9 +89,22 @@ func CachedECSListTasks(ECSClient AWSECSClientInterface, accountID string, regio
cacheKey := fmt.Sprintf("%s-ecs-ListTasks-%s-%s", accountID, region, clusterName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached ECS tasks data")
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:ListTasks",
"account": accountID,
"region": region,
"cluster": clusterName,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:ListTasks",
"account": accountID,
"region": region,
"cluster": clusterName,
"cache": "miss",
}).Info("AWS API call")
for {
ListTasks, err := ECSClient.ListTasks(
@@ -120,9 +145,22 @@ func CachedECSDescribeTasks(ECSClient AWSECSClientInterface, accountID string, r
cacheKey := fmt.Sprintf("%s-ecs-DescribeTasks-%s-%s", accountID, region, clusterFileSystemSafe)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached ECS task details data")
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:DescribeTasks",
"account": accountID,
"region": region,
"cluster": cluster,
"cache": "hit",
}).Info("AWS API call")
return cached.([]ecsTypes.Task), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:DescribeTasks",
"account": accountID,
"region": region,
"cluster": cluster,
"cache": "miss",
}).Info("AWS API call")
DescribeTasks, err := ECSClient.DescribeTasks(
context.TODO(),
@@ -153,9 +191,22 @@ func CachedECSDescribeTaskDefinition(ECSClient AWSECSClientInterface, accountID
cacheKey := fmt.Sprintf("%s-ecs-DescribeTaskDefinition-%s-%s", accountID, region, taskDefinitionFileSystemSafe)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached ECS task definition details data")
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:DescribeTaskDefinition",
"account": accountID,
"region": region,
"taskDefinition": taskDefinition,
"cache": "hit",
}).Info("AWS API call")
return cached.(ecsTypes.TaskDefinition), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:DescribeTaskDefinition",
"account": accountID,
"region": region,
"taskDefinition": taskDefinition,
"cache": "miss",
}).Info("AWS API call")
DescribeTaskDefinition, err := ECSClient.DescribeTaskDefinition(
context.TODO(),
@@ -186,9 +237,22 @@ func CachedECSListServices(ECSClient AWSECSClientInterface, accountID string, re
cacheKey := fmt.Sprintf("%s-ecs-ListServices-%s-%s", accountID, region, clusterName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached ECS services data")
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:ListServices",
"account": accountID,
"region": region,
"cluster": clusterName,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ecs:ListServices",
"account": accountID,
"region": region,
"cluster": clusterName,
"cache": "miss",
}).Info("AWS API call")
for {
ListServices, err := ECSClient.ListServices(
+18
View File
@@ -135,12 +135,30 @@ func (c *MockedECSClient) DescribeTasks(ctx context.Context, input *ecs.Describe
Status: aws.String(a.Status),
})
}
var containers []ecsTypes.Container
for _, container := range mockedTask.Containers {
containers = append(containers, ecsTypes.Container{
ContainerArn: aws.String(container.ContainerArn),
Cpu: aws.String(container.CPU),
HealthStatus: ecsTypes.HealthStatus(container.HealthStatus),
Image: aws.String(container.Image),
LastStatus: aws.String(container.LastStatus),
Memory: aws.String(container.Memory),
Name: aws.String(container.Name),
RuntimeId: aws.String(container.RuntimeID),
TaskArn: aws.String(container.TaskArn),
})
}
tasks = append(tasks, ecsTypes.Task{
ClusterArn: aws.String(mockedTask.ClusterArn),
TaskDefinitionArn: aws.String(mockedTask.TaskDefinitionArn),
LaunchType: ecsTypes.LaunchType(*aws.String(mockedTask.LaunchType)),
TaskArn: aws.String(mockedTask.TaskArn),
Attachments: attachments,
Containers: containers,
})
}
}
+49
View File
@@ -11,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/efs"
efsTypes "github.com/aws/aws-sdk-go-v2/service/efs/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSEFSClientInterface interface {
@@ -34,8 +35,20 @@ func CachedDescribeFileSystems(EFSClient AWSEFSClientInterface, accountID string
cacheKey := fmt.Sprintf("%s-efs-DescribeFileSystems-%s", accountID, r)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "efs:DescribeFileSystems",
"account": accountID,
"region": r,
"cache": "hit",
}).Info("AWS API call")
return cached.([]efsTypes.FileSystemDescription), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "efs:DescribeFileSystems",
"account": accountID,
"region": r,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeFileSystems, err := EFSClient.DescribeFileSystems(
@@ -73,8 +86,20 @@ func CachedDescribeMountTargets(EFSClient AWSEFSClientInterface, accountID strin
cacheKey := fmt.Sprintf("%s-efs-DescribeMountTargets-%s-%s", accountID, r, filesystemId)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "efs:DescribeMountTargets",
"account": accountID,
"region": r,
"cache": "hit",
}).Info("AWS API call")
return cached.([]efsTypes.MountTargetDescription), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "efs:DescribeMountTargets",
"account": accountID,
"region": r,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeMountTargets, err := EFSClient.DescribeMountTargets(
@@ -113,8 +138,20 @@ func CachedDescribeAccessPoints(EFSClient AWSEFSClientInterface, accountID strin
cacheKey := fmt.Sprintf("%s-efs-DescribeAccessPoints-%s-%s", accountID, r, filesystemId)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "efs:DescribeAccessPoints",
"account": accountID,
"region": r,
"cache": "hit",
}).Info("AWS API call")
return cached.([]efsTypes.AccessPointDescription), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "efs:DescribeAccessPoints",
"account": accountID,
"region": r,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeAccessPoints, err := EFSClient.DescribeAccessPoints(
context.TODO(),
@@ -151,8 +188,20 @@ func CachedDescribeFileSystemPolicy(EFSClient AWSEFSClientInterface, filesystemI
cacheKey := fmt.Sprintf("efs-%s-DescribeFileSystemPolicy-%s-%s", accountID, r, filesystemId)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "efs:DescribeFileSystemPolicy",
"account": accountID,
"region": r,
"cache": "hit",
}).Info("AWS API call")
return cached.(policy.Policy), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "efs:DescribeFileSystemPolicy",
"account": accountID,
"region": r,
"cache": "miss",
}).Info("AWS API call")
Policy, err := EFSClient.DescribeFileSystemPolicy(
context.TODO(),
+57
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/eks"
eksTypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type EKSClientInterface interface {
@@ -30,8 +31,22 @@ func CachedEKSDescribeCluster(client EKSClientInterface, accountID string, clust
cacheKey := fmt.Sprintf("%s-eks-DescribeCluster-%s-%s", accountID, region, clusterName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "eks:DescribeCluster",
"account": accountID,
"region": region,
"cluster": clusterName,
"cache": "hit",
}).Info("AWS API call")
return cached.(eksTypes.Cluster), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "eks:DescribeCluster",
"account": accountID,
"region": region,
"cluster": clusterName,
"cache": "miss",
}).Info("AWS API call")
clusterOutput, err := client.DescribeCluster(
context.TODO(),
&eks.DescribeClusterInput{
@@ -57,8 +72,20 @@ func CachedEKSListClusters(client EKSClientInterface, accountID string, region s
cacheKey := fmt.Sprintf("%s-eks-ListClusters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "eks:ListClusters",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "eks:ListClusters",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListClusters, err := client.ListClusters(
context.TODO(),
@@ -93,8 +120,22 @@ func CachedEKSListNodeGroups(client EKSClientInterface, accountID string, region
cacheKey := fmt.Sprintf("%s-eks-ListNodeGroups-%s-%s", accountID, region, clusterName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "eks:ListNodegroups",
"account": accountID,
"region": region,
"cluster": clusterName,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "eks:ListNodegroups",
"account": accountID,
"region": region,
"cluster": clusterName,
"cache": "miss",
}).Info("AWS API call")
for {
ListNodeGroups, err := client.ListNodegroups(
context.TODO(),
@@ -129,8 +170,24 @@ func CachedEKSDescribeNodeGroup(client EKSClientInterface, accountID string, reg
cacheKey := fmt.Sprintf("%s-eks-DescribeNodeGroup-%s-%s-%s", accountID, region, clusterName, nodeGroupName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "eks:DescribeNodegroup",
"account": accountID,
"region": region,
"cluster": clusterName,
"nodeGroup": nodeGroupName,
"cache": "hit",
}).Info("AWS API call")
return cached.(eksTypes.Nodegroup), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "eks:DescribeNodegroup",
"account": accountID,
"region": region,
"cluster": clusterName,
"nodeGroup": nodeGroupName,
"cache": "miss",
}).Info("AWS API call")
nodeGroupOutput, err := client.DescribeNodegroup(
context.TODO(),
&eks.DescribeNodegroupInput{
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/elasticache"
elasticacheTypes "github.com/aws/aws-sdk-go-v2/service/elasticache/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSElastiCacheClientInterface interface {
@@ -26,8 +27,20 @@ func CachedElastiCacheDescribeCacheClusters(client AWSElastiCacheClientInterface
cacheKey := fmt.Sprintf("%s-elasticache-DescribeCacheClusters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "elasticache:DescribeCacheClusters",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]elasticacheTypes.CacheCluster), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "elasticache:DescribeCacheClusters",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeCacheClusters, err := client.DescribeCacheClusters(
context.TODO(),
+22
View File
@@ -3,9 +3,13 @@ package sdk
import (
"context"
"encoding/gob"
"fmt"
"github.com/BishopFox/cloudfox/internal"
"github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk"
elasticbeanstalkTypes "github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSElasticBeanstalkClientInterface interface {
@@ -18,6 +22,23 @@ func init() {
func CachedElasticBeanstalkDescribeApplications(client AWSElasticBeanstalkClientInterface, accountID string, region string) ([]elasticbeanstalkTypes.ApplicationDescription, error) {
var applications []elasticbeanstalkTypes.ApplicationDescription
cacheKey := fmt.Sprintf("%s-elasticbeanstalk-DescribeApplications-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "elasticbeanstalk:DescribeApplications",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]elasticbeanstalkTypes.ApplicationDescription), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "elasticbeanstalk:DescribeApplications",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
DescribeApplications, err := client.DescribeApplications(
context.TODO(),
&elasticbeanstalk.DescribeApplicationsInput{},
@@ -31,5 +52,6 @@ func CachedElasticBeanstalkDescribeApplications(client AWSElasticBeanstalkClient
}
applications = append(applications, DescribeApplications.Applications...)
internal.Cache.Set(cacheKey, applications, cache.DefaultExpiration)
return applications, nil
}
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing"
elbTypes "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type ELBClientInterface interface {
@@ -25,8 +26,20 @@ func CachedELBDescribeLoadBalancers(client ELBClientInterface, accountID string,
cacheKey := fmt.Sprintf("%s-elb-DescribeLoadBalancers-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "elb:DescribeLoadBalancers",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]elbTypes.LoadBalancerDescription), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "elb:DescribeLoadBalancers",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeLoadBalancers, err := client.DescribeLoadBalancers(
context.TODO(),
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
elbV2Types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type ELBv2ClientInterface interface {
@@ -25,8 +26,20 @@ func CachedELBv2DescribeLoadBalancers(client ELBv2ClientInterface, accountID str
cacheKey := fmt.Sprintf("%s-elbv2-DescribeLoadBalancers-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "elbv2:DescribeLoadBalancers",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]elbV2Types.LoadBalancer), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "elbv2:DescribeLoadBalancers",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeLoadBalancers, err := client.DescribeLoadBalancers(
context.TODO(),
+27
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/emr"
emrTypes "github.com/aws/aws-sdk-go-v2/service/emr/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSEMRClientInterface interface {
@@ -30,8 +31,20 @@ func CachedEMRListClusters(client AWSEMRClientInterface, accountID string, regio
cacheKey := fmt.Sprintf("%s-emr-ListClusters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "emr:ListClusters",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]emrTypes.ClusterSummary), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "emr:ListClusters",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListClusters, err := client.ListClusters(
context.TODO(),
@@ -66,8 +79,22 @@ func CachedEMRListInstances(client AWSEMRClientInterface, accountID string, regi
cacheKey := fmt.Sprintf("%s-emr-ListInstances-%s-%s", accountID, region, clusterID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "emr:ListInstances",
"account": accountID,
"region": region,
"clusterId": clusterID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]emrTypes.Instance), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "emr:ListInstances",
"account": accountID,
"region": region,
"clusterId": clusterID,
"cache": "miss",
}).Info("AWS API call")
for {
ListInstances, err := client.ListInstances(
context.TODO(),
+63 -5
View File
@@ -11,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/glue"
glueTypes "github.com/aws/aws-sdk-go-v2/service/glue/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSGlueClientInterface interface {
@@ -36,9 +37,20 @@ func CachedGlueListDevEndpoints(GlueClient AWSGlueClientInterface, accountID str
cacheKey := "glue-ListDevEndpoints-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached Glue dev endpoints data")
sharedLogger.WithFields(logrus.Fields{
"api": "glue:ListDevEndpoints",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "glue:ListDevEndpoints",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListDevEndpoints, err := GlueClient.ListDevEndpoints(
@@ -77,9 +89,20 @@ func CachedGlueListJobs(GlueClient AWSGlueClientInterface, accountID string, reg
cacheKey := "glue-ListJobs-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached Glue jobs data")
sharedLogger.WithFields(logrus.Fields{
"api": "glue:ListJobs",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "glue:ListJobs",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListJobs, err := GlueClient.ListJobs(
@@ -118,9 +141,22 @@ func CachedGlueGetTables(GlueClient AWSGlueClientInterface, accountID string, re
cacheKey := "glue-GetTables-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached Glue tables data")
sharedLogger.WithFields(logrus.Fields{
"api": "glue:GetTables",
"account": accountID,
"region": region,
"database": dbName,
"cache": "hit",
}).Info("AWS API call")
return cached.([]glueTypes.Table), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "glue:GetTables",
"account": accountID,
"region": region,
"database": dbName,
"cache": "miss",
}).Info("AWS API call")
for {
GetTables, err := GlueClient.GetTables(
@@ -160,9 +196,20 @@ func CachedGlueGetDatabases(GlueClient AWSGlueClientInterface, accountID string,
cacheKey := "glue-GetDatabases-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached Glue databases data")
sharedLogger.WithFields(logrus.Fields{
"api": "glue:GetDatabases",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]glueTypes.Database), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "glue:GetDatabases",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetDatabases, err := GlueClient.GetDatabases(
@@ -203,9 +250,20 @@ func CachedGlueGetResourcePolicies(GlueClient AWSGlueClientInterface, accountID
cacheKey := "glue-GetResourcePolicies-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached Glue resource policies data")
sharedLogger.WithFields(logrus.Fields{
"api": "glue:GetResourcePolicies",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]policy.Policy), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "glue:GetResourcePolicies",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
GetResourcePolicies, err := GlueClient.GetResourcePolicies(
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/grafana"
grafanaTypes "github.com/aws/aws-sdk-go-v2/service/grafana/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type GrafanaClientInterface interface {
@@ -25,8 +26,20 @@ func CachedGrafanaListWorkspaces(client GrafanaClientInterface, accountID string
cacheKey := fmt.Sprintf("%s-grafana-ListWorkspaces-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "grafana:ListWorkspaces",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]grafanaTypes.WorkspaceSummary), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "grafana:ListWorkspaces",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
+77
View File
@@ -13,6 +13,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/iam"
iamTypes "github.com/aws/aws-sdk-go-v2/service/iam/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSIAMClientInterface interface {
@@ -44,8 +45,18 @@ func CachedIamListUsers(IAMClient AWSIAMClientInterface, accountID string) ([]ia
cacheKey := fmt.Sprintf("%s-iam-ListUsers", accountID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "iam:ListUsers",
"account": accountID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]iamTypes.User), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "iam:ListUsers",
"account": accountID,
"cache": "miss",
}).Info("AWS API call")
for {
ListUsers, err := IAMClient.ListUsers(
@@ -81,8 +92,18 @@ func CachedIamListRoles(IAMClient AWSIAMClientInterface, accountID string) ([]ia
cacheKey := fmt.Sprintf("%s-iam-ListRoles", accountID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "iam:ListRoles",
"account": accountID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]iamTypes.Role), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "iam:ListRoles",
"account": accountID,
"cache": "miss",
}).Info("AWS API call")
for {
ListRoles, err := IAMClient.ListRoles(
@@ -118,8 +139,20 @@ func CachedIamListAccessKeys(IAMClient AWSIAMClientInterface, accountID string,
cacheKey := fmt.Sprintf("%s-iam-ListAccessKeys-%s", accountID, userName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "iam:ListAccessKeys",
"account": accountID,
"userName": userName,
"cache": "hit",
}).Info("AWS API call")
return cached.([]iamTypes.AccessKeyMetadata), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "iam:ListAccessKeys",
"account": accountID,
"userName": userName,
"cache": "miss",
}).Info("AWS API call")
for {
ListAccessKeys, err := IAMClient.ListAccessKeys(
@@ -172,8 +205,18 @@ func CachedIAMGetAccountAuthorizationDetails(IAMClient AWSIAMClientInterface, ac
cacheKey := fmt.Sprintf("%s-iam-GetAccountAuthorizationDetails", accountID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "iam:GetAccountAuthorizationDetails",
"account": accountID,
"cache": "hit",
}).Info("AWS API call")
return cached.(customGAADOutput), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "iam:GetAccountAuthorizationDetails",
"account": accountID,
"cache": "miss",
}).Info("AWS API call")
for {
GetAccountAuthorizationDetails, err := IAMClient.GetAccountAuthorizationDetails(
@@ -224,8 +267,20 @@ func CachedIamSimulatePrincipalPolicy(IAMClient AWSIAMClientInterface, accountID
cacheKey := fmt.Sprintf("%s-iamSimulator-%s-%s-%s", accountID, name, hex.EncodeToString(md5hashedActionNames[:truncatedHashLength]), hex.EncodeToString(md5hashedResourceArns[:truncatedHashLength]))
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "iam:SimulatePrincipalPolicy",
"account": accountID,
"principal": name,
"cache": "hit",
}).Info("AWS API call")
return cached.([]iamTypes.EvaluationResult), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "iam:SimulatePrincipalPolicy",
"account": accountID,
"principal": name,
"cache": "miss",
}).Info("AWS API call")
for {
SimulatePrincipalPolicy, err := IAMClient.SimulatePrincipalPolicy(
@@ -261,8 +316,18 @@ func CachedIamListGroups(IAMClient AWSIAMClientInterface, accountID string) ([]i
cacheKey := fmt.Sprintf("%s-iam-ListGroups", accountID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "iam:ListGroups",
"account": accountID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]iamTypes.Group), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "iam:ListGroups",
"account": accountID,
"cache": "miss",
}).Info("AWS API call")
for {
ListGroups, err := IAMClient.ListGroups(
@@ -296,9 +361,21 @@ func CachedIamGetInstanceProfile(IAMClient AWSIAMClientInterface, accountID stri
cacheKey := fmt.Sprintf("%s-iam-GetInstanceProfile-%s", accountID, instanceProfileName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "iam:GetInstanceProfile",
"account": accountID,
"profile": instanceProfileName,
"cache": "hit",
}).Info("AWS API call")
return cached.(iamTypes.InstanceProfile), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "iam:GetInstanceProfile",
"account": accountID,
"profile": instanceProfileName,
"cache": "miss",
}).Info("AWS API call")
GetInstanceProfile, err := IAMClient.GetInstanceProfile(
context.TODO(),
&iam.GetInstanceProfileInput{
+13
View File
@@ -8,6 +8,7 @@ import (
"github.com/BishopFox/cloudfox/internal"
"github.com/aws/aws-sdk-go-v2/service/kinesis"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSKinesisClientInterface interface {
@@ -24,8 +25,20 @@ func CachedKinesisListStreams(client AWSKinesisClientInterface, accountID string
cacheKey := fmt.Sprintf("%s-kinesis-ListStreams-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "kinesis:ListStreams",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "kinesis:ListStreams",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListStreams, err := client.ListStreams(
context.TODO(),
+107
View File
@@ -0,0 +1,107 @@
package sdk
import (
"context"
"encoding/gob"
"fmt"
"github.com/BishopFox/cloudfox/internal"
"github.com/BishopFox/cloudfox/internal/aws/policy"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/kms"
kmsTypes "github.com/aws/aws-sdk-go-v2/service/kms/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
// KMSClientInterface is an interface for the AWS SDK KMS client.
type KMSClientInterface interface {
ListKeys(context.Context, *kms.ListKeysInput, ...func(options *kms.Options)) (*kms.ListKeysOutput, error)
GetKeyPolicy(context.Context, *kms.GetKeyPolicyInput, ...func(options *kms.Options)) (*kms.GetKeyPolicyOutput, error)
}
func init() {
gob.Register([]kmsTypes.KeyListEntry{})
gob.Register(policy.Policy{})
}
// CachedKMSListKeys returns a list of KMS keys for the given account and region.
func CachedKMSListKeys(client KMSClientInterface, accountID string, region string) ([]kmsTypes.KeyListEntry, error) {
var keys []kmsTypes.KeyListEntry
cacheKey := fmt.Sprintf("%s-kms-ListKeys-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "kms:ListKeys",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]kmsTypes.KeyListEntry), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "kms:ListKeys",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
keyPaginator := kms.NewListKeysPaginator(client.(kms.ListKeysAPIClient), &kms.ListKeysInput{}, func(options *kms.ListKeysPaginatorOptions) {})
for keyPaginator.HasMorePages() {
output, err := keyPaginator.NextPage(context.TODO())
if err != nil {
return nil, err
}
for _, key := range output.Keys {
keys = append(keys, key)
}
}
internal.Cache.Set(cacheKey, keys, cache.DefaultExpiration)
return keys, nil
}
// CachedKMSGetKeyPolicy returns the policy for the given KMS key.
func CachedKMSGetKeyPolicy(client KMSClientInterface, accountID string, region string, keyID string) (policy.Policy, error) {
var keyPolicy policy.Policy
var policyJson string
cacheKey := fmt.Sprintf("%s-kms-GetKeyPolicy-%s-%s", accountID, region, keyID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "kms:GetKeyPolicy",
"account": accountID,
"region": region,
"keyId": keyID,
"cache": "hit",
}).Info("AWS API call")
return cached.(policy.Policy), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "kms:GetKeyPolicy",
"account": accountID,
"region": region,
"keyId": keyID,
"cache": "miss",
}).Info("AWS API call")
getKeyPolicy, err := client.GetKeyPolicy(
context.TODO(),
&kms.GetKeyPolicyInput{
KeyId: &keyID,
},
)
if err != nil {
return keyPolicy, err
}
policyJson = aws.ToString(getKeyPolicy.Policy)
keyPolicy, err = policy.ParseJSONPolicy([]byte(policyJson))
if err != nil {
return keyPolicy, fmt.Errorf("parsing policy (%s) as JSON: %s", keyID, err)
}
internal.Cache.Set(cacheKey, keyPolicy, cache.DefaultExpiration)
return keyPolicy, nil
}
+42
View File
@@ -0,0 +1,42 @@
package sdk
import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/kms"
kmsTypes "github.com/aws/aws-sdk-go-v2/service/kms/types"
)
type MockedKMSClient struct {
}
func (m *MockedKMSClient) ListKeys(ctx context.Context, input *kms.ListKeysInput, options ...func(*kms.Options)) (*kms.ListKeysOutput, error) {
return &kms.ListKeysOutput{
Keys: []kmsTypes.KeyListEntry{
{
KeyId: aws.String("key1"),
KeyArn: aws.String("arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab"),
},
},
}, nil
}
func (m *MockedKMSClient) GetKeyPolicy(ctx context.Context, input *kms.GetKeyPolicyInput, options ...func(options *kms.Options)) (*kms.GetKeyPolicyOutput, error) {
return &kms.GetKeyPolicyOutput{
Policy: aws.String(`{
"Version": "2012-10-17",
"Id": "key-default-1",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "kms:*",
"Resource": "*"
}
]
}`),
}, nil
}
+27
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/lambda"
lambdaTypes "github.com/aws/aws-sdk-go-v2/service/lambda/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type LambdaClientInterface interface {
@@ -29,8 +30,20 @@ func CachedLambdaListFunctions(client LambdaClientInterface, accountID string, r
cacheKey := fmt.Sprintf("%s-lambda-ListFunctions-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "lambda:ListFunctions",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]lambdaTypes.FunctionConfiguration), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "lambda:ListFunctions",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListFunctions, err := client.ListFunctions(
@@ -114,8 +127,22 @@ func CachedLambdaGetFunctionUrlConfig(client LambdaClientInterface, accountID st
cacheKey := fmt.Sprintf("%s-lambda-GetFunctionUrlConfig-%s-%s", accountID, region, functionName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "lambda:GetFunctionUrlConfig",
"account": accountID,
"region": region,
"function": functionName,
"cache": "hit",
}).Info("AWS API call")
return cached.(customGetFuntionURLOutput), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "lambda:GetFunctionUrlConfig",
"account": accountID,
"region": region,
"function": functionName,
"cache": "miss",
}).Info("AWS API call")
GetFunctionUrlConfig, err := client.GetFunctionUrlConfig(
context.TODO(),
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/lightsail"
lightsailTypes "github.com/aws/aws-sdk-go-v2/service/lightsail/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type lightsailClientInterface interface {
@@ -69,8 +70,20 @@ func CachedLightsailGetContainerServices(client lightsailClientInterface, accoun
cacheKey := fmt.Sprintf("%s-lightsail-GetContainerService-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "lightsail:GetContainerServices",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]lightsailTypes.ContainerService), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "lightsail:GetContainerServices",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
GetInstances, err := client.GetContainerServices(
context.TODO(),
&lightsail.GetContainerServicesInput{},
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/mq"
mqTypes "github.com/aws/aws-sdk-go-v2/service/mq/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type MQClientInterface interface {
@@ -26,8 +27,20 @@ func CachedMQListBrokers(client MQClientInterface, accountID string, region stri
cacheKey := fmt.Sprintf("%s-mq-ListBrokers-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "mq:ListBrokers",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]mqTypes.BrokerSummary), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "mq:ListBrokers",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListBrokers, err := client.ListBrokers(
+47 -3
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/opensearch"
openSearchTypes "github.com/aws/aws-sdk-go-v2/service/opensearch/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type OpenSearchClientInterface interface {
@@ -23,14 +24,26 @@ func init() {
gob.Register(openSearchTypes.DomainStatus{})
}
// create CachedOpenSearchListDomainNames function that uses go-cache and pagination
// CachedOpenSearchListDomainNames function that uses go-cache and pagination
func CachedOpenSearchListDomainNames(client OpenSearchClientInterface, accountID string, region string) ([]openSearchTypes.DomainInfo, error) {
var domains []openSearchTypes.DomainInfo
cacheKey := fmt.Sprintf("%s-opensearch-ListDomainNames-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "opensearch:ListDomainNames",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]openSearchTypes.DomainInfo), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "opensearch:ListDomainNames",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
ListDomainNames, err := client.ListDomainNames(
context.TODO(),
@@ -50,14 +63,31 @@ func CachedOpenSearchListDomainNames(client OpenSearchClientInterface, accountID
return domains, nil
}
// create CachedOpenSearchDescribeDomainConfig function that uses go-cache and pagination and supports region option
// CachedOpenSearchDescribeDomainConfig function that uses go-cache and pagination and supports region option
func CachedOpenSearchDescribeDomainConfig(client OpenSearchClientInterface, accountID string, region string, domainName string) (openSearchTypes.DomainConfig, error) {
fmt.Printf("CachedOpenSearchDescribeDomainConfig: %s %s %s\n", accountID, region, domainName)
var DomainConfig openSearchTypes.DomainConfig
cacheKey := fmt.Sprintf("%s-opensearch-DescribeDomainConfig-%s-%s", accountID, region, domainName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "opensearch:DescribeDomainConfig",
"account": accountID,
"region": region,
"domain": domainName,
"cache": "hit",
}).Info("AWS API call")
return cached.(openSearchTypes.DomainConfig), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "opensearch:DescribeDomainConfig",
"account": accountID,
"region": region,
"domain": domainName,
"cache": "miss",
}).Info("AWS API call")
DescribeDomainConfig, err := client.DescribeDomainConfig(
context.TODO(),
&opensearch.DescribeDomainConfigInput{
@@ -78,14 +108,28 @@ func CachedOpenSearchDescribeDomainConfig(client OpenSearchClientInterface, acco
return DomainConfig, nil
}
// create CachedOpenSearchDescribeDomain function that uses go-cache and pagination and supports region option
// CachedOpenSearchDescribeDomain function that uses go-cache and pagination and supports region option
func CachedOpenSearchDescribeDomain(client OpenSearchClientInterface, accountID string, region string, domainName string) (openSearchTypes.DomainStatus, error) {
var DomainStatus openSearchTypes.DomainStatus
cacheKey := fmt.Sprintf("%s-opensearch-DescribeDomain-%s-%s", accountID, region, domainName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "opensearch:DescribeDomain",
"account": accountID,
"region": region,
"domain": domainName,
"cache": "hit",
}).Info("AWS API call")
return cached.(openSearchTypes.DomainStatus), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "opensearch:DescribeDomain",
"account": accountID,
"region": region,
"domain": domainName,
"cache": "miss",
}).Info("AWS API call")
DescribeDomain, err := client.DescribeDomain(
context.TODO(),
&opensearch.DescribeDomainInput{
+54 -6
View File
@@ -27,8 +27,8 @@ func (m *MockedOpenSearchClient) ListDomainNames(ctx context.Context, input *ope
}
func (m *MockedOpenSearchClient) DescribeDomainConfig(ctx context.Context, input *opensearch.DescribeDomainConfigInput, options ...func(*opensearch.Options)) (*opensearch.DescribeDomainConfigOutput, error) {
return &opensearch.DescribeDomainConfigOutput{
DomainConfig: &openSearchTypes.DomainConfig{
domainConfigMap := map[string]*openSearchTypes.DomainConfig{
"domain1": {
EngineVersion: &openSearchTypes.VersionStatus{
Options: aws.String("OpenSearch-1.1"),
Status: &openSearchTypes.OptionStatus{
@@ -49,15 +49,63 @@ func (m *MockedOpenSearchClient) DescribeDomainConfig(ctx context.Context, input
EnforceHTTPS: aws.Bool(true),
},
},
AdvancedSecurityOptions: &openSearchTypes.AdvancedSecurityOptionsStatus{
Options: &openSearchTypes.AdvancedSecurityOptions{
Enabled: aws.Bool(true),
},
},
},
"domain2": {
EngineVersion: &openSearchTypes.VersionStatus{
Options: aws.String("OpenSearch-1.1"),
Status: &openSearchTypes.OptionStatus{
PendingDeletion: aws.Bool(false),
},
},
ClusterConfig: &openSearchTypes.ClusterConfigStatus{
Options: &openSearchTypes.ClusterConfig{
DedicatedMasterCount: aws.Int32(3),
DedicatedMasterEnabled: aws.Bool(true),
InstanceCount: aws.Int32(3),
WarmCount: aws.Int32(3),
WarmEnabled: aws.Bool(true),
},
},
DomainEndpointOptions: &openSearchTypes.DomainEndpointOptionsStatus{
Options: &openSearchTypes.DomainEndpointOptions{
EnforceHTTPS: aws.Bool(true),
},
},
AdvancedSecurityOptions: &openSearchTypes.AdvancedSecurityOptionsStatus{
Options: &openSearchTypes.AdvancedSecurityOptions{
Enabled: aws.Bool(false),
},
},
},
}
return &opensearch.DescribeDomainConfigOutput{
DomainConfig: domainConfigMap[*input.DomainName],
}, nil
}
func (m *MockedOpenSearchClient) DescribeDomain(ctx context.Context, input *opensearch.DescribeDomainInput, options ...func(*opensearch.Options)) (*opensearch.DescribeDomainOutput, error) {
return &opensearch.DescribeDomainOutput{
DomainStatus: &openSearchTypes.DomainStatus{
DomainName: aws.String("domain1"),
Endpoint: aws.String("https://domain1.us-east-1.es.amazonaws.com"),
domainStatusMap := map[string]*openSearchTypes.DomainStatus{
"domain1": {
DomainName: aws.String("domain1"),
Endpoint: aws.String("https://domain1.us-east-1.es.amazonaws.com"),
ARN: aws.String("arn:aws:es:us-east-1:123456789012:domain/domain1"),
AccessPolicies: aws.String(`{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":[\"es:ESHttpGet\",\"es:ESHttpHead\",\"es:ESHttpPost\"],\"Resource\":\"*\",\"Condition\":{\"IpAddress\":{\"aws:SourceIp\":\"192.168.1.100/32\"}}}]}`),
},
"domain2": {
DomainName: aws.String("domain2"),
Endpoint: aws.String("https://domain2.us-east-1.es.amazonaws.com"),
ARN: aws.String("arn:aws:es:us-east-1:123456789012:domain/domain2"),
AccessPolicies: aws.String(`{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":[\"es:ESHttpGet\",\"es:ESHttpHead\",\"es:ESHttpPost\"],\"Resource\":\"*\"}]}`),
},
}
return &opensearch.DescribeDomainOutput{
DomainStatus: domainStatusMap[*input.DomainName],
}, nil
}
+21
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/organizations"
orgTypes "github.com/aws/aws-sdk-go-v2/service/organizations/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type OrganizationsClientInterface interface {
@@ -28,8 +29,18 @@ func CachedOrganizationsListAccounts(client OrganizationsClientInterface, accoun
cacheKey := fmt.Sprintf("%s-organizations-ListAccounts", accountID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "organizations:ListAccounts",
"account": accountID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]orgTypes.Account), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "organizations:ListAccounts",
"account": accountID,
"cache": "miss",
}).Info("AWS API call")
for {
ListAccounts, err := client.ListAccounts(
@@ -62,8 +73,18 @@ func CachedOrganizationsDescribeOrganization(client OrganizationsClientInterface
cacheKey := fmt.Sprintf("%s-organizations-DescribeOrganization", accountID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "organizations:DescribeOrganization",
"account": accountID,
"cache": "hit",
}).Info("AWS API call")
return cached.(*orgTypes.Organization), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "organizations:DescribeOrganization",
"account": accountID,
"cache": "miss",
}).Info("AWS API call")
DescribeOrganization, err := client.DescribeOrganization(
context.TODO(),
+25
View File
@@ -8,6 +8,7 @@ import (
"github.com/BishopFox/cloudfox/internal"
"github.com/aws/aws-sdk-go-v2/service/rds"
rdsTypes "github.com/aws/aws-sdk-go-v2/service/rds/types"
"github.com/sirupsen/logrus"
"github.com/patrickmn/go-cache"
)
@@ -29,8 +30,20 @@ func CachedRDSDescribeDBInstances(client RDSClientInterface, accountID string, r
cacheKey := fmt.Sprintf("%s-rds-DescribeDBInstances-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "rds:DescribeDBInstances",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]rdsTypes.DBInstance), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "rds:DescribeDBInstances",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeDBInstances, err := client.DescribeDBInstances(
context.TODO(),
@@ -65,8 +78,20 @@ func CachedRDSDescribeDBClusters(client RDSClientInterface, accountID string, re
cacheKey := fmt.Sprintf("%s-rds-DescribeDBClusters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "rds:DescribeDBClusters",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]rdsTypes.DBCluster), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "rds:DescribeDBClusters",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeDBClusters, err := client.DescribeDBClusters(
context.TODO(),
+8
View File
@@ -21,6 +21,10 @@ func (m *MockedRDSClient) DescribeDBInstances(ctx context.Context, input *rds.De
EngineVersion: aws.String("13.3"),
InstanceCreateTime: aws.Time(time.Now()),
MasterUsername: aws.String("postgres"),
Endpoint: &rdsTypes.Endpoint{
Address: aws.String("db1-instances-1.blah.us-west-2.rds.amazonaws.com"),
Port: aws.Int32(5432),
},
},
{
DBInstanceIdentifier: aws.String("db2"),
@@ -28,6 +32,10 @@ func (m *MockedRDSClient) DescribeDBInstances(ctx context.Context, input *rds.De
EngineVersion: aws.String("13.3"),
InstanceCreateTime: aws.Time(time.Now()),
MasterUsername: aws.String("postgres"),
Endpoint: &rdsTypes.Endpoint{
Address: aws.String("db2-instances-1.blah.us-west-2.rds.amazonaws.com"),
Port: aws.Int32(5432),
},
},
},
}, nil
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/redshift"
redshiftTypes "github.com/aws/aws-sdk-go-v2/service/redshift/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSRedShiftClientInterface interface {
@@ -26,8 +27,20 @@ func CachedRedShiftDescribeClusters(client AWSRedShiftClientInterface, accountID
cacheKey := fmt.Sprintf("%s-redshift-DescribeClusters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "redshift:DescribeClusters",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]redshiftTypes.Cluster), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "redshift:DescribeClusters",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeClusters, err := client.DescribeClusters(
context.TODO(),
+23
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/route53"
route53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSRoute53ClientInterface interface {
@@ -28,8 +29,18 @@ func CachedRoute53ListHostedZones(client AWSRoute53ClientInterface, accountID st
cacheKey := fmt.Sprintf("%s-route53-ListHostedZones", accountID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "route53:ListHostedZones",
"account": accountID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]route53types.HostedZone), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "route53:ListHostedZones",
"account": accountID,
"cache": "miss",
}).Info("AWS API call")
for {
ListHostedZones, err := client.ListHostedZones(
@@ -63,8 +74,20 @@ func CachedRoute53ListResourceRecordSets(client AWSRoute53ClientInterface, accou
cacheKey := fmt.Sprintf("%s-route53-ListResourceRecordSets-%s", accountID, hostedZoneID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "route53:ListResourceRecordSets",
"account": accountID,
"hostedZoneId": hostedZoneID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]route53types.ResourceRecordSet), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "route53:ListResourceRecordSets",
"account": accountID,
"hostedZoneId": hostedZoneID,
"cache": "miss",
}).Info("AWS API call")
for {
ListResourceRecordSets, err := client.ListResourceRecordSets(
+51 -4
View File
@@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
s3Types "github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSS3ClientInterface interface {
@@ -30,10 +31,19 @@ func CachedListBuckets(S3Client AWSS3ClientInterface, accountID string) ([]s3Typ
cacheKey := fmt.Sprintf("%s-s3-ListBuckets", accountID)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached data for ListBuckets data")
sharedLogger.WithFields(logrus.Fields{
"api": "s3:ListBuckets",
"account": accountID,
"cache": "hit",
}).Info("AWS API call")
return cached.([]s3Types.Bucket), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "s3:ListBuckets",
"account": accountID,
"cache": "miss",
}).Info("AWS API call")
ListBuckets, err := S3Client.ListBuckets(
context.TODO(),
&s3.ListBucketsInput{},
@@ -52,9 +62,20 @@ func CachedGetBucketLocation(S3Client AWSS3ClientInterface, accountID string, bu
cacheKey := fmt.Sprintf("%s-s3-GetBucketLocation-%s", accountID, bucketName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached data for GetBucketLocation data")
sharedLogger.WithFields(logrus.Fields{
"api": "s3:GetBucketLocation",
"account": accountID,
"bucket": bucketName,
"cache": "hit",
}).Info("AWS API call")
return cached.(string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "s3:GetBucketLocation",
"account": accountID,
"bucket": bucketName,
"cache": "miss",
}).Info("AWS API call")
GetBucketRegion, err := S3Client.GetBucketLocation(
context.TODO(),
&s3.GetBucketLocationInput{
@@ -76,9 +97,22 @@ func CachedGetBucketPolicy(S3Client AWSS3ClientInterface, accountID string, r st
cacheKey := fmt.Sprintf("%s-s3-GetBucketPolicy-%s-%s", accountID, r, bucketName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached data for GetBucketPolicy data")
sharedLogger.WithFields(logrus.Fields{
"api": "s3:GetBucketPolicy",
"account": accountID,
"region": r,
"bucket": bucketName,
"cache": "hit",
}).Info("AWS API call")
return cached.(string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "s3:GetBucketPolicy",
"account": accountID,
"region": r,
"bucket": bucketName,
"cache": "miss",
}).Info("AWS API call")
BucketPolicyObject, err := S3Client.GetBucketPolicy(
context.TODO(),
@@ -103,9 +137,22 @@ func CachedGetPublicAccessBlock(S3Client AWSS3ClientInterface, accountID string,
cacheKey := fmt.Sprintf("%s-s3-GetPublicAccessBlock-%s-%s", accountID, r, bucketName)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached data for GetPublicAccessBlock data")
sharedLogger.WithFields(logrus.Fields{
"api": "s3:GetPublicAccessBlock",
"account": accountID,
"region": r,
"bucket": bucketName,
"cache": "hit",
}).Info("AWS API call")
return cached.(*s3Types.PublicAccessBlockConfiguration), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "s3:GetPublicAccessBlock",
"account": accountID,
"region": r,
"bucket": bucketName,
"cache": "miss",
}).Info("AWS API call")
PublicAccessBlock, err := S3Client.GetPublicAccessBlock(
context.TODO(),
+27
View File
@@ -11,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
secretsmanagerTypes "github.com/aws/aws-sdk-go-v2/service/secretsmanager/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type SecretsManagerClientInterface interface {
@@ -30,8 +31,20 @@ func CachedSecretsManagerListSecrets(client SecretsManagerClientInterface, accou
cacheKey := fmt.Sprintf("%s-secretsmanager-ListSecrets-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "secretsmanager:ListSecrets",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]secretsmanagerTypes.SecretListEntry), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "secretsmanager:ListSecrets",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListSecrets, err := client.ListSecrets(
context.TODO(),
@@ -66,8 +79,22 @@ func CachedSecretsManagerGetResourcePolicy(client SecretsManagerClientInterface,
cacheKey := fmt.Sprintf("%s-secretsmanager-GetResourcePolicy-%s-%s", accountID, region, secretId)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "secretsmanager:GetResourcePolicy",
"account": accountID,
"region": region,
"secretId": secretId,
"cache": "hit",
}).Info("AWS API call")
return cached.(policy.Policy), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "secretsmanager:GetResourcePolicy",
"account": accountID,
"region": region,
"secretId": secretId,
"cache": "miss",
}).Info("AWS API call")
GetResourcePolicy, err := client.GetResourcePolicy(
context.TODO(),
&secretsmanager.GetResourcePolicyInput{
+57 -4
View File
@@ -8,6 +8,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/sns"
snsTypes "github.com/aws/aws-sdk-go-v2/service/sns/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSSNSClientInterface interface {
@@ -29,10 +30,22 @@ func CachedSNSListTopics(SNSClient AWSSNSClientInterface, accountID string, regi
cacheKey := "sns-ListTopics-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached SNS topics data")
sharedLogger.WithFields(logrus.Fields{
"api": "sns:ListTopics",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "sns:ListTopics",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListTopics, err := SNSClient.ListTopics(
context.TODO(),
@@ -72,10 +85,22 @@ func CachedSNSListSubscriptions(SNSClient AWSSNSClientInterface, accountID strin
cacheKey := "sns-ListSubscriptions-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached SNS subscriptions data")
sharedLogger.WithFields(logrus.Fields{
"api": "sns:ListSubscriptions",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "sns:ListSubscriptions",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListSubscriptions, err := SNSClient.ListSubscriptions(
context.TODO(),
@@ -115,10 +140,24 @@ func CachedSNSListSubscriptionsByTopic(SNSClient AWSSNSClientInterface, accountI
cacheKey := "sns-ListSubscriptionsByTopic-" + accountID + "-" + region + "-" + topicArn
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached SNS subscriptions data")
sharedLogger.WithFields(logrus.Fields{
"api": "sns:ListSubscriptionsByTopic",
"account": accountID,
"region": region,
"topicArn": topicArn,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "sns:ListSubscriptionsByTopic",
"account": accountID,
"region": region,
"topicArn": topicArn,
"cache": "miss",
}).Info("AWS API call")
for {
ListSubscriptionsByTopic, err := SNSClient.ListSubscriptionsByTopic(
context.TODO(),
@@ -157,10 +196,24 @@ func CachedSNSGetTopicAttributes(SNSClient AWSSNSClientInterface, accountID stri
cacheKey := "sns-GetTopicAttributes-" + accountID + "-" + region + "-" + topicArn
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached SNS topic attributes data")
sharedLogger.WithFields(logrus.Fields{
"api": "sns:GetTopicAttributes",
"account": accountID,
"region": region,
"topicArn": topicArn,
"cache": "hit",
}).Info("AWS API call")
return cached.(map[string]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "sns:GetTopicAttributes",
"account": accountID,
"region": region,
"topicArn": topicArn,
"cache": "miss",
}).Info("AWS API call")
GetTopicAttributes, err := SNSClient.GetTopicAttributes(
context.TODO(),
&sns.GetTopicAttributesInput{
+13 -1
View File
@@ -7,6 +7,7 @@ import (
"github.com/BishopFox/cloudfox/internal"
"github.com/aws/aws-sdk-go-v2/service/sqs"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSSQSClientInterface interface {
@@ -23,9 +24,20 @@ func CachedSQSListQueues(SQSClient AWSSQSClientInterface, accountID string, regi
cacheKey := "sqs-ListQueues-" + accountID + "-" + region
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached SQS queues data")
sharedLogger.WithFields(logrus.Fields{
"api": "sqs:ListQueues",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]string), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "sqs:ListQueues",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListQueues, err := SQSClient.ListQueues(
+13 -1
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/ssm"
"github.com/aws/aws-sdk-go-v2/service/ssm/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type AWSSSMClientInterface interface {
@@ -26,9 +27,20 @@ func CachedSSMDescribeParameters(SSMClient AWSSSMClientInterface, accountID stri
cacheKey := fmt.Sprintf("%s-ssm-DescribeParameters-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.Debug("Using cached SSM parameters data")
sharedLogger.WithFields(logrus.Fields{
"api": "ssm:DescribeParameters",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]types.ParameterMetadata), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "ssm:DescribeParameters",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
DescribeParameters, err := SSMClient.DescribeParameters(
+13
View File
@@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/sfn"
sfnTypes "github.com/aws/aws-sdk-go-v2/service/sfn/types"
"github.com/patrickmn/go-cache"
"github.com/sirupsen/logrus"
)
type StepFunctionsClientInterface interface {
@@ -25,8 +26,20 @@ func CachedStepFunctionsListStateMachines(client StepFunctionsClientInterface, a
cacheKey := fmt.Sprintf("%s-stepfunctions-ListStateMachines-%s", accountID, region)
cached, found := internal.Cache.Get(cacheKey)
if found {
sharedLogger.WithFields(logrus.Fields{
"api": "states:ListStateMachines",
"account": accountID,
"region": region,
"cache": "hit",
}).Info("AWS API call")
return cached.([]sfnTypes.StateMachineListItem), nil
}
sharedLogger.WithFields(logrus.Fields{
"api": "states:ListStateMachines",
"account": accountID,
"region": region,
"cache": "miss",
}).Info("AWS API call")
for {
ListStateMachines, err := client.ListStateMachines(
context.TODO(),
+7 -2
View File
@@ -30,6 +30,7 @@ type SecretsModule struct {
WrapTable bool
AWSOutputType string
AWSTableCols string
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
Secrets []Secret
@@ -192,8 +193,12 @@ func (m *SecretsModule) Receiver(receiver chan Secret, receiverDone chan bool) {
func (m *SecretsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Secret) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("secretsmanager", r)
if err != nil {
+8 -8
View File
@@ -100,19 +100,19 @@ func generatePmapperDataBasePaths(accountId *string) (string, string) {
if err != nil {
log.Fatal("Could not get homedir")
}
edgesPath = fmt.Sprintf(dir + "/Library/Application Support/com.nccgroup.principalmapper/" + aws.ToString(accountId) + "/graph/edges.json")
nodesPath = fmt.Sprintf(dir + "/Library/Application Support/com.nccgroup.principalmapper/" + aws.ToString(accountId) + "/graph/nodes.json")
edgesPath = fmt.Sprintf("%s/Library/Application Support/com.nccgroup.principalmapper/%s/graph/edges.json", dir, aws.ToString(accountId))
nodesPath = fmt.Sprintf("%s/Library/Application Support/com.nccgroup.principalmapper/%s/graph/nodes.json", dir, aws.ToString(accountId))
} else if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" {
xdg, ok := os.LookupEnv("XDG_DATA_HOME")
if ok {
edgesPath = fmt.Sprintf(xdg + aws.ToString(accountId) + "/graph/edges.json")
nodesPath = fmt.Sprintf(xdg + aws.ToString(accountId) + "/graph/nodes.json")
edgesPath = fmt.Sprintf("%s%s/graph/edges.json", xdg, aws.ToString(accountId))
nodesPath = fmt.Sprintf("%s%s/graph/nodes.json", xdg, aws.ToString(accountId))
} else {
dir, err := os.UserHomeDir()
if err == nil {
edgesPath = fmt.Sprintf(dir + "/.local/share/principalmapper/" + aws.ToString(accountId) + "/graph/edges.json")
nodesPath = fmt.Sprintf(dir + "/.local/share/principalmapper/" + aws.ToString(accountId) + "/graph/nodes.json")
edgesPath = fmt.Sprintf("%s/.local/share/principalmapper/%s/graph/edges.json", dir, aws.ToString(accountId))
nodesPath = fmt.Sprintf("%s/.local/share/principalmapper/%s/graph/nodes.json", dir, aws.ToString(accountId))
} else {
log.Fatal("Could not homedir.")
}
@@ -123,8 +123,8 @@ func generatePmapperDataBasePaths(accountId *string) (string, string) {
if err != nil {
log.Fatal("Could not get userconfigdir")
}
edgesPath = fmt.Sprintf(dir + "\\principalmapper" + aws.ToString(accountId) + "\\graph\\edges.json")
nodesPath = fmt.Sprintf(dir + "\\principalmapper" + aws.ToString(accountId) + "\\graph\\nodes.json")
edgesPath = fmt.Sprintf("%s\\principalmapper%s\\graph\\edges.json", dir, aws.ToString(accountId))
nodesPath = fmt.Sprintf("%s\\principalmapper%s\\graph\\nodes.json", dir, aws.ToString(accountId))
}
+7 -2
View File
@@ -34,6 +34,7 @@ type SNSModule struct {
Goroutines int
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
Topics []SNSTopic
@@ -192,8 +193,12 @@ func (m *SNSModule) PrintSNS(outputDirectory string, verbosity int) {
func (m *SNSModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan SNSTopic) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("sns", r)
if err != nil {
+7 -2
View File
@@ -36,6 +36,7 @@ type SQSModule struct {
Goroutines int
AWSProfile string
WrapTable bool
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
Queues []Queue
@@ -194,8 +195,12 @@ func (m *SQSModule) PrintSQS(outputDirectory string, verbosity int) {
func (m *SQSModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Queue) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, err := servicemap.IsServiceInRegion("sqs", r)
if err != nil {
+8 -4
View File
@@ -3,7 +3,6 @@ package aws
import (
"context"
"fmt"
"log"
"path/filepath"
"sort"
"strconv"
@@ -46,6 +45,7 @@ type WorkloadsModule struct {
iamSimClient IamSimulatorModule
InstanceProfileToRolesMap map[string][]iamTypes.Role
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
Workloads []Workload
@@ -271,8 +271,12 @@ func (m *WorkloadsModule) Receiver(receiver chan Workload, receiverDone chan boo
func (m *WorkloadsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Workload) {
defer wg.Done()
servicemap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
// Use shared ServiceMap instance if provided, otherwise create a new one
servicemap := m.ServiceMap
if servicemap == nil {
servicemap = &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
}
res, _ := servicemap.IsServiceInRegion("ec2", r)
@@ -345,7 +349,7 @@ func (m *WorkloadsModule) getEC2WorkloadsPerRegion(r string, wg *sync.WaitGroup,
// Describe the IAM instance profile
profileOutput, err := sdk.CachedIamGetInstanceProfile(m.IAMClient, aws.ToString(m.Caller.Account), profileName)
if err != nil {
log.Printf("failed to get instance profile for %s, %v", profileArn, err)
m.modLog.Errorf("failed to get instance profile for %s, %v", profileArn, err)
continue
}
+243 -118
View File
@@ -2,11 +2,13 @@ package cli
import (
"encoding/gob"
"errors"
"fmt"
"log"
"os"
"path/filepath"
"github.com/aws/aws-sdk-go-v2/service/kms"
"github.com/BishopFox/cloudfox/aws"
"github.com/BishopFox/cloudfox/aws/sdk"
"github.com/BishopFox/cloudfox/internal"
@@ -60,6 +62,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/sqs"
"github.com/aws/aws-sdk-go-v2/service/ssm"
"github.com/aws/smithy-go/ptr"
"github.com/bishopfox/awsservicemap"
"github.com/bishopfox/knownawsaccountslookup"
"github.com/dominikbraun/graph"
"github.com/fatih/color"
@@ -138,9 +141,10 @@ var (
PostRun: awsPostRun,
}
CapeAdminOnly bool
CapeJobName string
CapeCommand = &cobra.Command{
CapeAdminOnly bool
CapeArnIgnoreList string
CapeJobName string
CapeCommand = &cobra.Command{
Use: "cape",
Aliases: []string{"CAPE"},
Short: "Cross-Account Privilege Escalation Route finder. Needs to be run with multiple profiles using -l or -a flag. Needs pmapper data to be present",
@@ -263,10 +267,11 @@ var (
PostRun: awsPostRun,
}
SimulatorResource string
SimulatorAction string
SimulatorPrincipal string
IamSimulatorCommand = &cobra.Command{
SimulatorResource string
SimulatorAction string
SimulatorPrincipal string
IamSimulatorAdminCheckOnly bool
IamSimulatorCommand = &cobra.Command{
Use: "iam-simulator",
Aliases: []string{"iamsimulator", "simulator"},
Short: "Wrapper around the AWS IAM Simulate Principal Policy command",
@@ -405,7 +410,8 @@ var (
PostRun: awsPostRun,
}
ResourceTrustsCommand = &cobra.Command{
ResourceTrustsIncludeKms bool
ResourceTrustsCommand = &cobra.Command{
Use: "resource-trusts",
Aliases: []string{"resourcetrusts", "resourcetrust"},
Short: "Enumerate all resource trusts",
@@ -519,7 +525,7 @@ var (
func initAWSProfiles() {
// Ensure only one profile setting is chosen
if AWSProfile != "" && AWSProfilesList != "" || AWSProfile != "" && AWSAllProfiles || AWSProfilesList != "" && AWSAllProfiles {
log.Fatalf("[-] Error specifying AWS profiles. Choose only one of -p/--profile, -a/--all-profiles, -l/--profiles-list")
internal.TxtLog.Fatalf("[-] Error specifying AWS profiles. Choose only one of -p/--profile, -a/--all-profiles, -l/--profiles-list")
} else if AWSProfile != "" {
AWSProfiles = append(AWSProfiles, AWSProfile)
} else if AWSProfilesList != "" {
@@ -564,7 +570,7 @@ func awsPreRun(cmd *cobra.Command, args []string) {
cacheDirectory := filepath.Join(AWSOutputDirectory, "cached-data", "aws", ptr.ToString(caller.Account))
err = internal.LoadCacheFromGobFiles(cacheDirectory)
if err != nil {
if err == internal.ErrDirectoryDoesNotExist {
if errors.Is(err, internal.ErrDirectoryDoesNotExist) {
fmt.Printf("[%s][%s] No cache directory for %s. Skipping loading cached data.\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", cmd.Root().Version)), cyan(profile), ptr.ToString(caller.Account))
} else {
fmt.Printf("[%s][%s] No cache data for %s. Error: %v\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", cmd.Root().Version)), cyan(profile), ptr.ToString(caller.Account), err)
@@ -606,11 +612,11 @@ func awsPostRun(cmd *cobra.Command, args []string) {
outputDirectory := filepath.Join(AWSOutputDirectory, "cached-data", "aws", ptr.ToString(caller.Account))
err = internal.SaveCacheToGobFiles(outputDirectory, *caller.Account)
if err != nil {
log.Fatalf("failed to save cache: %v", err)
internal.TxtLog.Fatalf("failed to save cache: %v", err)
}
err = internal.SaveCacheToFiles(outputDirectory, *caller.Account)
if err != nil {
log.Fatalf("failed to save cache: %v", err)
internal.TxtLog.Fatalf("failed to save cache: %v", err)
}
fmt.Printf("[%s][%s] Cached AWS data written to %s\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", cmd.Root().Version)), cyan(profile), outputDirectory)
@@ -631,7 +637,7 @@ func FindOrgMgmtAccountAndReorderAccounts(AWSProfiles []string, version string)
cacheDirectory := filepath.Join(AWSOutputDirectory, "cached-data", "aws", ptr.ToString(caller.Account))
err = internal.LoadCacheFromGobFiles(cacheDirectory)
if err != nil {
if err == internal.ErrDirectoryDoesNotExist {
if errors.Is(err, internal.ErrDirectoryDoesNotExist) {
fmt.Printf("[%s][%s] No cache directory for %s. Skipping loading cached data.\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", version)), cyan(profile), ptr.ToString(caller.Account))
} else {
fmt.Printf("[%s][%s] No cache data for %s. Error: %v\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", version)), cyan(profile), ptr.ToString(caller.Account), err)
@@ -682,6 +688,9 @@ func runAccessKeysCommand(cmd *cobra.Command, args []string) {
func runApiGwCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
continue
@@ -695,6 +704,7 @@ func runApiGwCommand(cmd *cobra.Command, args []string) {
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
ServiceMap: sharedServiceMap,
}
m.PrintApiGws(AWSOutputDirectory, Verbosity)
}
@@ -725,6 +735,9 @@ func runBucketsCommand(cmd *cobra.Command, args []string) {
func runCloudformationCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -739,6 +752,7 @@ func runCloudformationCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintCloudformationStacks(AWSOutputDirectory, Verbosity)
}
@@ -746,6 +760,9 @@ func runCloudformationCommand(cmd *cobra.Command, args []string) {
func runCodeBuildCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -762,6 +779,7 @@ func runCodeBuildCommand(cmd *cobra.Command, args []string) {
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
PmapperDataBasePath: PmapperDataBasePath,
ServiceMap: sharedServiceMap,
}
m.PrintCodeBuildProjects(AWSOutputDirectory, Verbosity)
}
@@ -769,6 +787,9 @@ func runCodeBuildCommand(cmd *cobra.Command, args []string) {
func runDatabasesCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -786,6 +807,7 @@ func runDatabasesCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintDatabases(AWSOutputDirectory, Verbosity)
}
@@ -793,6 +815,9 @@ func runDatabasesCommand(cmd *cobra.Command, args []string) {
func runECRCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -807,6 +832,7 @@ func runECRCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintECR(AWSOutputDirectory, Verbosity)
}
@@ -814,6 +840,9 @@ func runECRCommand(cmd *cobra.Command, args []string) {
func runSQSCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -831,6 +860,7 @@ func runSQSCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintSQS(AWSOutputDirectory, Verbosity)
}
@@ -838,17 +868,32 @@ func runSQSCommand(cmd *cobra.Command, args []string) {
func runSNSCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
continue
}
cloudFoxSNSClient := aws.InitCloudFoxSNSClient(*caller, profile, cmd.Root().Version, Goroutines, AWSWrapTable, AWSMFAToken)
cloudFoxSNSClient.PrintSNS(AWSOutputDirectory, Verbosity)
m := aws.SNSModule{
SNSClient: sns.NewFromConfig(AWSConfig),
Caller: *caller,
AWSProfile: profile,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
ServiceMap: sharedServiceMap,
}
m.PrintSNS(AWSOutputDirectory, Verbosity)
}
}
func runEKSCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -867,6 +912,7 @@ func runEKSCommand(cmd *cobra.Command, args []string) {
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
PmapperDataBasePath: PmapperDataBasePath,
ServiceMap: sharedServiceMap,
}
m.EKS(AWSOutputDirectory, Verbosity)
}
@@ -874,6 +920,9 @@ func runEKSCommand(cmd *cobra.Command, args []string) {
func runEndpointsCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -903,6 +952,7 @@ func runEndpointsCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintEndpoints(AWSOutputDirectory, Verbosity)
}
@@ -910,13 +960,15 @@ func runEndpointsCommand(cmd *cobra.Command, args []string) {
func runEnvsCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
continue
}
m := aws.EnvsModule{
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
@@ -930,6 +982,7 @@ func runEnvsCommand(cmd *cobra.Command, args []string) {
LambdaClient: lambda.NewFromConfig(AWSConfig),
LightsailClient: lightsail.NewFromConfig(AWSConfig),
SagemakerClient: sagemaker.NewFromConfig(AWSConfig),
ServiceMap: sharedServiceMap,
}
m.PrintEnvs(AWSOutputDirectory, Verbosity)
}
@@ -937,6 +990,9 @@ func runEnvsCommand(cmd *cobra.Command, args []string) {
func runFilesystemsCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -953,6 +1009,7 @@ func runFilesystemsCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
filesystems.PrintFilesystems(AWSOutputDirectory, Verbosity)
}
@@ -1172,6 +1229,20 @@ func runCapeCommand(cmd *cobra.Command, args []string) {
}
}
// if the CapeArnIgnoreList arg is not empty, read the file and add the arns to the CapeArnIgnoreList
if CapeArnIgnoreList != "" {
// call ReadArnIgnoreListFile and add the arns to the CapeArnIgnoreList
arnsToIgnore, err := aws.ReadArnIgnoreListFile(CapeArnIgnoreList)
if err != nil {
fmt.Println("Error reading the arn ignore list file: " + err.Error())
}
// remove nodes that are in the CapeArnIgnoreList from the graph
for _, arn := range arnsToIgnore {
GlobalGraph.RemoveVertex(arn)
}
}
// make pmapper edges
//you can update edges, so we can just merge attributes as needed
// first we add the edges that already exist in pmapper, then later we will make more edges based on the cloudfox role trusts logic
@@ -1182,7 +1253,7 @@ func runCapeCommand(cmd *cobra.Command, args []string) {
graph.EdgeAttribute(edge.ShortReason, edge.Reason),
)
if err != nil {
if err == graph.ErrEdgeAlreadyExists {
if errors.Is(err, graph.ErrEdgeAlreadyExists) {
// update theedge by copying the existing graph.Edge with attributes and add the new attributes
//fmt.Println("Edge already exists")
@@ -1318,10 +1389,20 @@ func runCapeTUICommand(cmd *cobra.Command, args []string) {
if _, err := os.Stat(filepath.Join(cloudfoxRunData.OutputLocation, "json", fileName)); os.IsNotExist(err) {
fmt.Printf("[%s] Could not retrieve CAPE data for profile %s.\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", cmd.Root().Version)), profile)
//remove the profile from the list of profiles to analyze
AWSProfiles = append(AWSProfiles[:i], AWSProfiles[i+1:]...)
if len(AWSProfiles) > 1 {
AWSProfiles = append(AWSProfiles[:i], AWSProfiles[i+1:]...)
} else {
if CapeAdminOnly {
fmt.Printf("[%s] Could not retrieve cape data. Did you run cape without the --admin-only flag? You'll need to run cape with --admin-only to use the tui with --admin-only\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", cmd.Root().Version)))
} else {
fmt.Printf("[%s] Did you run cape with the --admin-only flag? You'll need to run cape without --admin-only to use the tui without --admin-only\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", cmd.Root().Version)))
}
os.Exit(1)
}
}
}
if len(capeOutputFileLocations) == 0 {
fmt.Printf("[%s] Could not retrieve CAPE data.\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", cmd.Root().Version)))
os.Exit(1)
@@ -1338,13 +1419,14 @@ func runIamSimulatorCommand(cmd *cobra.Command, args []string) {
continue
}
m := aws.IamSimulatorModule{
IAMClient: iam.NewFromConfig(AWSConfig),
Caller: *caller,
AWSProfileProvided: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
IAMClient: iam.NewFromConfig(AWSConfig),
Caller: *caller,
AWSProfileProvided: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
IamSimulatorAdminCheckOnly: IamSimulatorAdminCheckOnly,
}
m.PrintIamSimulator(SimulatorPrincipal, SimulatorAction, SimulatorResource, AWSOutputDirectory, Verbosity)
}
@@ -1352,6 +1434,9 @@ func runIamSimulatorCommand(cmd *cobra.Command, args []string) {
func runInstancesCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -1370,6 +1455,7 @@ func runInstancesCommand(cmd *cobra.Command, args []string) {
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
PmapperDataBasePath: PmapperDataBasePath,
ServiceMap: sharedServiceMap,
}
m.Instances(InstancesFilter, AWSOutputDirectory, Verbosity)
}
@@ -1377,6 +1463,9 @@ func runInstancesCommand(cmd *cobra.Command, args []string) {
func runInventoryCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -1430,6 +1519,7 @@ func runInventoryCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintInventoryPerRegion(AWSOutputDirectory, Verbosity)
}
@@ -1437,6 +1527,9 @@ func runInventoryCommand(cmd *cobra.Command, args []string) {
func runLambdasCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -1454,6 +1547,7 @@ func runLambdasCommand(cmd *cobra.Command, args []string) {
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
PmapperDataBasePath: PmapperDataBasePath,
ServiceMap: sharedServiceMap,
}
m.PrintLambdas(AWSOutputDirectory, Verbosity)
}
@@ -1461,6 +1555,9 @@ func runLambdasCommand(cmd *cobra.Command, args []string) {
func runOutboundAssumedRolesCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -1476,6 +1573,7 @@ func runOutboundAssumedRolesCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintOutboundRoleTrusts(OutboundAssumedRolesDays, AWSOutputDirectory, Verbosity)
}
@@ -1547,13 +1645,15 @@ func runPrincipalsCommand(cmd *cobra.Command, args []string) {
continue
}
m := aws.IamPrincipalsModule{
IAMClient: iam.NewFromConfig(AWSConfig),
Caller: *caller,
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
IAMClient: iam.NewFromConfig(AWSConfig),
Caller: *caller,
AWSProfile: profile,
Goroutines: Goroutines,
SkipAdminCheck: AWSSkipAdminCheck,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
PmapperDataBasePath: PmapperDataBasePath,
}
m.PrintIamPrincipals(AWSOutputDirectory, Verbosity)
}
@@ -1561,6 +1661,9 @@ func runPrincipalsCommand(cmd *cobra.Command, args []string) {
func runRAMCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -1575,6 +1678,7 @@ func runRAMCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
ram.PrintRAM(AWSOutputDirectory, Verbosity)
@@ -1583,26 +1687,44 @@ func runRAMCommand(cmd *cobra.Command, args []string) {
func runResourceTrustsCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
continue
}
m := aws.ResourceTrustsModule{
Caller: *caller,
AWSProfileProvided: profile,
Goroutines: Goroutines,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
WrapTable: AWSWrapTable,
CloudFoxVersion: cmd.Root().Version,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
AWSConfig: AWSConfig,
}
m.PrintResources(AWSOutputDirectory, Verbosity)
runResourceTrustsCommandWithProfile(cmd, args, profile)
}
}
func runResourceTrustsCommandWithProfile(cmd *cobra.Command, args []string, profile string) {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
var KMSClient sdk.KMSClientInterface = kms.NewFromConfig(AWSConfig)
var APIGatewayClient sdk.APIGatewayClientInterface = apigateway.NewFromConfig(AWSConfig)
var EC2Client sdk.AWSEC2ClientInterface = ec2.NewFromConfig(AWSConfig)
var OpenSearchClient sdk.OpenSearchClientInterface = opensearch.NewFromConfig(AWSConfig)
if err != nil {
return
}
m := aws.ResourceTrustsModule{
KMSClient: &KMSClient,
APIGatewayClient: &APIGatewayClient,
EC2Client: &EC2Client,
OpenSearchClient: &OpenSearchClient,
Caller: *caller,
AWSProfileProvided: profile,
Goroutines: Goroutines,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
WrapTable: AWSWrapTable,
CloudFoxVersion: cmd.Root().Version,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
AWSConfig: AWSConfig,
ServiceMap: sharedServiceMap,
}
m.PrintResources(AWSOutputDirectory, Verbosity, ResourceTrustsIncludeKms)
}
func runRoleTrustCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
@@ -1649,6 +1771,9 @@ func runRoute53Command(cmd *cobra.Command, args []string) {
func runSecretsCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -1665,6 +1790,7 @@ func runSecretsCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintSecrets(AWSOutputDirectory, Verbosity)
}
@@ -1694,6 +1820,9 @@ func runTagsCommand(cmd *cobra.Command, args []string) {
func runWorkloadsCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -1714,6 +1843,7 @@ func runWorkloadsCommand(cmd *cobra.Command, args []string) {
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
PmapperDataBasePath: PmapperDataBasePath,
ServiceMap: sharedServiceMap,
}
m.PrintWorkloads(AWSOutputDirectory, Verbosity)
}
@@ -1721,6 +1851,9 @@ func runWorkloadsCommand(cmd *cobra.Command, args []string) {
func runDirectoryServicesCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
var AWSConfig = internal.AWSConfigFileLoader(profile, cmd.Root().Version, AWSMFAToken)
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
@@ -1735,6 +1868,7 @@ func runDirectoryServicesCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintDirectories(AWSOutputDirectory, Verbosity)
}
@@ -1742,6 +1876,9 @@ func runDirectoryServicesCommand(cmd *cobra.Command, args []string) {
func runECSTasksCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
continue
@@ -1760,6 +1897,7 @@ func runECSTasksCommand(cmd *cobra.Command, args []string) {
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
PmapperDataBasePath: PmapperDataBasePath,
ServiceMap: sharedServiceMap,
}
m.ECSTasks(AWSOutputDirectory, Verbosity)
}
@@ -1767,6 +1905,9 @@ func runECSTasksCommand(cmd *cobra.Command, args []string) {
func runENICommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
continue
@@ -1781,6 +1922,7 @@ func runENICommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.ElasticNetworkInterfaces(AWSOutputDirectory, Verbosity)
}
@@ -1788,6 +1930,9 @@ func runENICommand(cmd *cobra.Command, args []string) {
func runNetworkPortsCommand(cmd *cobra.Command, args []string) {
for _, profile := range AWSProfiles {
sharedServiceMap := &awsservicemap.AwsServiceMap{
JsonFileSource: "DOWNLOAD_FROM_AWS",
}
caller, err := internal.AWSWhoami(profile, cmd.Root().Version, AWSMFAToken)
if err != nil {
continue
@@ -1808,6 +1953,7 @@ func runNetworkPortsCommand(cmd *cobra.Command, args []string) {
Verbosity: Verbosity,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
ServiceMap: sharedServiceMap,
}
m.PrintNetworkPorts(AWSOutputDirectory)
}
@@ -1909,14 +2055,13 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
SQSClient: sqsClient,
SSMClient: ssmClient,
StepFunctionClient: stepFunctionClient,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
}
inventory2.PrintInventoryPerRegion(AWSOutputDirectory, Verbosity)
@@ -1961,11 +2106,10 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
instances.Instances(InstancesFilter, AWSOutputDirectory, Verbosity)
route53 := aws.Route53Module{
Route53Client: route53Client,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
}
lambdasMod := aws.LambdasModule{
@@ -1999,7 +2143,6 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
filesystems.PrintFilesystems(AWSOutputDirectory, Verbosity)
endpoints := aws.EndpointsModule{
EKSClient: eksClient,
S3Client: s3Client,
LambdaClient: lambdaClient,
@@ -2015,14 +2158,13 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
CloudfrontClient: cloudfrontClient,
AppRunnerClient: appRunnerClient,
LightsailClient: lightsailClient,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
}
endpoints.PrintEndpoints(AWSOutputDirectory, Verbosity)
@@ -2030,12 +2172,11 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
gateways := aws.ApiGwModule{
APIGatewayv2Client: apiGatewayv2Client,
APIGatewayClient: apiGatewayClient,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
}
gateways.PrintApiGws(AWSOutputDirectory, Verbosity)
@@ -2056,10 +2197,9 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
databases.PrintDatabases(AWSOutputDirectory, Verbosity)
ecstasks := aws.ECSTasksModule{
EC2Client: ec2Client,
ECSClient: ecsClient,
IAMClient: iamClient,
EC2Client: ec2Client,
ECSClient: ecsClient,
IAMClient: iamClient,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
@@ -2073,9 +2213,8 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
ecstasks.ECSTasks(AWSOutputDirectory, Verbosity)
eksCommand := aws.EKSModule{
EKSClient: eksClient,
IAMClient: iamClient,
EKSClient: eksClient,
IAMClient: iamClient,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
@@ -2103,11 +2242,10 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
fmt.Printf("[%s] %s\n", cyan(emoji.Sprintf(":fox:cloudfox :fox:")), green("Looking for secrets hidden between the seat cushions."))
ec2UserData := aws.InstancesModule{
EC2Client: ec2Client,
IAMClient: iamClient,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
EC2Client: ec2Client,
IAMClient: iamClient,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
UserDataAttributesOnly: true,
AWSProfile: profile,
Goroutines: Goroutines,
@@ -2117,7 +2255,6 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
}
ec2UserData.Instances(InstancesFilter, AWSOutputDirectory, Verbosity)
envsMod := aws.EnvsModule{
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
@@ -2183,14 +2320,13 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
secrets := aws.SecretsModule{
SecretsManagerClient: secretsManagerClient,
SSMClient: ssmClient,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
}
secrets.PrintSecrets(AWSOutputDirectory, Verbosity)
@@ -2224,10 +2360,8 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
networkPorts.PrintNetworkPorts(AWSOutputDirectory)
sqsMod := aws.SQSModule{
SQSClient: sqsClient,
SQSClient: sqsClient,
StorePolicies: StoreSQSAccessPolicies,
Caller: *caller,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
AWSProfile: profile,
@@ -2241,19 +2375,7 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
cloudFoxSNSClient := aws.InitCloudFoxSNSClient(*caller, profile, cmd.Root().Version, Goroutines, AWSWrapTable, AWSMFAToken)
cloudFoxSNSClient.PrintSNS(AWSOutputDirectory, Verbosity)
resourceTrustsCommand := aws.ResourceTrustsModule{
Caller: *caller,
AWSProfileProvided: profile,
Goroutines: Goroutines,
AWSRegions: internal.GetEnabledRegions(profile, cmd.Root().Version, AWSMFAToken),
WrapTable: AWSWrapTable,
CloudFoxVersion: cmd.Root().Version,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
AWSMFAToken: AWSMFAToken,
AWSConfig: AWSConfig,
}
resourceTrustsCommand.PrintResources(AWSOutputDirectory, Verbosity)
runResourceTrustsCommandWithProfile(cmd, args, profile)
codeBuildCommand := aws.CodeBuildModule{
CodeBuildClient: codeBuildClient,
@@ -2375,9 +2497,6 @@ func init() {
// Map Access Keys Module Flags
AccessKeysCommand.Flags().StringVarP(&AccessKeysFilter, "filter", "f", "none", "Access key ID to search for")
// IAM Simulator Module Flags
//IamSimulatorCommand.Flags().StringVarP(&IamSimulatorFilter, "filter", "f", "none", "Access key ID to search for")
// Instances Map Module Flags
InstancesCommand.Flags().StringVarP(&InstancesFilter, "filter", "f", "all", "[InstanceID | InstanceIDsFile]")
InstancesCommand.Flags().BoolVarP(&InstanceMapUserDataAttributesOnly, "userdata", "u", false, "Use this flag to retrieve only the userData attribute from EC2 instances.")
@@ -2395,6 +2514,7 @@ func init() {
IamSimulatorCommand.Flags().StringVar(&SimulatorPrincipal, "principal", "", "Principal Arn")
IamSimulatorCommand.Flags().StringVar(&SimulatorAction, "action", "", "Action")
IamSimulatorCommand.Flags().StringVar(&SimulatorResource, "resource", "*", "Resource")
IamSimulatorCommand.Flags().BoolVar(&IamSimulatorAdminCheckOnly, "admin-check-only", false, "Only check check if principals are admin")
// iam-simulator module flags
PermissionsCommand.Flags().StringVar(&PermissionsPrincipal, "principal", "", "Principal Arn")
@@ -2408,10 +2528,15 @@ func init() {
// cape command flags
CapeCommand.Flags().BoolVar(&CapeAdminOnly, "admin-only", false, "Only return paths that lead to an admin role - much faster")
//CapeCommand.Flags().StringVar(&CapeJobName, "job-name", "", "Name of the cape job")
// flag that accepts a list of arns to ignore
CapeCommand.Flags().StringVar(&CapeArnIgnoreList, "arn-ignore-list", "", "File containing a list of ARNs to ignore separated by newlines")
// cape tui command flags
CapeTuiCmd.Flags().BoolVar(&CapeAdminOnly, "admin-only", false, "Only return paths that lead to an admin role - much faster")
// Resource Trust command flags
ResourceTrustsCommand.Flags().BoolVar(&ResourceTrustsIncludeKms, "include-kms", false, "Include KMS keys in the output")
// Global flags for the AWS modules
AWSCommands.PersistentFlags().StringVarP(&AWSProfile, "profile", "p", "", "AWS CLI Profile Name")
AWSCommands.PersistentFlags().StringVarP(&AWSProfilesList, "profiles-list", "l", "", "File containing a AWS CLI profile names separated by newlines")
+1 -1
View File
@@ -17,7 +17,7 @@ package iamservice
// Projects []string
// }
// // Be incorportated in iam.go
// // Be incorporated in iam.go
// 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()
+1 -1
View File
@@ -4,4 +4,4 @@ const CLOUDFOX_USER_AGENT = "cloudfox"
const CLOUDFOX_LOG_FILE_DIR_NAME = ".cloudfox"
const CLOUDFOX_BASE_DIRECTORY = "cloudfox-output"
const LOOT_DIRECTORY_NAME = "loot"
const CLOUDFOX_VERSION = "1.14.0"
const CLOUDFOX_VERSION = "1.17.0"
+179 -158
View File
@@ -1,192 +1,213 @@
module github.com/BishopFox/cloudfox
go 1.21.2
toolchain go1.21.6
go 1.24.2
require (
cloud.google.com/go/artifactregistry v1.14.6
cloud.google.com/go/bigquery v1.57.1
cloud.google.com/go/iam v1.1.5
cloud.google.com/go/resourcemanager v1.9.4
cloud.google.com/go/secretmanager v1.11.4
cloud.google.com/go/storage v1.35.1
cloud.google.com/go/artifactregistry v1.18.0
cloud.google.com/go/bigquery v1.72.0
cloud.google.com/go/iam v1.5.3
cloud.google.com/go/resourcemanager v1.10.7
cloud.google.com/go/secretmanager v1.16.0
cloud.google.com/go/storage v1.58.0
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.1
github.com/Azure/go-autorest/autorest v0.11.29
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12
github.com/aquasecurity/table v1.8.0
github.com/aws/aws-sdk-go-v2 v1.26.1
github.com/aws/aws-sdk-go-v2/config v1.26.2
github.com/aws/aws-sdk-go-v2/credentials v1.16.13
github.com/aws/aws-sdk-go-v2/service/apigateway v1.21.6
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.18.6
github.com/aws/aws-sdk-go-v2/service/apprunner v1.25.5
github.com/aws/aws-sdk-go-v2/service/athena v1.37.3
github.com/aws/aws-sdk-go-v2/service/cloud9 v1.22.5
github.com/aws/aws-sdk-go-v2/service/cloudformation v1.42.5
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.32.5
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.35.6
github.com/aws/aws-sdk-go-v2/service/codeartifact v1.23.5
github.com/aws/aws-sdk-go-v2/service/codebuild v1.26.5
github.com/aws/aws-sdk-go-v2/service/codecommit v1.20.0
github.com/aws/aws-sdk-go-v2/service/codedeploy v1.22.2
github.com/aws/aws-sdk-go-v2/service/datapipeline v1.19.5
github.com/aws/aws-sdk-go-v2/service/directoryservice v1.24.4
github.com/aws/aws-sdk-go-v2/service/docdb v1.29.5
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.26.7
github.com/aws/aws-sdk-go-v2/service/ec2 v1.142.0
github.com/aws/aws-sdk-go-v2/service/ecr v1.24.6
github.com/aws/aws-sdk-go-v2/service/ecs v1.35.6
github.com/aws/aws-sdk-go-v2/service/efs v1.26.5
github.com/aws/aws-sdk-go-v2/service/eks v1.37.0
github.com/aws/aws-sdk-go-v2/service/elasticache v1.34.6
github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.20.5
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.21.6
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.26.6
github.com/aws/aws-sdk-go-v2/service/emr v1.35.6
github.com/aws/aws-sdk-go-v2/service/fsx v1.40.0
github.com/aws/aws-sdk-go-v2/service/glue v1.73.0
github.com/aws/aws-sdk-go-v2/service/grafana v1.18.5
github.com/aws/aws-sdk-go-v2/service/iam v1.28.5
github.com/aws/aws-sdk-go-v2/service/kinesis v1.24.6
github.com/aws/aws-sdk-go-v2/service/lambda v1.49.6
github.com/aws/aws-sdk-go-v2/service/lightsail v1.32.5
github.com/aws/aws-sdk-go-v2/service/mq v1.20.6
github.com/aws/aws-sdk-go-v2/service/opensearch v1.27.1
github.com/aws/aws-sdk-go-v2/service/organizations v1.23.5
github.com/aws/aws-sdk-go-v2/service/ram v1.23.7
github.com/aws/aws-sdk-go-v2/service/rds v1.66.0
github.com/aws/aws-sdk-go-v2/service/redshift v1.39.7
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.19.6
github.com/aws/aws-sdk-go-v2/service/route53 v1.36.0
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.7
github.com/aws/aws-sdk-go-v2/service/sagemaker v1.122.0
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0
github.com/aws/aws-sdk-go-v2/service/sfn v1.24.6
github.com/aws/aws-sdk-go-v2/service/sns v1.26.6
github.com/aws/aws-sdk-go-v2/service/sqs v1.29.6
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.6
github.com/aws/aws-sdk-go-v2/service/sts v1.26.6
github.com/aws/smithy-go v1.20.2
github.com/bishopfox/awsservicemap v1.0.3
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3
github.com/Azure/go-autorest/autorest v0.11.30
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13
github.com/aquasecurity/table v1.11.0
github.com/aws/aws-sdk-go-v2 v1.41.0
github.com/aws/aws-sdk-go-v2/config v1.32.5
github.com/aws/aws-sdk-go-v2/credentials v1.19.5
github.com/aws/aws-sdk-go-v2/service/apigateway v1.38.3
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.33.4
github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.9
github.com/aws/aws-sdk-go-v2/service/athena v1.56.4
github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.15
github.com/aws/aws-sdk-go-v2/service/cloudformation v1.71.4
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.58.3
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.55.4
github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.16
github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.8
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.7
github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.8
github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.15
github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.11
github.com/aws/aws-sdk-go-v2/service/docdb v1.48.8
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.5
github.com/aws/aws-sdk-go-v2/service/ec2 v1.276.1
github.com/aws/aws-sdk-go-v2/service/ecr v1.54.4
github.com/aws/aws-sdk-go-v2/service/ecs v1.69.5
github.com/aws/aws-sdk-go-v2/service/efs v1.41.9
github.com/aws/aws-sdk-go-v2/service/eks v1.76.3
github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.8
github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.18
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.18
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.54.5
github.com/aws/aws-sdk-go-v2/service/emr v1.57.4
github.com/aws/aws-sdk-go-v2/service/fsx v1.65.1
github.com/aws/aws-sdk-go-v2/service/glue v1.135.3
github.com/aws/aws-sdk-go-v2/service/grafana v1.32.9
github.com/aws/aws-sdk-go-v2/service/iam v1.53.1
github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.9
github.com/aws/aws-sdk-go-v2/service/lambda v1.87.0
github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.10
github.com/aws/aws-sdk-go-v2/service/mq v1.34.14
github.com/aws/aws-sdk-go-v2/service/opensearch v1.56.0
github.com/aws/aws-sdk-go-v2/service/organizations v1.50.0
github.com/aws/aws-sdk-go-v2/service/ram v1.34.18
github.com/aws/aws-sdk-go-v2/service/rds v1.113.1
github.com/aws/aws-sdk-go-v2/service/redshift v1.61.4
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.5
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.2
github.com/aws/aws-sdk-go-v2/service/sagemaker v1.228.2
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.0
github.com/aws/aws-sdk-go-v2/service/sfn v1.40.5
github.com/aws/aws-sdk-go-v2/service/sns v1.39.10
github.com/aws/aws-sdk-go-v2/service/sqs v1.42.20
github.com/aws/aws-sdk-go-v2/service/ssm v1.67.7
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5
github.com/aws/smithy-go v1.24.0
github.com/bishopfox/awsservicemap v1.1.0
github.com/bishopfox/knownawsaccountslookup v0.0.0-20231228165844-c37ef8df33cb
github.com/dominikbraun/graph v0.23.0
github.com/fatih/color v1.16.0
github.com/goccy/go-json v0.10.2
github.com/googleapis/gax-go/v2 v2.12.0
github.com/fatih/color v1.18.0
github.com/goccy/go-json v0.10.5
github.com/googleapis/gax-go/v2 v2.15.0
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/sirupsen/logrus v1.9.3
github.com/spf13/afero v1.11.0
github.com/spf13/cobra v1.8.0
golang.org/x/crypto v0.17.0
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b
github.com/spf13/afero v1.15.0
github.com/spf13/cobra v1.10.2
golang.org/x/crypto v0.46.0
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9
)
require (
cel.dev/expr v0.25.1 // indirect
cloud.google.com/go/auth v0.17.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/monitoring v1.24.3 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect
github.com/apache/arrow/go/v15 v15.0.2 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/colorprofile v0.4.1 // indirect
github.com/charmbracelet/x/ansi v0.11.3 // indirect
github.com/charmbracelet/x/cellbuf v0.0.14 // indirect
github.com/charmbracelet/x/term v0.2.2 // indirect
github.com/clipperhouse/displaywidth v0.6.1 // indirect
github.com/clipperhouse/stringish v0.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
golang.org/x/sync v0.5.0 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/telemetry v0.0.0-20251208220230-2638a1023523 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
require (
golang.org/x/oauth2 v0.15.0
google.golang.org/api v0.152.0
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17
google.golang.org/protobuf v1.33.0
github.com/aws/aws-sdk-go-v2/service/kms v1.49.4
golang.org/x/oauth2 v0.34.0
google.golang.org/api v0.257.0
google.golang.org/genproto v0.0.0-20251202230838-ff82c1b0f217
google.golang.org/protobuf v1.36.11
)
require (
cloud.google.com/go v0.110.10 // indirect
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/longrunning v0.5.4 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect
cloud.google.com/go v0.123.0 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
cloud.google.com/go/longrunning v0.7.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/apache/arrow/go/v12 v12.0.0 // indirect
github.com/apache/thrift v0.16.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect
github.com/charmbracelet/bubbles v0.18.0
github.com/charmbracelet/bubbletea v0.25.0
github.com/charmbracelet/lipgloss v0.9.1
github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.7 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.1 // indirect
github.com/Azure/go-autorest/autorest/to v0.4.1 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.2 // indirect
github.com/Azure/go-autorest/logger v0.2.2 // indirect
github.com/Azure/go-autorest/tracing v0.6.1 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.16 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect
github.com/charmbracelet/bubbles v0.21.0
github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/lipgloss v1.1.0
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/go-openapi/errors v0.21.0 // indirect
github.com/go-openapi/strfmt v0.21.10 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v2.0.8+incompatible // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/go-openapi/errors v0.22.5 // indirect
github.com/go-openapi/strfmt v0.25.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/google/flatbuffers v25.9.23+incompatible // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/asmfmt v1.3.2 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/klauspost/compress v1.18.2 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
github.com/mattn/go-runewidth v0.0.19 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/neo4j/neo4j-go-driver/v5 v5.14.0
github.com/neo4j/neo4j-go-driver/v5 v5.28.4
github.com/oklog/ulid v1.3.1 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/rivo/uniseg v0.4.6 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.mongodb.org/mongo-driver v1.13.1 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.16.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/grpc v1.59.0 // indirect
go.mongodb.org/mongo-driver v1.17.6 // indirect
golang.org/x/mod v0.31.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/term v0.38.0 // indirect
golang.org/x/text v0.32.0 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/tools v0.40.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/grpc v1.77.0 // indirect
)
+415 -431
View File
@@ -1,388 +1,401 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y=
cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic=
cloud.google.com/go/artifactregistry v1.14.6 h1:/hQaadYytMdA5zBh+RciIrXZQBWK4vN7EUsrQHG+/t8=
cloud.google.com/go/artifactregistry v1.14.6/go.mod h1:np9LSFotNWHcjnOgh8UVK0RFPCTUGbO0ve3384xyHfE=
cloud.google.com/go/bigquery v1.57.1 h1:FiULdbbzUxWD0Y4ZGPSVCDLvqRSyCIO6zKV7E2nf5uA=
cloud.google.com/go/bigquery v1.57.1/go.mod h1:iYzC0tGVWt1jqSzBHqCr3lrRn0u13E8e+AqowBsDgug=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
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/datacatalog v1.18.3 h1:zmdxP6nOjN5Qb1rtu9h4kbEVwerQ6Oshf+t747QJUew=
cloud.google.com/go/datacatalog v1.18.3/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM=
cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg=
cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI=
cloud.google.com/go/resourcemanager v1.9.4 h1:JwZ7Ggle54XQ/FVYSBrMLOQIKoIT/uer8mmNvNLK51k=
cloud.google.com/go/resourcemanager v1.9.4/go.mod h1:N1dhP9RFvo3lUfwtfLWVxfUWq8+KUQ+XLlHLH3BoFJ0=
cloud.google.com/go/secretmanager v1.11.4 h1:krnX9qpG2kR2fJ+u+uNyNo+ACVhplIAS4Pu7u+4gd+k=
cloud.google.com/go/secretmanager v1.11.4/go.mod h1:wreJlbS9Zdq21lMzWmJ0XhWW2ZxgPeahsqeV/vZoJ3w=
cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w=
cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
cloud.google.com/go/artifactregistry v1.18.0 h1:4qQIM1a1OymPxCODgLpXJo+097feE0i9pwpof98SimQ=
cloud.google.com/go/artifactregistry v1.18.0/go.mod h1:UEAPCgHDFC1q+A8nnVxXHPEy9KCVOeavFBF1fEChQvU=
cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4=
cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/bigquery v1.72.0 h1:D/yLju+3Ens2IXx7ou1DJ62juBm+/coBInn4VVOg5Cw=
cloud.google.com/go/bigquery v1.72.0/go.mod h1:GUbRtmeCckOE85endLherHD9RsujY+gS7i++c1CqssQ=
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
cloud.google.com/go/datacatalog v1.26.1 h1:bCRKA8uSQN8wGW3Tw0gwko4E9a64GRmbW1nCblhgC2k=
cloud.google.com/go/datacatalog v1.26.1/go.mod h1:2Qcq8vsHNxMDgjgadRFmFG47Y+uuIVsyEGUrlrKEdrg=
cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc=
cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU=
cloud.google.com/go/logging v1.13.1 h1:O7LvmO0kGLaHY/gq8cV7T0dyp6zJhYAOtZPX4TF3QtY=
cloud.google.com/go/logging v1.13.1/go.mod h1:XAQkfkMBxQRjQek96WLPNze7vsOmay9H5PqfsNYDqvw=
cloud.google.com/go/longrunning v0.7.0 h1:FV0+SYF1RIj59gyoWDRi45GiYUMM3K1qO51qoboQT1E=
cloud.google.com/go/longrunning v0.7.0/go.mod h1:ySn2yXmjbK9Ba0zsQqunhDkYi0+9rlXIwnoAf+h+TPY=
cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE=
cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI=
cloud.google.com/go/resourcemanager v1.10.7 h1:oPZKIdjyVTuag+D4HF7HO0mnSqcqgjcuA18xblwA0V0=
cloud.google.com/go/resourcemanager v1.10.7/go.mod h1:rScGkr6j2eFwxAjctvOP/8sqnEpDbQ9r5CKwKfomqjs=
cloud.google.com/go/secretmanager v1.16.0 h1:19QT7ZsLJ8FSP1k+4esQvuCD7npMJml6hYzilxVyT+k=
cloud.google.com/go/secretmanager v1.16.0/go.mod h1://C/e4I8D26SDTz1f3TQcddhcmiC3rMEl0S1Cakvs3Q=
cloud.google.com/go/storage v1.58.0 h1:PflFXlmFJjG/nBeR9B7pKddLQWaFaRWx4uUi/LyNxxo=
cloud.google.com/go/storage v1.58.0/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI=
cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U=
cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s=
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=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0 h1:pPvTJ1dY0sA35JOeFq6TsY2xj6Z85Yo23Pj4wCCvu4o=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0/go.mod h1:mLfWfj8v3jfWKsL9G4eoBoXVcsqcIUTapmdKy7uGOp0=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.1 h1:AMf7YbZOZIW5b66cXNHMWWT/zkjhz5+a+k/3x40EO7E=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.1/go.mod h1:uwfk06ZBcvL/g4VHNjurPfVln9NMbsk2XIZxJ+hu81k=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1/go.mod h1:Ng3urmn6dYe8gnbCMoHHVl5APYz2txho3koEkV2o2HA=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 h1:ZJJNFaQ86GVKQ9ehwqyAFE6pIfyicpuJ8IkVaPBc6/4=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3/go.mod h1:URuDvhmATVKqHBH9/0nOiNKk0+YcwfQ3WkK5PqHKxc8=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc=
github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs=
github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA=
github.com/Azure/go-autorest/autorest v0.11.30 h1:iaZ1RGz/ALZtN5eq4Nr1SOFSlf2E4pDI3Tcsl+dZPVE=
github.com/Azure/go-autorest/autorest v0.11.30/go.mod h1:t1kpPIOpIVX7annvothKvb0stsrXa37i7b+xpmBW8Fs=
github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=
github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8=
github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c=
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 h1:wkAZRgT/pn8HhFyzfe9UnqOjJYqlembgCTi72Bm/xKk=
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc=
github.com/Azure/go-autorest/autorest/adal v0.9.24 h1:BHZfgGsGwdkHDyZdtQRQk1WeUdW0m2WPAwuHZwUi5i4=
github.com/Azure/go-autorest/autorest/adal v0.9.24/go.mod h1:7T1+g0PYFmACYW5LlG2fcoPiPlFHjClyRGL7dRlP5c8=
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 h1:Ov8avRZi2vmrE2JcXw+tu5K/yB41r7xK9GZDiBF7NdM=
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13/go.mod h1:5BAVfWLWXihP47vYrPuBKKf4cS0bXI+KM9Qx6ETDJYo=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.7 h1:Q9R3utmFg9K1B4OYtAZ7ZUUvIUdzQt7G2MN5Hi/d670=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.7/go.mod h1:bVrAueELJ0CKLBpUHDIvD516TwmHmzqwCpvONWRsw3s=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/date v0.3.1 h1:o9Z8Jyt+VJJTCZ/UORishuHOusBwolhjokt9s5k8I4w=
github.com/Azure/go-autorest/autorest/date v0.3.1/go.mod h1:Dz/RDmXlfiFFS/eW+b/xMUSFs1tboPVy6UjgADToWDM=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac=
github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
github.com/Azure/go-autorest/autorest/to v0.4.1 h1:CxNHBqdzTr7rLtdrtb5CMjJcDut+WNGCVv7OmS5+lTc=
github.com/Azure/go-autorest/autorest/to v0.4.1/go.mod h1:EtaofgU4zmtvn1zT2ARsjRFdq9vXx0YWtmElwL+GZ9M=
github.com/Azure/go-autorest/autorest/validation v0.3.2 h1:myD3tcvs+Fk1bkJ1Xx7xidop4z4FWvWADiMGMXeVd2E=
github.com/Azure/go-autorest/autorest/validation v0.3.2/go.mod h1:4z7eU88lSINAB5XL8mhfPumiUdoAQo/c7qXwbsM8Zhc=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/logger v0.2.2 h1:hYqBsEBywrrOSW24kkOCXRcKfKhK76OzLTfF+MYDE2o=
github.com/Azure/go-autorest/logger v0.2.2/go.mod h1:I5fg9K52o+iuydlWfa9T5K6WFos9XYr9dYTFzpqgibw=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 h1:hVeq+yCyUi+MsoO/CU95yqCIcdzra5ovzk8Q2BBpV2M=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/apache/arrow/go/v12 v12.0.0 h1:xtZE63VWl7qLdB0JObIXvvhGjoVNrQ9ciIHG2OK5cmc=
github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg=
github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY=
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
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=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA=
github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo=
github.com/aws/aws-sdk-go-v2/config v1.26.2 h1:+RWLEIWQIGgrz2pBPAUoGgNGs1TOyF4Hml7hCnYj2jc=
github.com/aws/aws-sdk-go-v2/config v1.26.2/go.mod h1:l6xqvUxt0Oj7PI/SUXYLNyZ9T/yBPn3YTQcJLLOdtR8=
github.com/aws/aws-sdk-go-v2/credentials v1.16.13 h1:WLABQ4Cp4vXtXfOWOS3MEZKr6AAYUpMczLhgKtAjQ/8=
github.com/aws/aws-sdk-go-v2/credentials v1.16.13/go.mod h1:Qg6x82FXwW0sJHzYruxGiuApNo31UEtJvXVSZAXeWiw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc=
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 h1:ugD6qzjYtB7zM5PN/ZIeaAIyefPaD82G8+SJopgvUpw=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9/go.mod h1:YD0aYBWCrPENpHolhKw2XDlTIWae2GKXT1T4o6N6hiM=
github.com/aws/aws-sdk-go-v2/service/apigateway v1.21.6 h1:ePPaOVn92r5n8Neecdpy93hDmR0PBH6H6b7VQCE5vKE=
github.com/aws/aws-sdk-go-v2/service/apigateway v1.21.6/go.mod h1:P/zwE9uiC6eK/kL3CS60lxTTVC2zAvaS4iW31io41V4=
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.18.6 h1:bCdxKjM8DpkNJXnOLVx+Hnav0eM4yJK8kof56VvIjMc=
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.18.6/go.mod h1:zQ6tOYz7oGI7MbLRDBXfo63puDoTroVcVNXWfmRDA1E=
github.com/aws/aws-sdk-go-v2/service/apprunner v1.25.5 h1:YpUU6SUj7EYB+l4kGQk2ch5Vz+HK/cn2bfYsJk81+GI=
github.com/aws/aws-sdk-go-v2/service/apprunner v1.25.5/go.mod h1:W1Z87aVGwtb3egdiWLrnMyj5oHzShACix2iebsixuVA=
github.com/aws/aws-sdk-go-v2/service/athena v1.37.3 h1:qNLkDi/rOaauOuh33a4MNZjyfxvwIgC5qsDiHPvjDk0=
github.com/aws/aws-sdk-go-v2/service/athena v1.37.3/go.mod h1:MlpC6swcjh1Il80u6XoeY2BTHIZRZWvoXOfaq3rfh8I=
github.com/aws/aws-sdk-go-v2/service/cloud9 v1.22.5 h1:eSu3COqcATUvidX7AfqOhp6fJadqGD2gTX2Z0oWGUXQ=
github.com/aws/aws-sdk-go-v2/service/cloud9 v1.22.5/go.mod h1:R80rQE5F5/Qf+l4pTpxq8GiEd0OqLo3/S5bNBNEs04A=
github.com/aws/aws-sdk-go-v2/service/cloudformation v1.42.5 h1:5+m0XrCIwjjeP4f3AdC1wyQBc2ClIJi2mP4e3Wkdgvw=
github.com/aws/aws-sdk-go-v2/service/cloudformation v1.42.5/go.mod h1:oPk8ZMctRUtGC13pOE83Zp0baZgJsmzuKm4IRR+zQOI=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.32.5 h1:synDXYpTr5FA80g8twNr49Dd7iAKnxerp93l/kNm/cQ=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.32.5/go.mod h1:Dil6nVeCPyPc1gF5EeCrVUTtXexn80MpfqhgSp/Zb64=
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.35.6 h1:Yc+avPLGARzp4A9Oi9VRxvlcGqI+0MYIg4tPSupKv2U=
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.35.6/go.mod h1:zrqdG1b+4AGoTwTMVFzvzY7ARB3GPo4gKRuK8WPEo8w=
github.com/aws/aws-sdk-go-v2/service/codeartifact v1.23.5 h1:KKuWOQhF/0JPurE6c4Uaem2/Vd221FI0io5gv+rXty0=
github.com/aws/aws-sdk-go-v2/service/codeartifact v1.23.5/go.mod h1:P7DrCurmyD78GbU8IRD+JIK3f9FkeuTe9A8/zXDJv7Q=
github.com/aws/aws-sdk-go-v2/service/codebuild v1.26.5 h1:EPnlDd4V2EXywlOPAw/pMUW4PHUgSulKm4zXFU6bixE=
github.com/aws/aws-sdk-go-v2/service/codebuild v1.26.5/go.mod h1:G2JUWf01sbb5/A8qGcM4dqy4nbl4y4IGWmaCDWAvA2Y=
github.com/aws/aws-sdk-go-v2/service/codecommit v1.20.0 h1:bKW3m6CmWzV/HNqgHiv+HNH0epvyUhnfGAkMzIegUIo=
github.com/aws/aws-sdk-go-v2/service/codecommit v1.20.0/go.mod h1:pI87yFGLN6qjkKhI4Hdh1cpcak8bu/QAJFesJNCSj7k=
github.com/aws/aws-sdk-go-v2/service/codedeploy v1.22.2 h1:3b8fwDhM0bJoOVglvM1w4665Ry6mrb3Rp+AH8iGI6qg=
github.com/aws/aws-sdk-go-v2/service/codedeploy v1.22.2/go.mod h1:RiusqJl55/p7S8LNMh2J3ZsDHDqxRiPdsfIaZRKeEUo=
github.com/aws/aws-sdk-go-v2/service/datapipeline v1.19.5 h1:zkIKbco/gM4fmbU90ajz4ah3ErgAgot7aTE0PpIxNuE=
github.com/aws/aws-sdk-go-v2/service/datapipeline v1.19.5/go.mod h1:+G+TF84SIgMdGDjZKKYPpx6LwXSN4QcywQGa8e2vJ1U=
github.com/aws/aws-sdk-go-v2/service/directoryservice v1.24.4 h1:XBgx3sdaA0SoPXsZSNSUL14H0UnYnTSVArieaYNv0EI=
github.com/aws/aws-sdk-go-v2/service/directoryservice v1.24.4/go.mod h1:Lm/qj7nCC0zEFoAdjbun8xLkflPFNbbspQVZgQQiOz8=
github.com/aws/aws-sdk-go-v2/service/docdb v1.29.5 h1:txsajy47TIyoL7/BQt0VwqmzLPIsfAT/RWI9iD4q5vU=
github.com/aws/aws-sdk-go-v2/service/docdb v1.29.5/go.mod h1:8d1RpdlgxFU6VO2aWru1ckR0Vsm4EgqCZgOamw5OHpw=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.26.7 h1:X60rMbnylU1xmmhv4+/N78t+lKOCC4ELst5eR25dyqg=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.26.7/go.mod h1:o7TD9sjdgrl8l/g2a2IkYjuhxjPy9DMP2sWo7piaRBQ=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.142.0 h1:VrFC1uEZjX4ghkm/et8ATVGb1mT75Iv8aPKPjUE+F8A=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.142.0/go.mod h1:qjhtI9zjpUHRc6khtrIM9fb48+ii6+UikL3/b+MKYn0=
github.com/aws/aws-sdk-go-v2/service/ecr v1.24.6 h1:cT7h+GWP2k0hJSsPmppKgxl4C9R6gCC5/oF4oHnmpK4=
github.com/aws/aws-sdk-go-v2/service/ecr v1.24.6/go.mod h1:AOHmGMoPtSY9Zm2zBuwUJQBisIvYAZeA1n7b6f4e880=
github.com/aws/aws-sdk-go-v2/service/ecs v1.35.6 h1:Sc2mLjyA1R8z2l705AN7Wr7QOlnUxVnGPJeDIVyUSrs=
github.com/aws/aws-sdk-go-v2/service/ecs v1.35.6/go.mod h1:LzHcyOEvaLjbc5e+fP/KmPWBr+h/Ef+EHvnf1Pzo368=
github.com/aws/aws-sdk-go-v2/service/efs v1.26.5 h1:N1ezZV2yy7NV2w/bA4s4I/+0n2xpL4DzlmroEg5qFsg=
github.com/aws/aws-sdk-go-v2/service/efs v1.26.5/go.mod h1:PJHqaboMcF/eLy1F/Y9hyls4CQGP5+T5f0iRq6CPXu4=
github.com/aws/aws-sdk-go-v2/service/eks v1.37.0 h1:tCIkZ/ZdJMGZ1MOwdcioYhOUkkD4F58KFvQTgR3ZIlc=
github.com/aws/aws-sdk-go-v2/service/eks v1.37.0/go.mod h1:L1uv3UgQlAkdM9v0gpec7nnfUiQkCnGMjBE7MJArfWQ=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.34.6 h1:Y/5eE9Sc+OBID9pZ4EVFzyQviv1d1RbqB17HRur9ySg=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.34.6/go.mod h1:iPx2i26hgUULkNh1Jk4QzYzzQKd2nXl/rD9Fm5hQ2uk=
github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.20.5 h1:wUyVpgx2Rs8wYFbzeZTN2uzAuORh8Ea5iV1eIDjatM0=
github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.20.5/go.mod h1:EhlhcjyCljBHkCR17DvnvSnmVYrdgsIzPTH3+vnhaV0=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.21.6 h1:pTyTNb1QVqMT0livj/Goj+68cnJg7fe4o+wFZvasB4M=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.21.6/go.mod h1:N37+67ROdmH7BgLyp1cwCjRpKism3cwkeDlOktRLXMQ=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.26.6 h1:twI2uRmpbm0KBog3Ay61IqOtNp6+QxKfSA78zftME/o=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.26.6/go.mod h1:Tpt4kC8x1HfYuh2rG/6yXZrxjABETERrUl9IdA/IS98=
github.com/aws/aws-sdk-go-v2/service/emr v1.35.6 h1:eJ1K3IaNErKlR8MXg0c4aMjPpvp9qI39WCzx50u+XtQ=
github.com/aws/aws-sdk-go-v2/service/emr v1.35.6/go.mod h1:Drh6y2qLaw/wnDKTIcdqM2m358MIRXsZ2Bj2tjhVLq0=
github.com/aws/aws-sdk-go-v2/service/fsx v1.40.0 h1:bH7oEgVZ4pR27sciaYeNuACsZy6wQXjqRjli54tunOg=
github.com/aws/aws-sdk-go-v2/service/fsx v1.40.0/go.mod h1:GnnK4J/WQajWEAwXd/82wpF275XVhNgsYsXtK1baOjE=
github.com/aws/aws-sdk-go-v2/service/glue v1.73.0 h1:KMA3nvkeQf5I40cFjjl3GaoasKRPtph+J8RfcWlLlWU=
github.com/aws/aws-sdk-go-v2/service/glue v1.73.0/go.mod h1:ALQEuXs/XUdwrkAucRl3juNFbiomoaPICShOoGzHNiE=
github.com/aws/aws-sdk-go-v2/service/grafana v1.18.5 h1:1HGLgX6zvanwVsruEyamDDxXZKQlIPFZYzQVR5Zhv3Q=
github.com/aws/aws-sdk-go-v2/service/grafana v1.18.5/go.mod h1:g9Hl5MYDQtTfNldyymQL5/D93cxP8PGu2B/776IMml0=
github.com/aws/aws-sdk-go-v2/service/iam v1.28.5 h1:Ts2eDDuMLrrmd0ARlg5zSoBQUvhdthgiNnPdiykTJs0=
github.com/aws/aws-sdk-go-v2/service/iam v1.28.5/go.mod h1:kKI0gdVsf+Ev9knh/3lBJbchtX5LLNH25lAzx3KDj3Q=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 h1:/90OR2XbSYfXucBMJ4U14wrjlfleq/0SB6dZDPncgmo=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9/go.mod h1:dN/Of9/fNZet7UrQQ6kTDo/VSwKPIq94vjlU16bRARc=
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.10 h1:h8uweImUHGgyNKrxIUwpPs6XiH0a6DJ17hSJvFLgPAo=
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.8.10/go.mod h1:LZKVtMBiZfdvUWgwg61Qo6kyAmE5rn9Dw36AqnycvG8=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 h1:iEAeF6YC3l4FzlJPP9H3Ko1TXpdjdqWffxXjp8SY6uk=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9/go.mod h1:kjsXoK23q9Z/tLBrckZLLyvjhZoS+AGrzqzUfEClvMM=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.24.6 h1:FO/aIHk86VePDUh/3Q/A5pnvu45miO1GZB8rIq2BUlA=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.24.6/go.mod h1:Sj7qc+P/GOGOPMDn8+B7Cs+WPq1Gk+R6CXRXVhZtWcA=
github.com/aws/aws-sdk-go-v2/service/lambda v1.49.6 h1:w8lI9zlVwRTL9f4KB9fRThddhRivv+EQQzv2nU8JDQo=
github.com/aws/aws-sdk-go-v2/service/lambda v1.49.6/go.mod h1:0V5z1X/8NA9eQ5cZSz5ZaHU8xA/hId2ZAlsHeO7Jrdk=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.32.5 h1:0KVnA62WGcVdeJKH+DTUkxNms2OsIky+AmB2iX93eAs=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.32.5/go.mod h1:wI7palPB84YaqCYglfNiyAlDcXTFbcJ9rDHMu15cFto=
github.com/aws/aws-sdk-go-v2/service/mq v1.20.6 h1:n86T5yw0kS6a5nbpkEpDzLPCBXXb35lx3iDkmQWlizA=
github.com/aws/aws-sdk-go-v2/service/mq v1.20.6/go.mod h1:phfKOOpMQhlBv2KE8gF17P82zLcSedA9b7fMSGTLBdQ=
github.com/aws/aws-sdk-go-v2/service/opensearch v1.27.1 h1:qmxbwQY/gnN7eBElvy9saejXWaKD6ENU8JF5SuoAWLQ=
github.com/aws/aws-sdk-go-v2/service/opensearch v1.27.1/go.mod h1:l89g2sqHGQRg0UZ1ldFfOxh96mZAGn8ZBlaXpoJ2psQ=
github.com/aws/aws-sdk-go-v2/service/organizations v1.23.5 h1:4sW8XPTtuH6PX8CUcpUxBKg0Pf67k1MOOgq9Y+v4ls8=
github.com/aws/aws-sdk-go-v2/service/organizations v1.23.5/go.mod h1:AMzAwJifk4gEft+ElIMFjOb2qUNqHODfjSszVL5Nfeo=
github.com/aws/aws-sdk-go-v2/service/ram v1.23.7 h1:xZdtfxmMRR65HqUFJ3Lfhzkmd9KhVI30TM8Sjj25Pio=
github.com/aws/aws-sdk-go-v2/service/ram v1.23.7/go.mod h1:VgmJolFAkLhZ5Qnnmyfqqyu6+Dt+5E761HzU2ou0Tjg=
github.com/aws/aws-sdk-go-v2/service/rds v1.66.0 h1:WUQ6kmnta31GhQvRJtHPVoO4hSNF8Yh2CQIFCZbhZ8g=
github.com/aws/aws-sdk-go-v2/service/rds v1.66.0/go.mod h1:MYzRMSdY70kcS8AFg0aHmk/xj6VAe0UfaCCoLrBWPow=
github.com/aws/aws-sdk-go-v2/service/redshift v1.39.7 h1:k4WaqQ7LHSGrSftCRXTRLv7WaozXu+fZ1jdisQSR2eU=
github.com/aws/aws-sdk-go-v2/service/redshift v1.39.7/go.mod h1:8hU0Ax6q6QA+jrMcWTE0A4YH594MQoWP3EzGO3GH5Dw=
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.19.6 h1:wiM6xGxWTPI8Yck4efgQGS0lanuMILbng8oukqa4bNM=
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.19.6/go.mod h1:Nngchp1Q7LNBS8J10r4P0npfroNRaCVz6wWNfBz7j4E=
github.com/aws/aws-sdk-go-v2/service/route53 v1.36.0 h1:7wh6KdJnej4T7sE/xfnZf5T+GQzp6GfoZi+5r6ZPlW8=
github.com/aws/aws-sdk-go-v2/service/route53 v1.36.0/go.mod h1:F9El48+5Tf+TkYJB/6M9H7oqXw9Mr9eVetwJ6SUql7g=
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.7 h1:o0ASbVwUAIrfp/WcCac+6jioZt4Hd8k/1X8u7GJ/QeM=
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.7/go.mod h1:vADO6Jn+Rq4nDtfwNjhgR84qkZwiC6FqCaXdw/kYwjA=
github.com/aws/aws-sdk-go-v2/service/sagemaker v1.122.0 h1:YSTmNx+/qyprl8gkBdkxuKW7lI1zPRG7QBSDJVdiZic=
github.com/aws/aws-sdk-go-v2/service/sagemaker v1.122.0/go.mod h1:aGWPLBmB3O7wnYYJLHZdahmPt/ai3QAnOTjxxNmMB2A=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0 h1:dPCRgAL4WD9tSMaDglRNGOiAtSTjkwNiUW5GDpWFfHA=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0/go.mod h1:4Ae1NCLK6ghmjzd45Tc33GgCKhUWD2ORAlULtMO1Cbs=
github.com/aws/aws-sdk-go-v2/service/sfn v1.24.6 h1:agEKwGJ+CyvQ2oARsHsA8fn/CCz7I402CgfWcnhIPGE=
github.com/aws/aws-sdk-go-v2/service/sfn v1.24.6/go.mod h1:goJW4NkHiLfCWTNykK9w7PkACje1y9OIT1IOn8kmRvw=
github.com/aws/aws-sdk-go-v2/service/sns v1.26.6 h1:w2YwF8889ardGU3Y0qZbJ4Zzh+Q/QqKZ4kwkK7JFvnI=
github.com/aws/aws-sdk-go-v2/service/sns v1.26.6/go.mod h1:IrcbquqMupzndZ20BXxDxjM7XenTRhbwBOetk4+Z5oc=
github.com/aws/aws-sdk-go-v2/service/sqs v1.29.6 h1:UdbDTllc7cmusTTMy1dcTrYKRl4utDEsmKh9ZjvhJCc=
github.com/aws/aws-sdk-go-v2/service/sqs v1.29.6/go.mod h1:mCUv04gd/7g+/HNzDB4X6dzJuygji0ckvB3Lg/TdG5Y=
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.6 h1:EZw+TRx/4qlfp6VJ0P1sx04Txd9yGNK+NiO1upaXmh4=
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.6/go.mod h1:uXndCJoDO9gpuK24rNWVCnrGNUydKFEAYAZ7UU9S0rQ=
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM=
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38=
github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 h1:HJeiuZ2fldpd0WqngyMR6KW7ofkXNLyOaHwEIGm39Cs=
github.com/aws/aws-sdk-go-v2/service/sts v1.26.6/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU=
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/Azure/go-autorest/tracing v0.6.1 h1:YUMSrC/CeD1ZnnXcNYU4a/fzsO35u2Fsful9L/2nyR0=
github.com/Azure/go-autorest/tracing v0.6.1/go.mod h1:/3EgjbsjraOqiicERAeu3m7/z0x1TzjQGAwDrJrXGkc=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=
github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE=
github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA=
github.com/aquasecurity/table v1.11.0 h1:SzgCAv7dZcv/gyAyzxorS6OgEk7w/WU5iT2pStIkpl4=
github.com/aquasecurity/table v1.11.0/go.mod h1:eqOmvjjB7AhXFgFqpJUEE/ietg7RrMSJZXyTN8E/wZw=
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
github.com/aws/aws-sdk-go-v2/config v1.32.5 h1:pz3duhAfUgnxbtVhIK39PGF/AHYyrzGEyRD9Og0QrE8=
github.com/aws/aws-sdk-go-v2/config v1.32.5/go.mod h1:xmDjzSUs/d0BB7ClzYPAZMmgQdrodNjPPhd6bGASwoE=
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 h1:xMo63RlqP3ZZydpJDMBsH9uJ10hgHYfQFIk1cHDXrR4=
github.com/aws/aws-sdk-go-v2/credentials v1.19.5/go.mod h1:hhbH6oRcou+LpXfA/0vPElh/e0M3aFeOblE1sssAAEk=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c=
github.com/aws/aws-sdk-go-v2/service/apigateway v1.38.3 h1:nnhGwOSJAnWSwcOINuRUql8/C/l0pCGedsNgv6FSZHs=
github.com/aws/aws-sdk-go-v2/service/apigateway v1.38.3/go.mod h1:U3xTNpFRAV7yduECTfDBDJVFmY5FLrL5HsTSigwOeHs=
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.33.4 h1:FcarAOOdK+8gIYD8/90x7JTOAno+U6IrzMdowePmyBA=
github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.33.4/go.mod h1:pCcxm44Iqac20ss6LXtMfg9eAqrP0HHmovnX5PZuHcE=
github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.9 h1:3MgcobMoBK3IqP2TbuySbdjc79EYCmN+ZRCKQD6d0GU=
github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.9/go.mod h1:n6b+O7QJ6E37dXZYPdLnC4S7Cc5HUYOQPZijLeDKIGY=
github.com/aws/aws-sdk-go-v2/service/athena v1.56.4 h1:kCHAYlcGKCKKDGMRUfnY6pI992vC3UdA3+oPdfDBSHE=
github.com/aws/aws-sdk-go-v2/service/athena v1.56.4/go.mod h1:Whob/cKMykIKxGMQVhPhGEC1+D+bgEDOL7brjSB4ju8=
github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.15 h1:VKLLGKz1jfsQMf/tCjqiqzwha+5n8bcndAqH4/yMJEk=
github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.15/go.mod h1:6eUG6qcUwAACFF/b0fIlZF0sSUwRwY2yJaJ0KoRNjF8=
github.com/aws/aws-sdk-go-v2/service/cloudformation v1.71.4 h1:9dwMueqbHIp0KTw2Zt0rhVobiPMlAI8UgyxiaBzM+1E=
github.com/aws/aws-sdk-go-v2/service/cloudformation v1.71.4/go.mod h1:R4SVh77rxRZut8uzbNhnXcwA5m99OT4hqhHkZjh5NAk=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.58.3 h1:/nyo0QD97D5VQQL/UE+rKGNKz+BesiqJgjdmp0qtTOQ=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.58.3/go.mod h1:Jp0zmzn87l3dKarpDT/qbHNyISst5OnmzMACKuiyMvY=
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.55.4 h1:paDKcKBWPFh/uaTEMPMXyVj5Qsz2dlHaJCi+6yg1C84=
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.55.4/go.mod h1:06x0N2mdQ+l0uv/fjo8p96812Ex8sxq24LmC8JPajmg=
github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.16 h1:2aeK1qzoI6UE7HlSK/CAkY9vpD5SCTl5JmFHp6a9bIA=
github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.16/go.mod h1:6YRsWY0geYy2aMn8sFK5vRKSDRFwVcQlh8iQxYLkVFY=
github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.8 h1:uzot4kkdHaFpj1cjsHilL6B4wjC47pKoGzRBu6Ru/vo=
github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.8/go.mod h1:br0rKgL6SJI6tuipFqqCTwbi8YgQ0zTYi1HHAq0uaBQ=
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.7 h1:dDCQa1O+WlSiOAUBfaOz5jUF0F7jPQgu5R8rr8MwJMY=
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.7/go.mod h1:RG+BocRGH+NSHVRceQhGB+KbtVZvlsQZpRXBjDEYF48=
github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.8 h1:Bx0k8RPrh96xQnpAnWswwwX5ZqEeDH7FB9NbxAXySo4=
github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.8/go.mod h1:bchL+dkmEfUXEfGALO3JxXuX4VzuaKDPlWR+I/0wK/0=
github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.15 h1:Y+vUunZVFB0e121ZbhPO5pJwbkEk8vQvMZ2WCcDFBhU=
github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.15/go.mod h1:vl1x2XdHm+Jyu5dRq9M0VhTkVJ5P17IKCznvnyf1MLI=
github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.11 h1:dH/Ds4gb0NJGr7M1TxQuhYIbC2T0zON2ZQ/BFcl+dgE=
github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.11/go.mod h1:ZCc4ygfV7hmUWSWr+u4Md4HrYH2c8YXLwcVRJyZwW+c=
github.com/aws/aws-sdk-go-v2/service/docdb v1.48.8 h1:K0x4vo5YzRJlwT8CEg7cUibIiY4HVyKiXjscqJbFySE=
github.com/aws/aws-sdk-go-v2/service/docdb v1.48.8/go.mod h1:vdlOC1T3TZh2obQqhQyMp+qDek9+YeemF1EfTNq31GQ=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.5 h1:mSBrQCXMjEvLHsYyJVbN8QQlcITXwHEuu+8mX9e2bSo=
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.5/go.mod h1:eEuD0vTf9mIzsSjGBFWIaNQwtH5/mzViJOVQfnMY5DE=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.276.1 h1:P7db/Z55pXvwnueLuHUuVlxnqjbAtiadm01+QIC42OA=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.276.1/go.mod h1:Wg68QRgy2gEGGdmTPU/UbVpdv8sM14bUZmF64KFwAsY=
github.com/aws/aws-sdk-go-v2/service/ecr v1.54.4 h1:4THfkydiKvFeOFlfY1ABHe4Nsj+Jy6S6tHBqUAojY0M=
github.com/aws/aws-sdk-go-v2/service/ecr v1.54.4/go.mod h1:8n8vVvu7LzveA0or4iWQwNndJStpKOX4HiVHM5jax2U=
github.com/aws/aws-sdk-go-v2/service/ecs v1.69.5 h1:5nkhwt0d/gjuT3AQ2LUK0aFRNB3MGlzB2elqy/ZsKP4=
github.com/aws/aws-sdk-go-v2/service/ecs v1.69.5/go.mod h1:LQMlcWBoiFVD3vUVEz42ST0yTiaDujv2dRE6sXt1yPE=
github.com/aws/aws-sdk-go-v2/service/efs v1.41.9 h1:uHir2myVtdCfpe6ZcmOgmkUFRTUq2mKfhvfQpBcrry4=
github.com/aws/aws-sdk-go-v2/service/efs v1.41.9/go.mod h1:qOhKklI/Hn44U8oZPT16hdCAAjap4PWmCkwDm5YNVPY=
github.com/aws/aws-sdk-go-v2/service/eks v1.76.3 h1:840uwcJTIwrMPLuEUQVFKZbPgwnYzc5WDyXMiMYm5Ts=
github.com/aws/aws-sdk-go-v2/service/eks v1.76.3/go.mod h1:7IU8o/Snul26xioEWN5tgoOas1ISPGsiq5gME5rPh3o=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.8 h1:LiAvvvkFFhvL0AKbsDwEFLC6w4jLOd6r/eNk/b7ZvL4=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.8/go.mod h1:QMDpBJOUoPTE4u4IJjbbmrY9ky+yFe6rU1FdKQtvc30=
github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.18 h1:WNywQvcnq/95BVy9bO6kHcjxHkykMoGze0O5IHA2Xuc=
github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.18/go.mod h1:inFofqLNjvAAY2vtW07FGa63nRPlextd9G/u21x7ZPc=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.18 h1:9/Iq0ZYOzp0kFUFyIF+zpJ3O2iy3tPU/lhswxjv3PD0=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.18/go.mod h1:k5+wZyTFojuJuvXkj95slLYMAvKnUoX2zL3kWu416K0=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.54.5 h1:JjKuK9zbAVv6X44ia/OZrRS8ngOx3QfvtQTN0poJdPw=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.54.5/go.mod h1:qZnMTI+Q9S/C2dNbIMhIH8XMMR3UpO1dgpM4FnH8ZOY=
github.com/aws/aws-sdk-go-v2/service/emr v1.57.4 h1:6gpOrv5HebiRILDlq6quIr4UtmhyxdE0v+tVKdpu0wo=
github.com/aws/aws-sdk-go-v2/service/emr v1.57.4/go.mod h1:qHrbyloGbgvGIYYWn51aHx7HK9gVQKHTWZPLmhlfgtQ=
github.com/aws/aws-sdk-go-v2/service/fsx v1.65.1 h1:1OsMVlUOssZxN48OLHPIyjNWEv1C3OZKHncJHo9T5Wg=
github.com/aws/aws-sdk-go-v2/service/fsx v1.65.1/go.mod h1:RVRf2tjHWVfexLrSH9CJQ0iU7SsDkhIwx0vQ7xzifKM=
github.com/aws/aws-sdk-go-v2/service/glue v1.135.3 h1:Y3AJG3faZeMLkERgg+vdqhLDtBIx+8uc14BvWlxFcCY=
github.com/aws/aws-sdk-go-v2/service/glue v1.135.3/go.mod h1:t3GxMA7CEzEXN6zmI6Br0gSLy+9x4ndsXTk1prQuP7s=
github.com/aws/aws-sdk-go-v2/service/grafana v1.32.9 h1:5UI/ZQ+cW+sPsWe6BHn3K+hW23GVp1bht4REgfE7Rks=
github.com/aws/aws-sdk-go-v2/service/grafana v1.32.9/go.mod h1:QVVGT98da/skEaF+G12IB3AAosDTS57x0bL4bJ9FCuE=
github.com/aws/aws-sdk-go-v2/service/iam v1.53.1 h1:xNCUk9XN6Pa9PyzbEfzgRpvEIVlqtth402yjaWvNMu4=
github.com/aws/aws-sdk-go-v2/service/iam v1.53.1/go.mod h1:GNQZL4JRSGH6L0/SNGOtffaB1vmlToYp3KtcUIB0NhI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo=
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.16 h1:8g4OLy3zfNzLV20wXmZgx+QumI9WhWHnd4GCdvETxs4=
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.16/go.mod h1:5a78jwLMs7BaesU0UIhLfVy2ZmOEgOy6ewYQXKTD37Q=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.9 h1:9Dme/lCNr7GT+n3+AsJV95g5akEhSYeJKoQOcrL8xZ4=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.9/go.mod h1:77+d3nX1hnx0CMC+FG3N34e86SOaEKGpSP+8bQYkX90=
github.com/aws/aws-sdk-go-v2/service/kms v1.49.4 h1:2gom8MohxN0SnhHZBYAC4S8jHG+ENEnXjyJ5xKe3vLc=
github.com/aws/aws-sdk-go-v2/service/kms v1.49.4/go.mod h1:HO31s0qt0lso/ADvZQyzKs8js/ku0fMHsfyXW8OPVYc=
github.com/aws/aws-sdk-go-v2/service/lambda v1.87.0 h1:E5UXxF3vK3JuViwKCHfTJBIiFjvE4aytSucZjI2UAlQ=
github.com/aws/aws-sdk-go-v2/service/lambda v1.87.0/go.mod h1:6f64Y1BEf6e1uCI+LtGbcZSKDK1GvgJ+iI4vP/bbE8s=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.10 h1:MQuZZ6Tq1qQabPlkVxrCMdyVl70Ogl4AERZKo+y9Wzo=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.10/go.mod h1:U5C3JME1ibKESmpzBAqlRpTYZfVbTqrb5ICJm+sVVd8=
github.com/aws/aws-sdk-go-v2/service/mq v1.34.14 h1:mqy/sNV+hiOfa5/GVyAD3Ru25M9ZRmnJrupwTbnbjLA=
github.com/aws/aws-sdk-go-v2/service/mq v1.34.14/go.mod h1:ux7Ft3OASBbfFRODkjpRBaskK6kDBquWWMRgadU9uWg=
github.com/aws/aws-sdk-go-v2/service/opensearch v1.56.0 h1:5fEX9xgasulnog9z/s2tfA1HzxoOcTzjFNZxbRvURYw=
github.com/aws/aws-sdk-go-v2/service/opensearch v1.56.0/go.mod h1:0VgDf/vMiSyGBTP1OrqqdWLpbAJQd9wKfFpLtWffrFQ=
github.com/aws/aws-sdk-go-v2/service/organizations v1.50.0 h1:HGC9bFaqjHWWD8cnNYVbQIrkzZwRJs2UxqdrGnaeSvE=
github.com/aws/aws-sdk-go-v2/service/organizations v1.50.0/go.mod h1:tTgixGOX/GSKJg6/ktn/dc49IYJDxeV+LNxiYE33riU=
github.com/aws/aws-sdk-go-v2/service/ram v1.34.18 h1:KzbQzFBEsdAdJcYDqm7aGYcZEpC3AQZmmoV1biAZceU=
github.com/aws/aws-sdk-go-v2/service/ram v1.34.18/go.mod h1:eqmXZjuKAjyMalpTlvdTmOH8LdJw5m9pbnKI/m6GUPs=
github.com/aws/aws-sdk-go-v2/service/rds v1.113.1 h1:/vV0g/Su8rCTqT57UUYiFU/aRrPXz//fGDn1dkXblG4=
github.com/aws/aws-sdk-go-v2/service/rds v1.113.1/go.mod h1:q02df+DL73LN+jDXzj86tMsI6kKf1kfv61nB684H+o8=
github.com/aws/aws-sdk-go-v2/service/redshift v1.61.4 h1:nufUF8qOf5sSKOBJsTu5sYJnA+sgKGA6712pdIpCSoA=
github.com/aws/aws-sdk-go-v2/service/redshift v1.61.4/go.mod h1:QYBdUiwwcvJ6/RomRedCV4hEKkvI1GtJ35d9Qv2r2Zs=
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.5 h1:0jwTqyyPsbn4UysC6ltj/AuntNBWBeU++kNJQtShtg0=
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.5/go.mod h1:ydy76wx7I+HsqhlEo0vhVTl785TDNbpgtEXhd3i4ZTc=
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0 h1:80pDB3Tpmb2RCSZORrK9/3iQxsd+w6vSzVqpT1FGiwE=
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0/go.mod h1:6EZUGGNLPLh5Unt30uEoA+KQcByERfXIkax9qrc80nA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.2 h1:U3ygWUhCpiSPYSHOrRhb3gOl9T5Y3kB8k5Vjs//57bE=
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.2/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8=
github.com/aws/aws-sdk-go-v2/service/sagemaker v1.228.2 h1:96uJoMTjZ6WdXD0+bCjQib+U42++cYrf4fXbiu7VpEY=
github.com/aws/aws-sdk-go-v2/service/sagemaker v1.228.2/go.mod h1:6TLogKvr0gKvi3GDJd6rZQ9uVl/fkXgCkWUuVD4EdLI=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.0 h1:vL6rQXcGtFv9q/9eRPdI+lL+dvTm7xKGZYSHEvmrpDk=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.0/go.mod h1:QwEDLD+7EukuEUnbWtiNE8LhgvvmhjZoi4XAppYPtyc=
github.com/aws/aws-sdk-go-v2/service/sfn v1.40.5 h1:nhPlRp9oCZOh1M/4zVn4pqguzEJ3Q3emnyS9k8sW8u8=
github.com/aws/aws-sdk-go-v2/service/sfn v1.40.5/go.mod h1:dfVRuB5XudlLMY6PVMu4T2lmfXYMARapmdc2/cUN2Mw=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU=
github.com/aws/aws-sdk-go-v2/service/sns v1.39.10 h1:wqErrLzV3iERQ7dbZbKQS0gOM6ngxZtmPwKyRGn+Krc=
github.com/aws/aws-sdk-go-v2/service/sns v1.39.10/go.mod h1:OiwBtRz6QlQyt69WLBMvSiyfgI7cOd6xSJ9ThTMjI5M=
github.com/aws/aws-sdk-go-v2/service/sqs v1.42.20 h1:qa+1W+Kon3WDwO+8ugco4D9KvO0Pf0KBTn1hN7opIFw=
github.com/aws/aws-sdk-go-v2/service/sqs v1.42.20/go.mod h1:OG0Y3TgC+IeM++ngh+IcEkN24ruGsmRiAP8GUsOhMW8=
github.com/aws/aws-sdk-go-v2/service/ssm v1.67.7 h1:0q42w8/mywPCzQD1IoWIBUCYfBJc5+fLwtZNpHffBSM=
github.com/aws/aws-sdk-go-v2/service/ssm v1.67.7/go.mod h1:urlU9nfKJEfi0+8T9luB3f3Y0UnomH/yxI7tTrfH9es=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 h1:eYnlt6QxnFINKzwxP5/Ucs1vkG7VT3Iezmvfgc2waUw=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/bishopfox/awsservicemap v1.0.3 h1:0T+mJLwG+vQV9+o3dzwzxhWJWE40VpoCLWtaPBwixYc=
github.com/bishopfox/awsservicemap v1.0.3/go.mod h1:oy9Fyqh6AozQjShSx+zRNouTlp7k3z3YEMoFkN8rquc=
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
github.com/bishopfox/awsservicemap v1.1.0 h1:MM+rmGsXjkBtFR1IlS+GpVKR2srGr+V4l/J5JWn4yAY=
github.com/bishopfox/awsservicemap v1.1.0/go.mod h1:oy9Fyqh6AozQjShSx+zRNouTlp7k3z3YEMoFkN8rquc=
github.com/bishopfox/knownawsaccountslookup v0.0.0-20231228165844-c37ef8df33cb h1:ot96tC/kdm0GKV1kl+aXJorqJbyx92R9bjRQvbBmLKU=
github.com/bishopfox/knownawsaccountslookup v0.0.0-20231228165844-c37ef8df33cb/go.mod h1:2OnSqu4B86+2xGSIE5D4z3Rze9yJ/LNNjNXHhwMR+vY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk=
github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk=
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
github.com/charmbracelet/x/ansi v0.11.3 h1:6DcVaqWI82BBVM/atTyq6yBoRLZFBsnoDoX9GCu2YOI=
github.com/charmbracelet/x/ansi v0.11.3/go.mod h1:yI7Zslym9tCJcedxz5+WBq+eUGMJT0bM06Fqy1/Y4dI=
github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4=
github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA=
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
github.com/clipperhouse/displaywidth v0.6.1 h1:/zMlAezfDzT2xy6acHBzwIfyu2ic0hgkT83UX5EY2gY=
github.com/clipperhouse/displaywidth v0.6.1/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w=
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo=
github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY=
github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho=
github.com/go-openapi/strfmt v0.21.10 h1:JIsly3KXZB/Qf4UzvzJpg4OELH/0ASDQsyk//TTBDDk=
github.com/go-openapi/strfmt v0.21.10/go.mod h1:vNDMwbilnl7xKiO/Ve/8H8Bb2JIInBnH+lqiw6QWgis=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM=
github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs=
github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g=
github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4=
github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/errors v0.22.5 h1:Yfv4O/PRYpNF3BNmVkEizcHb3uLVVsrDt3LNdgAKRY4=
github.com/go-openapi/errors v0.22.5/go.mod h1:z9S8ASTUqx7+CP1Q8dD8ewGH/1JWFFLX/2PmAYNQLgk=
github.com/go-openapi/strfmt v0.25.0 h1:7R0RX7mbKLa9EYCTHRcCuIPcaqlyQiWNPTXwClK0saQ=
github.com/go-openapi/strfmt v0.25.0/go.mod h1:nNXct7OzbwrMY9+5tLX4I21pzcmE6ccMGXl3jFdPfn8=
github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
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.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
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.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/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/flatbuffers v25.9.23+incompatible h1:rGZKv+wOb6QPzIdkM2KxhBZCDrA0DeN6DNmRDrqIsQU=
github.com/google/flatbuffers v25.9.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ=
github.com/googleapis/enterprise-certificate-proxy v0.3.7/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo=
github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
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/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/kyokomi/emoji v2.2.4+incompatible h1:np0woGKwx9LiHAQmwZx79Oc0rHpNw3o+3evou4BEPv4=
github.com/kyokomi/emoji v2.2.4+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
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=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/neo4j/neo4j-go-driver/v5 v5.14.0 h1:5x3vD4HkXQIktlG63jSG8v9iweGjmObIPU7Y9U0ThUI=
github.com/neo4j/neo4j-go-driver/v5 v5.14.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/neo4j/neo4j-go-driver/v5 v5.28.4 h1:7toxehVcYkZbyxV4W3Ib9VcnyRBQPucF+VwNNmtSXi4=
github.com/neo4j/neo4j-go-driver/v5 v5.28.4/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
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/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
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.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -390,158 +403,129 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
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/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk=
go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss=
go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE=
go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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-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=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4=
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM=
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
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/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251208220230-2638a1023523 h1:H52Mhyrc44wBgLTGzq6+0cmuVuF3LURCSXsLMOqfFos=
golang.org/x/telemetry v0.0.0-20251208220230-2638a1023523/go.mod h1:ArQvPJS723nJQietgilmZA+shuB3CZxH1n2iXq9VSfs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
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-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E=
gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA=
google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY=
google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY=
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.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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
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=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.257.0 h1:8Y0lzvHlZps53PEaw+G29SsQIkuKrumGWs9puiexNAA=
google.golang.org/api v0.257.0/go.mod h1:4eJrr+vbVaZSqs7vovFd1Jb/A6ml6iw2e6FBYf3GAO4=
google.golang.org/genproto v0.0.0-20251202230838-ff82c1b0f217 h1:GvESR9BIyHUahIb0NcTum6itIWtdoglGX+rnGxm2934=
google.golang.org/genproto v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:yJ2HH4EHEDTd3JiLmhds6NkJ17ITVYOdV3m3VKOnws0=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
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.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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+1
View File
@@ -10,6 +10,7 @@ func LoadFileLinesIntoArray(input string) []string {
if err != nil {
return []string{input}
}
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
+94 -7
View File
@@ -6,6 +6,7 @@ import (
"encoding/gob"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
@@ -155,7 +156,7 @@ func AWSConfigFileLoader(AWSProfile string, version string, AwsMfaToken string)
TxtLog.Fatalf("Could not retrieve the specified profile name %s", err)
} else {
fmt.Printf("[%s][%s] Error retrieving credentials from environment variables, or the instance metadata service.\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", version)), cyan(AWSProfile))
TxtLog.Fatalf("Error retrieving credentials from environment variables, or the instance metadata service.\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", version)), cyan(AWSProfile))
TxtLog.Fatalf("[%s][%s]Error retrieving credentials from environment variables, or the instance metadata service.\n", cyan(emoji.Sprintf(":fox:cloudfox v%s :fox:", version)), cyan(AWSProfile))
}
//os.Exit(1)
}
@@ -243,19 +244,105 @@ func GetEnabledRegions(awsProfile string, version string, AwsMfaToken string) []
}
// ModuleFirstFormatter formats logs with module field before the message
type ModuleFirstFormatter struct {
logrus.TextFormatter
}
func (f *ModuleFirstFormatter) Format(entry *logrus.Entry) ([]byte, error) {
// Use the standard text formatter to get the base format
formatted, err := f.TextFormatter.Format(entry)
if err != nil {
return nil, err
}
// If there's a module field, reformat to put it before msg
if module, ok := entry.Data["module"]; ok {
// Parse the formatted output and rebuild with module first
str := string(formatted)
// Find and extract the module field
moduleStr := fmt.Sprintf("module=%v", module)
// If the formatted string contains the module field, move it before msg=
if idx := strings.Index(str, moduleStr); idx > 0 {
// Remove module from its current position
before := str[:idx]
after := str[idx+len(moduleStr):]
// Trim any extra space that might be left
after = strings.TrimPrefix(after, " ")
// Find where msg= starts
if msgIdx := strings.Index(before, "msg="); msgIdx > 0 {
// Rebuild: everything before msg, then module, then msg and after
newStr := before[:msgIdx] + moduleStr + " " + before[msgIdx:] + after
return []byte(newStr), nil
}
}
}
return formatted, nil
}
// SplitLevelHook is a custom logrus hook that splits logs by level
// Error and Fatal messages go to errorWriter, everything else goes to infoWriter
type SplitLevelHook struct {
errorWriter io.Writer
infoWriter io.Writer
formatter logrus.Formatter
}
func (h *SplitLevelHook) Levels() []logrus.Level {
return logrus.AllLevels
}
func (h *SplitLevelHook) Fire(entry *logrus.Entry) error {
line, err := h.formatter.Format(entry)
if err != nil {
return err
}
switch entry.Level {
case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
_, err = h.errorWriter.Write(line)
default:
_, err = h.infoWriter.Write(line)
}
return err
}
// txtLogger - Returns the txt logger
func TxtLogger() *logrus.Logger {
var txtFile *os.File
var err error
txtLogger := logrus.New()
txtFile, err = os.OpenFile(fmt.Sprintf("%s/cloudfox-error.log", ptr.ToString(GetLogDirPath())), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
// Open error log file (only errors and fatal messages)
errorFile, err := os.OpenFile(fmt.Sprintf("%s/cloudfox-error.log", ptr.ToString(GetLogDirPath())), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
txtFile, err = os.OpenFile(fmt.Sprintf("./cloudfox-error.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
errorFile, err = os.OpenFile(fmt.Sprintf("./cloudfox-error.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
}
if err != nil {
panic(fmt.Sprintf("Failed to open log file %v", err))
panic(fmt.Sprintf("Failed to open error log file %v", err))
}
txtLogger.Out = txtFile
// Open info log file (all non-error messages)
infoFile, err := os.OpenFile(fmt.Sprintf("%s/cloudfox-info.log", ptr.ToString(GetLogDirPath())), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
infoFile, err = os.OpenFile(fmt.Sprintf("./cloudfox-info.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
}
if err != nil {
panic(fmt.Sprintf("Failed to open info log file %v", err))
}
// Discard default output since we're using hooks
txtLogger.SetOutput(io.Discard)
// Add custom hook to split logs by level
txtLogger.AddHook(&SplitLevelHook{
errorWriter: errorFile,
infoWriter: infoFile,
formatter: &ModuleFirstFormatter{},
})
txtLogger.SetLevel(logrus.InfoLevel)
//txtLogger.SetReportCaller(true)
+4 -4
View File
@@ -22,7 +22,7 @@ func ParseJSONPolicy(data []byte) (Policy, error) {
return p, nil
}
// IsNull returns true iff the Policy is empty
// IsEmpty returns true if the Policy is empty
// you cannot do a comparison like this: `p == Policy{}' since we use custom types in the struct`
func (p *Policy) IsEmpty() bool {
out := true
@@ -37,7 +37,7 @@ func (p *Policy) IsEmpty() bool {
return out
}
// true iff there is at least one statement with principal * and no conditions
// IsPublic true if there is at least one statement with principal * and no conditions
func (p *Policy) IsPublic() bool {
for _, s := range p.Statement {
if s.IsAllow() && s.Principal.IsPublic() && s.Condition.IsEmpty() {
@@ -48,7 +48,7 @@ func (p *Policy) IsPublic() bool {
return false
}
// true iff there is at least one statement with principal * with conditions that do not scope access down to AWS accounts or organizations
// IsConditionallyPublic true if there is at least one statement with principal * with conditions that do not scope access down to AWS accounts or organizations
func (p *Policy) IsConditionallyPublic() bool {
for _, s := range p.Statement {
if s.IsAllow() && s.Principal.IsPublic() && !s.Condition.IsScopedOnAccountOrOrganization() && !s.Condition.IsEmpty() {
@@ -99,8 +99,8 @@ func composePattern(stringToTransform string) *regexp.Regexp {
return pattern
}
// source: https://github.com/nccgroup/PMapper/blob/master/principalmapper/querying/local_policy_simulation.py
// MatchesAfterExpansion checks the stringToCheck against stringToCheckAgainst.
// source: https://github.com/nccgroup/PMapper/blob/master/principalmapper/querying/local_policy_simulation.py
func MatchesAfterExpansion(stringFromPolicyToCheck, stringToCheckAgainst string) bool {
// Transform the stringToCheckAgainst into a regex pattern
pattern := composePattern(stringToCheckAgainst)
+48
View File
@@ -222,3 +222,51 @@ func TestDoesPolicyHaveMatchingStatement(t *testing.T) {
}
}
}
func TestDoesPermissionExpansionMatch(t *testing.T) {
tests := []struct {
actionToExpand string
actionToCheckAgainst string
want bool
}{
{
actionToExpand: "sts:AssumeRole",
actionToCheckAgainst: "sts:AssumeRole",
want: true,
},
{
actionToExpand: "*",
actionToCheckAgainst: "sts:AssumeRole",
want: true,
},
{
actionToExpand: "sts:Assume*",
actionToCheckAgainst: "sts:AssumeRole",
want: true,
},
{
actionToExpand: "sts:*",
actionToCheckAgainst: "sts:AssumeRole",
want: true,
},
{
actionToExpand: "s3:GetObject",
actionToCheckAgainst: "sts:AssumeRole",
want: false,
},
{
actionToExpand: "s3:*",
actionToCheckAgainst: "sts:AssumeRole",
want: false,
},
}
for _, tt := range tests {
actual := MatchesAfterExpansion(tt.actionToCheckAgainst, tt.actionToExpand)
if tt.want != actual {
//fmt.Printf("DoesPermissionHaveMatchingStatement(%s, %s) is %v but should be %v", tt.actionToExpand, tt.actionToCheckAgainst, actual, tt.want)
t.Errorf("DoesPermissionHaveMatchingStatement(%s, %s) is %v but should be %v", tt.actionToExpand, tt.actionToCheckAgainst, actual, tt.want)
}
}
}
Loaded 100 of 103 files, more files were not shown because too many files have changed in this diff. Show more