Compare commits

..
8 Commits
Author SHA1 Message Date
jbarciabf ba4ff4701a Merge pull request #130 from BishopFox/fix/network-ports-map-race
Fix concurrent map access race in network-ports module and bump version to 2.0.5
2026-05-26 10:45:11 -04:00
jbarciabf 81be56e006 Bump version to 2.0.5 2026-05-26 10:42:29 -04:00
jbarciabf 494443d7ce Fix concurrent map access race in network-ports module (#129)
The NetworkPortsModule cached EC2 NACLs and Security Groups in two
per-region maps. The cache lookup read the maps without holding a
lock while the cache population path took a write lock, producing a
"concurrent map read and map write" runtime panic when multiple
region goroutines hit the cache check concurrently. The panic
reproduced reliably in low-density AWS accounts where every region
goroutine raced through the cache check at the same instant.

Take the read lock on the cache fast-path in both
getEC2NACLsPerRegion and getEC2SecurityGroupsPerRegion. Move
naclsMutex and securityGroupsMutex from package-level vars onto the
module struct so concurrent module instances stop serializing on
each other's locks.

Convert CommandCounter from plain int fields with naked ++/-- to
int64 fields with Incr/Decr/Load methods that use atomic.AddInt64
and atomic.LoadInt64 internally. Worker goroutines and the spinner
goroutine were updating and reading the same counters without
synchronization, producing torn integer writes that could show as
off-by-one progress in the spinner. Plain int64 storage keeps the
struct copyable so existing constructors and helpers that take
modules by value continue to vet-clean.

Add TestNetworkPortsCacheConcurrentAccess as a regression test.
With the read lock removed, "go test -race" reports the
mapaccess2_faststr read racing the locked write; with the fix in
place the test passes.
2026-05-26 10:36:17 -04:00
Joseph Barcia 3d3cfc6c0c Update GitHub Actions to Node 24 compatible versions
- actions/checkout v4 -> v6
- actions/setup-go v4 -> v5
- go-version ^1.20 -> ^1.25
- Replace abandoned marvinpinto/action-automatic-releases with
  softprops/action-gh-release v2

Node.js 20 actions are deprecated and will be forced to Node 24
starting June 2, 2026, and removed September 16, 2026.
2026-05-26 10:30:22 -04:00
jbarciabf 1b0925877d Merge pull request #127 from BishopFox/fix/pmapper-basepath-all-checks
Fix pmapper-data-basepath ignored in all-checks and instances race condition
2026-04-21 09:06:40 -04:00
Joseph Barcia 7727d1d08c Fix pmapper-data-basepath ignored in all-checks and race condition in instances module
The pmapperCommand in runAllChecksCommand was missing the
PmapperDataBasePath parameter, causing --pmapper-data-basepath to be
ignored for the pmapper module when running all-checks. (Fixes #105)

The instances module had a race condition where role analysis ran before
the receiver goroutine finished collecting all MappedInstances. This
caused IsAdminRole and CanPrivEscToAdmin columns to appear empty in
all-checks despite pmapper data being available. Fixed by signaling
the receiver to stop and waiting for it to drain before running role
analysis.

Version bumped to 2.0.4.
2026-04-21 13:06:11 +00:00
jbarciabf c7f81dc5cc Merge pull request #126 from mitre88/main
Fix --pmapper-data-basepath ignored in all-checks for EC2 user data module
2026-04-21 09:02:34 -04:00
Open Source Contributor 008fb84d23 Fix --pmapper-data-basepath ignored in all-checks for EC2 user data module
The EC2 user data InstancesModule in runAllChecksCommand was not receiving
the PmapperDataBasePath parameter, causing the --pmapper-data-basepath flag
to be ignored when running all-checks.

Fix: Add PmapperDataBasePath: PmapperDataBasePath to the ec2UserData struct
initialization in runAllChecksCommand.
2026-04-20 20:38:56 -06:00
168 changed files with 1573 additions and 5183 deletions

No files matched your search

+6 -9
View File
@@ -15,10 +15,10 @@ jobs:
steps:
- name: Go 1.21
uses: actions/setup-go@v4
- name: Go 1.25
uses: actions/setup-go@v5
with:
go-version: ^1.20
go-version: ^1.25
id: go
- id: install-secret-key
@@ -28,7 +28,7 @@ jobs:
gpg --list-secret-keys --keyid-format LONG
- name: Check Out Code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Git Fetch Tags
run: git fetch --prune --unshallow --tags -f
@@ -39,9 +39,6 @@ jobs:
- name: Release binaries
uses: "marvinpinto/action-automatic-releases@latest"
uses: softprops/action-gh-release@v2
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
files: |
./cloudfox/*
files: ./cloudfox/*
+1 -1
View File
@@ -11,6 +11,6 @@ jobs:
codespell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- run: pip install --user codespell
- run: codespell --ignore-words-list="aks,referers,invokable" --skip="*.sum"
+1 -45
View File
@@ -110,7 +110,7 @@ Additional policy notes (as of 09/2022):
### GCP
* Google Cloud SDK installed and authenticated
* Application Default Credentials configured (`gcloud auth application-default login`), or use `--key-file` / `--access-token` / `--impersonate-sa` flags
* Application Default Credentials configured (`gcloud auth application-default login`)
* Recommended permissions at appropriate hierarchy levels (see below)
#### GCP Permissions: Minimal vs Comprehensive
@@ -204,50 +204,6 @@ For detailed setup instructions, see the [GCP Setup Guide](https://github.com/Bi
| Azure | [vms](https://github.com/BishopFox/cloudfox/wiki/Azure-Commands#vms) | Enumerates useful information for Compute instances in all available resource groups and subscriptions |
# GCP Global Flags
All GCP commands support these flags:
### Authentication
| Flag | Description |
| - | - |
| `--access-token` | Raw GCP access token for authentication (non-refreshable) |
| `-i, --impersonate-sa` | Service account email to impersonate (requires `roles/iam.serviceAccountTokenCreator`) |
| `-k, --key-file` | Path to a service account JSON key file for authentication |
If no authentication flags are provided, CloudFox uses Application Default Credentials (ADC). You can combine `--key-file` or `--access-token` with `--impersonate-sa` to impersonate using a specific base credential.
### Query Filtering
| Flag | Description |
| - | - |
| `-q, --query` | Filter output rows by substring match or column-aware key:value syntax |
| `--sqlquery` | Filter output with SQL-like WHERE clause syntax |
**`--query` examples:**
```bash
# Plain substring (matches any column)
cloudfox gcp -p my-project iam --query "privesc02"
# Column-specific: Role contains "owner" AND Principal contains "privesc02"
cloudfox gcp -p my-project serviceaccounts --query "Role:owner,Principal:privesc02"
# Negation: Role contains "owner" but Principal does NOT contain "compute"
cloudfox gcp -p my-project serviceaccounts --query "Role:owner,!Principal:compute"
# Exact match on column value
cloudfox gcp -p my-project iam --query "Role=roles/owner"
```
**`--sqlquery` examples:**
```bash
cloudfox gcp -p my-project serviceaccounts \
--sqlquery "Role CONTAINS owner AND Principal CONTAINS privesc02"
cloudfox gcp -p my-project iam --sqlquery "Source != Project"
```
For full query filtering documentation, see the [GCP Commands Wiki - Query Filtering](https://github.com/BishopFox/cloudfox/wiki/GCP-Commands#query-filtering).
# GCP Commands
For detailed documentation on each GCP command, see the [GCP Commands Wiki](https://github.com/BishopFox/cloudfox/wiki/GCP-Commands).
+2 -2
View File
@@ -161,7 +161,7 @@ func (m *AccessKeysModule) getAccessKeysForAllUsers() {
ListUsers, err := sdk.CachedIamListUsers(m.IAMClient, aws.ToString(m.Caller.Account))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
// added this to break out if there no users
@@ -171,7 +171,7 @@ func (m *AccessKeysModule) getAccessKeysForAllUsers() {
results, err := sdk.CachedIamListAccessKeys(m.IAMClient, aws.ToString(m.Caller.Account), aws.ToString(user.UserName))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
+47 -47
View File
@@ -191,19 +191,19 @@ func (m *ApiGwModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAPIGatewayAPIsPerRegion(r, wg, semaphore, dataReceiver)
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAPIGatewayVIPsPerRegion(r, wg, semaphore, dataReceiver)
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAPIGatewayv2APIsPerRegion(r, wg, semaphore, dataReceiver)
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAPIGatewayv2VIPsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -244,7 +244,7 @@ func (m *ApiGwModule) writeLoot(outputDirectory string, verbosity int) string {
// err = os.WriteFile(f, []byte(out), 0644)
// if err != nil {
// m.modLog.Error(err.Error())
// m.CommandCounter.Error++
// m.CommandCounter.IncrError()
// panic(err.Error())
// }
@@ -263,8 +263,8 @@ func (m *ApiGwModule) writeLoot(outputDirectory string, verbosity int) string {
func (m *ApiGwModule) getAPIGatewayAPIsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan ApiGateway) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -272,21 +272,21 @@ func (m *ApiGwModule) getAPIGatewayAPIsPerRegion(r string, wg *sync.WaitGroup, s
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
Items, err := sdk.CachedApiGatewayGetRestAPIs(m.APIGatewayClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
for _, api := range Items {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
for _, endpoint := range m.getEndpointsPerAPIGateway(r, api) {
dataReceiver <- endpoint
}
@@ -295,8 +295,8 @@ func (m *ApiGwModule) getAPIGatewayAPIsPerRegion(r string, wg *sync.WaitGroup, s
func (m *ApiGwModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan ApiGateway) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -304,16 +304,16 @@ func (m *ApiGwModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGroup, s
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
Items, err := sdk.CachedApiGatewayGetRestAPIs(m.APIGatewayClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -322,7 +322,7 @@ func (m *ApiGwModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGroup, s
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -334,7 +334,7 @@ func (m *ApiGwModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGroup, s
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -347,7 +347,7 @@ func (m *ApiGwModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGroup, s
for _, api := range Items {
if api.Id != nil && aws.ToString(api.Id) == aws.ToString(mapping.RestApiId) {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
endpoints := m.getEndpointsPerAPIGateway(r, api)
for _, endpoint := range endpoints {
@@ -376,8 +376,8 @@ func (m *ApiGwModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGroup, s
func (m *ApiGwModule) getEndpointsPerAPIGateway(r string, api apigatewayTypes.RestApi) []ApiGateway {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
var gateways []ApiGateway
@@ -402,7 +402,7 @@ func (m *ApiGwModule) getEndpointsPerAPIGateway(r string, api apigatewayTypes.Re
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return gateways
}
@@ -411,7 +411,7 @@ func (m *ApiGwModule) getEndpointsPerAPIGateway(r string, api apigatewayTypes.Re
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, stage := range GetStages.Item {
@@ -427,7 +427,7 @@ func (m *ApiGwModule) getEndpointsPerAPIGateway(r string, api apigatewayTypes.Re
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -454,8 +454,8 @@ func (m *ApiGwModule) getEndpointsPerAPIGateway(r string, api apigatewayTypes.Re
func (m *ApiGwModule) getAPIGatewayv2APIsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan ApiGateway) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -463,20 +463,20 @@ func (m *ApiGwModule) getAPIGatewayv2APIsPerRegion(r string, wg *sync.WaitGroup,
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
Items, err := sdk.CachedAPIGatewayv2GetAPIs(m.APIGatewayv2Client, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
for _, api := range Items {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
for _, endpoint := range m.getEndpointsPerAPIGatewayv2(r, api) {
dataReceiver <- endpoint
}
@@ -486,8 +486,8 @@ func (m *ApiGwModule) getAPIGatewayv2APIsPerRegion(r string, wg *sync.WaitGroup,
func (m *ApiGwModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan ApiGateway) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -495,16 +495,16 @@ func (m *ApiGwModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGroup,
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
Items, err := sdk.CachedAPIGatewayv2GetAPIs(m.APIGatewayv2Client, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -513,7 +513,7 @@ func (m *ApiGwModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGroup,
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, item := range GetDomainNames {
@@ -524,7 +524,7 @@ func (m *ApiGwModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGroup,
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -537,7 +537,7 @@ func (m *ApiGwModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGroup,
for _, api := range Items {
if api.ApiId != nil && aws.ToString(api.ApiId) == aws.ToString(mapping.ApiId) {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
endpoints := m.getEndpointsPerAPIGatewayv2(r, api)
for _, endpoint := range endpoints {
var old string
@@ -568,8 +568,8 @@ func (m *ApiGwModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGroup,
func (m *ApiGwModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2Types.Api) []ApiGateway {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
var gateways []ApiGateway
@@ -588,7 +588,7 @@ func (m *ApiGwModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2Type
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, stage := range GetStages {
@@ -603,7 +603,7 @@ func (m *ApiGwModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2Type
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, stage := range stages {
@@ -643,7 +643,7 @@ func (m *ApiGwModule) ApiGatewayApiKeyRequired(r string, ApiId *string, Resource
if err != nil {
m.Errors = append(m.Errors, fmt.Sprintf(" Error: Region: %s", r))
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
} else {
return aws.ToBool(GetMethod.ApiKeyRequired)
}
+7 -7
View File
@@ -88,7 +88,7 @@ func (m *BucketsModule) PrintBuckets(outputDirectory string, verbosity int) {
go m.Receiver(dataReceiver, receiverDone)
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(wg, semaphore, dataReceiver)
wg.Wait()
@@ -203,11 +203,11 @@ func (m *BucketsModule) Receiver(receiver chan BucketRow, receiverDone chan bool
func (m *BucketsModule) executeChecks(wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan BucketRow) {
defer wg.Done()
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.createBucketsRows(m.output.Verbosity, wg, semaphore, dataReceiver)
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}
func (m *BucketsModule) writeLoot(outputDirectory string, verbosity int, profile string) {
@@ -256,8 +256,8 @@ func (m *BucketsModule) writeLoot(outputDirectory string, verbosity int, profile
func (m *BucketsModule) createBucketsRows(verbosity int, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan BucketRow) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -357,7 +357,7 @@ func (m *BucketsModule) storeAccessPolicy(bucket *BucketRow) {
if err := m.storeFile(f, bucket.PolicyJSON); err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+8 -8
View File
@@ -80,7 +80,7 @@ func (m *CloudformationModule) PrintCloudformationStacks(outputDirectory string,
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -206,7 +206,7 @@ func (m *CloudformationModule) executeChecks(r string, wg *sync.WaitGroup, semap
}
for _, serviceRegion := range serviceRegions {
if r == serviceRegion {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.createCFStackRowsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -231,7 +231,7 @@ func (m *CloudformationModule) writeLoot(outputDirectory string, verbosity int)
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
pullFile := filepath.Join(path, "cloudformation-data.txt")
@@ -271,7 +271,7 @@ func (m *CloudformationModule) writeLoot(outputDirectory string, verbosity int)
err = os.WriteFile(pullFile, []byte(out), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
if verbosity > 2 {
@@ -288,8 +288,8 @@ func (m *CloudformationModule) writeLoot(outputDirectory string, verbosity int)
func (m *CloudformationModule) createCFStackRowsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan CFStack) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -302,7 +302,7 @@ func (m *CloudformationModule) createCFStackRowsPerRegion(r string, wg *sync.Wai
DescribeStacks, err := sdk.CachedCloudFormationDescribeStacks(m.CloudFormationClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, stack := range DescribeStacks {
@@ -314,7 +314,7 @@ func (m *CloudformationModule) createCFStackRowsPerRegion(r string, wg *sync.Wai
stackTemplateBody, err = sdk.CachedCloudFormationGetTemplate(m.CloudFormationClient, aws.ToString(m.Caller.Account), r, stackName)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
dataReceiver <- CFStack{
+2 -2
View File
@@ -87,7 +87,7 @@ func (m *CodeBuildModule) PrintCodeBuildProjects(outputDirectory string, verbosi
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -224,7 +224,7 @@ func (m *CodeBuildModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getcodeBuildProjectsPerRegion(r, wg, semaphore, dataReceiver)
}
+25 -25
View File
@@ -260,7 +260,7 @@ func (m *DatabasesModule) executeCheck(check check) {
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
check.wg.Add(1)
go check.executor(check.region, check.wg, check.semaphore, check.dataReceiver)
}
@@ -324,7 +324,7 @@ func (m *DatabasesModule) writeLoot(outputDirectory string, verbosity int) strin
// err = os.WriteFile(f, []byte(out), 0644)
// if err != nil {
// m.modLog.Error(err.Error())
// m.CommandCounter.Error++
// m.CommandCounter.IncrError()
// panic(err.Error())
// }
@@ -343,8 +343,8 @@ func (m *DatabasesModule) writeLoot(outputDirectory string, verbosity int) strin
func (m *DatabasesModule) getRdsClustersPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Database) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -352,13 +352,13 @@ func (m *DatabasesModule) getRdsClustersPerRegion(r string, wg *sync.WaitGroup,
defer func() {
<-semaphore
}()
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
DBClusters, err := sdk.CachedRDSDescribeDBClusters(m.RDSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -411,8 +411,8 @@ 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++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -420,14 +420,14 @@ func (m *DatabasesModule) getRdsInstancesPerRegion(r string, wg *sync.WaitGroup,
defer func() {
<-semaphore
}()
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
DBInstances, err := sdk.CachedRDSDescribeDBInstances(m.RDSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -480,8 +480,8 @@ func (m *DatabasesModule) getRdsInstancesPerRegion(r string, wg *sync.WaitGroup,
func (m *DatabasesModule) getRedshiftDatabasesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Database) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -489,9 +489,9 @@ func (m *DatabasesModule) getRedshiftDatabasesPerRegion(r string, wg *sync.WaitG
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
awsService := "Redshift"
protocol := "https"
@@ -502,7 +502,7 @@ func (m *DatabasesModule) getRedshiftDatabasesPerRegion(r string, wg *sync.WaitG
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++
m.CommandCounter.IncrError()
return
}
@@ -532,8 +532,8 @@ func (m *DatabasesModule) getRedshiftDatabasesPerRegion(r string, wg *sync.WaitG
func (m *DatabasesModule) getDynamoDBTablesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Database) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -541,15 +541,15 @@ func (m *DatabasesModule) getDynamoDBTablesPerRegion(r string, wg *sync.WaitGrou
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
awsService := "DynamoDB"
Tables, err := sdk.CachedDynamoDBListTables(m.DynamoDBClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -558,7 +558,7 @@ func (m *DatabasesModule) getDynamoDBTablesPerRegion(r string, wg *sync.WaitGrou
TableOutput, err := sdk.CachedDynamoDBDescribeTable(m.DynamoDBClient, aws.ToString(m.Caller.Account), r, table)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
size := aws.ToInt64(TableOutput.TableSizeBytes)
+4 -4
View File
@@ -84,7 +84,7 @@ func (m *DirectoryModule) PrintDirectories(outputDirectory string, verbosity int
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -203,7 +203,7 @@ func (m *DirectoryModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getDirectoriesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -223,8 +223,8 @@ func (m *DirectoryModule) Receiver(receiver chan Directory, receiverDone chan bo
}
func (m *DirectoryModule) getDirectoriesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Directory) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
+11 -11
View File
@@ -84,7 +84,7 @@ func (m *ECRModule) PrintECR(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -210,7 +210,7 @@ func (m *ECRModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan s
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getECRRecordsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -234,7 +234,7 @@ func (m *ECRModule) writeLoot(outputDirectory string, verbosity int) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
pullFile := filepath.Join(path, "ecr-pull-commands.txt")
@@ -259,7 +259,7 @@ func (m *ECRModule) writeLoot(outputDirectory string, verbosity int) {
err = os.WriteFile(pullFile, []byte(out), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
if verbosity > 2 {
@@ -277,8 +277,8 @@ func (m *ECRModule) writeLoot(outputDirectory string, verbosity int) {
func (m *ECRModule) getECRRecordsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Repository) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -290,7 +290,7 @@ func (m *ECRModule) getECRRecordsPerRegion(r string, wg *sync.WaitGroup, semapho
Repositories, err := sdk.CachedECRDescribeRepositories(m.ECRClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -302,7 +302,7 @@ func (m *ECRModule) getECRRecordsPerRegion(r string, wg *sync.WaitGroup, semapho
images, err := sdk.CachedECRDescribeImages(m.ECRClient, aws.ToString(m.Caller.Account), r, repoName)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
continue
}
@@ -350,7 +350,7 @@ func (m *ECRModule) getECRRecordsPerRegion(r string, wg *sync.WaitGroup, semapho
// var repositories []types.Repository
// Repositories, err := sdk.CachedECRDescribeRepositories(m.ECRClient, aws.ToString(m.Caller.Account), r)
// if err != nil {
// m.CommandCounter.Error++
// m.CommandCounter.IncrError()
// return nil, err
// }
@@ -364,7 +364,7 @@ func (m *ECRModule) getECRRecordsPerRegion(r string, wg *sync.WaitGroup, semapho
// ImageDetails, err := sdk.CachedECRDescribeImages(m.ECRClient, aws.ToString(m.Caller.Account), r, repoName)
// if err != nil {
// m.CommandCounter.Error++
// m.CommandCounter.IncrError()
// return nil, err
// }
// images = append(images, ImageDetails...)
@@ -375,7 +375,7 @@ func (m *ECRModule) getECRRepositoryPolicy(r string, repository string) (policy.
var repoPolicy policy.Policy
Policy, err := sdk.CachedECRGetRepositoryPolicy(m.ECRClient, aws.ToString(m.Caller.Account), r, repository)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return repoPolicy, err
}
repoPolicy, err = policy.ParseJSONPolicy([]byte(Policy))
+18 -18
View File
@@ -100,7 +100,7 @@ func (m *ECSTasksModule) ECSTasks(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, dataReceiver)
}
@@ -254,7 +254,7 @@ func (m *ECSTasksModule) writeLoot(outputDirectory string) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
privateIPsFilename := filepath.Join(path, "ecs-tasks-PrivateIPs.txt")
publicIPsFilename := filepath.Join(path, "ecs-tasks-PublicIPs.txt")
@@ -274,12 +274,12 @@ func (m *ECSTasksModule) writeLoot(outputDirectory string) {
err = os.WriteFile(privateIPsFilename, []byte(privateIPs), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
err = os.WriteFile(publicIPsFilename, []byte(publicIPs), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, task := range m.MappedECSTasks {
@@ -288,14 +288,14 @@ func (m *ECSTasksModule) writeLoot(outputDirectory string) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
taskDefinitionFilename := filepath.Join(path, task.TaskDefinitionName+".json")
err = os.WriteFile(taskDefinitionFilename, []byte(task.TaskDefinitionContent), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
}
@@ -321,12 +321,12 @@ func (m *ECSTasksModule) executeChecks(r string, wg *sync.WaitGroup, dataReceive
}
if res {
m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
m.getListClusters(r, dataReceiver)
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}
}
@@ -335,7 +335,7 @@ func (m *ECSTasksModule) getListClusters(region string, dataReceiver chan Mapped
ClusterArns, err := sdk.CachedECSListClusters(m.ECSClient, aws.ToString(m.Caller.Account), region)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -349,7 +349,7 @@ func (m *ECSTasksModule) getListTasks(clusterARN string, region string, dataRece
TaskArns, err := sdk.CachedECSListTasks(m.ECSClient, aws.ToString(m.Caller.Account), region, clusterARN)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -374,7 +374,7 @@ func (m *ECSTasksModule) loadTasksData(clusterARN string, taskARNs []string, reg
Tasks, err := sdk.CachedECSDescribeTasks(m.ECSClient, aws.ToString(m.Caller.Account), region, clusterARN, taskARNs)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -388,7 +388,7 @@ func (m *ECSTasksModule) loadTasksData(clusterARN string, taskARNs []string, reg
publicIPs, err := m.loadPublicIPs(eniIDs, region)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -397,7 +397,7 @@ func (m *ECSTasksModule) loadTasksData(clusterARN string, taskARNs []string, reg
taskDefinition, err := sdk.CachedECSDescribeTaskDefinition(m.ECSClient, aws.ToString(m.Caller.Account), region, aws.ToString(task.TaskDefinitionArn))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
mappedTask := MappedECSTask{
@@ -446,7 +446,7 @@ func (m *ECSTasksModule) describeTaskDefinition(taskDefinitionArn string, region
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return types.TaskDefinition{}, err
}
return *DescribeTaskDefinition.TaskDefinition, nil
@@ -466,7 +466,7 @@ func (m *ECSTasksModule) loadAllPublicIPs(eniIDs []string, region string) (map[s
publicIPs, err := m.loadPublicIPs(eniIDs[i:j], region)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return nil, fmt.Errorf("getting elastic network interfaces: %s", err)
}
+9 -9
View File
@@ -102,7 +102,7 @@ func (m *EKSModule) EKS(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -255,7 +255,7 @@ func (m *EKSModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan s
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getEKSRecordsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -279,7 +279,7 @@ func (m *EKSModule) writeLoot(outputDirectory string, verbosity int) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
pullFile := filepath.Join(path, "eks-kubeconfig-commands.txt")
@@ -303,7 +303,7 @@ func (m *EKSModule) writeLoot(outputDirectory string, verbosity int) {
err = os.WriteFile(pullFile, []byte(out), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
if verbosity > 2 {
@@ -322,8 +322,8 @@ func (m *EKSModule) writeLoot(outputDirectory string, verbosity int) {
func (m *EKSModule) getEKSRecordsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Cluster) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -336,7 +336,7 @@ func (m *EKSModule) getEKSRecordsPerRegion(r string, wg *sync.WaitGroup, semapho
clusters, err := sdk.CachedEKSListClusters(m.EKSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -347,7 +347,7 @@ func (m *EKSModule) getEKSRecordsPerRegion(r string, wg *sync.WaitGroup, semapho
clusterDetails, err := sdk.CachedEKSDescribeCluster(m.EKSClient, aws.ToString(m.Caller.Account), clusterName, r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
//nodeGroups = append(nodeGroups, DescribeCluster.Cluster.)
@@ -373,7 +373,7 @@ func (m *EKSModule) getEKSRecordsPerRegion(r string, wg *sync.WaitGroup, semapho
nodeGroupDetails, err := sdk.CachedEKSDescribeNodeGroup(m.EKSClient, aws.ToString(m.Caller.Account), clusterName, nodeGroup, r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
role = aws.ToString(nodeGroupDetails.NodeRole)
+10 -10
View File
@@ -73,7 +73,7 @@ func (m *ElasticNetworkInterfacesModule) ElasticNetworkInterfaces(outputDirector
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, dataReceiver)
}
@@ -199,7 +199,7 @@ func (m *ElasticNetworkInterfacesModule) writeLoot(outputDirectory string) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
privateIPsFilename := filepath.Join(path, "elastic-network-interfaces-PrivateIPs.txt")
publicIPsFilename := filepath.Join(path, "elastic-network-interfaces-PublicIPs.txt")
@@ -219,12 +219,12 @@ func (m *ElasticNetworkInterfacesModule) writeLoot(outputDirectory string) {
err = os.WriteFile(privateIPsFilename, []byte(privateIPs), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
err = os.WriteFile(publicIPsFilename, []byte(publicIPs), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
fmt.Printf("[%s][%s] Loot written to [%s]\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), privateIPsFilename)
@@ -246,12 +246,12 @@ func (m *ElasticNetworkInterfacesModule) executeChecks(r string, wg *sync.WaitGr
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
m.getDescribeNetworkInterfaces(r, dataReceiver)
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}
}
@@ -272,7 +272,7 @@ func (m *ElasticNetworkInterfacesModule) getDescribeNetworkInterfaces(region str
// )
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
+134 -134
View File
@@ -280,7 +280,7 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getLambdaFunctionsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -289,7 +289,7 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getEksClustersPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -298,7 +298,7 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getMqBrokersPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -307,7 +307,7 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getOpenSearchPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -316,7 +316,7 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getGrafanaEndPointsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -325,11 +325,11 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getELBv2ListenersPerRegion(r, wg, semaphore, dataReceiver)
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getELBListenersPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -338,19 +338,19 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAPIGatewayAPIsPerRegion(r, wg, semaphore, dataReceiver)
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAPIGatewayVIPsPerRegion(r, wg, semaphore, dataReceiver)
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAPIGatewayv2APIsPerRegion(r, wg, semaphore, dataReceiver)
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAPIGatewayv2VIPsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -359,7 +359,7 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getRdsClustersPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -368,13 +368,13 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getRedshiftEndPointsPerRegion(r, wg, semaphore, dataReceiver)
}
//apprunner is not supported by the aws json so we have to call it in every region
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAppRunnerEndpointsPerRegion(r, wg, semaphore, dataReceiver)
@@ -383,7 +383,7 @@ func (m *EndpointsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getLightsailContainerEndpointsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -394,7 +394,7 @@ func (m *EndpointsModule) writeLoot(outputDirectory string, verbosity int) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
panic(err.Error())
}
f := filepath.Join(path, "endpoints-UrlsOnly.txt")
@@ -408,7 +408,7 @@ func (m *EndpointsModule) writeLoot(outputDirectory string, verbosity int) {
err = os.WriteFile(f, []byte(out), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
panic(err.Error())
}
@@ -425,8 +425,8 @@ func (m *EndpointsModule) writeLoot(outputDirectory string, verbosity int) {
func (m *EndpointsModule) getLambdaFunctionsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -434,16 +434,16 @@ func (m *EndpointsModule) getLambdaFunctionsPerRegion(r string, wg *sync.WaitGro
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
var public string
Functions, err := sdk.CachedLambdaListFunctions(m.LambdaClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -455,7 +455,7 @@ func (m *EndpointsModule) getLambdaFunctionsPerRegion(r string, wg *sync.WaitGro
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++
m.CommandCounter.IncrError()
continue
}
endpoint := aws.ToString(FunctionDetails.FunctionUrl)
@@ -482,8 +482,8 @@ func (m *EndpointsModule) getLambdaFunctionsPerRegion(r string, wg *sync.WaitGro
func (m *EndpointsModule) getEksClustersPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -491,15 +491,15 @@ func (m *EndpointsModule) getEksClustersPerRegion(r string, wg *sync.WaitGroup,
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
Clusters, err := sdk.CachedEKSListClusters(m.EKSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -511,7 +511,7 @@ func (m *EndpointsModule) getEksClustersPerRegion(r string, wg *sync.WaitGroup,
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++
m.CommandCounter.IncrError()
continue
}
var endpoint string
@@ -545,8 +545,8 @@ func (m *EndpointsModule) getEksClustersPerRegion(r string, wg *sync.WaitGroup,
func (m *EndpointsModule) getMqBrokersPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -554,14 +554,14 @@ func (m *EndpointsModule) getMqBrokersPerRegion(r string, wg *sync.WaitGroup, se
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
BrokerSummaries, err := sdk.CachedMQListBrokers(m.MQClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -584,7 +584,7 @@ func (m *EndpointsModule) getMqBrokersPerRegion(r string, wg *sync.WaitGroup, se
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++
m.CommandCounter.IncrError()
continue
}
if aws.ToBool(BrokerDetails.PubliclyAccessible) {
@@ -611,8 +611,8 @@ func (m *EndpointsModule) getMqBrokersPerRegion(r string, wg *sync.WaitGroup, se
func (m *EndpointsModule) getOpenSearchPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -620,14 +620,14 @@ func (m *EndpointsModule) getOpenSearchPerRegion(r string, wg *sync.WaitGroup, s
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
DomainNames, err := sdk.CachedOpenSearchListDomainNames(m.OpenSearchClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -641,7 +641,7 @@ func (m *EndpointsModule) getOpenSearchPerRegion(r string, wg *sync.WaitGroup, s
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++
m.CommandCounter.IncrError()
return
}
@@ -663,7 +663,7 @@ func (m *EndpointsModule) getOpenSearchPerRegion(r string, wg *sync.WaitGroup, s
domainConfig, err := sdk.CachedOpenSearchDescribeDomainConfig(m.OpenSearchClient, aws.ToString(m.Caller.Account), r, name)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
if aws.ToBool(domainConfig.AdvancedSecurityOptions.Options.Enabled) {
@@ -697,8 +697,8 @@ func (m *EndpointsModule) getOpenSearchPerRegion(r string, wg *sync.WaitGroup, s
func (m *EndpointsModule) getGrafanaEndPointsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -706,14 +706,14 @@ func (m *EndpointsModule) getGrafanaEndPointsPerRegion(r string, wg *sync.WaitGr
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
ListWorkspaces, err := sdk.CachedGrafanaListWorkspaces(m.GrafanaClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -743,8 +743,8 @@ func (m *EndpointsModule) getGrafanaEndPointsPerRegion(r string, wg *sync.WaitGr
func (m *EndpointsModule) getELBv2ListenersPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -752,16 +752,16 @@ func (m *EndpointsModule) getELBv2ListenersPerRegion(r string, wg *sync.WaitGrou
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
awsService := "ELBv2"
LoadBalancers, err := sdk.CachedELBv2DescribeLoadBalancers(m.ELBv2Client, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -787,7 +787,7 @@ func (m *EndpointsModule) getELBv2ListenersPerRegion(r string, wg *sync.WaitGrou
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++
m.CommandCounter.IncrError()
continue
}
if scheme == "internet-facing" {
@@ -823,8 +823,8 @@ func (m *EndpointsModule) getELBv2ListenersPerRegion(r string, wg *sync.WaitGrou
func (m *EndpointsModule) getELBListenersPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -832,16 +832,16 @@ func (m *EndpointsModule) getELBListenersPerRegion(r string, wg *sync.WaitGroup,
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
awsService := "ELB"
LoadBalancerDescriptions, err := sdk.CachedELBDescribeLoadBalancers(m.ELBClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
var public string
@@ -883,8 +883,8 @@ func (m *EndpointsModule) getELBListenersPerRegion(r string, wg *sync.WaitGroup,
func (m *EndpointsModule) getAPIGatewayAPIsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -892,16 +892,16 @@ func (m *EndpointsModule) getAPIGatewayAPIsPerRegion(r string, wg *sync.WaitGrou
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
Items, err := sdk.CachedApiGatewayGetRestAPIs(m.APIGatewayClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -914,8 +914,8 @@ func (m *EndpointsModule) getAPIGatewayAPIsPerRegion(r string, wg *sync.WaitGrou
func (m *EndpointsModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -923,15 +923,15 @@ func (m *EndpointsModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGrou
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
Items, err := sdk.CachedApiGatewayGetRestAPIs(m.APIGatewayClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -942,7 +942,7 @@ func (m *EndpointsModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGrou
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++
m.CommandCounter.IncrError()
}
for _, item := range GetDomainNames {
@@ -955,7 +955,7 @@ func (m *EndpointsModule) getAPIGatewayVIPsPerRegion(r string, wg *sync.WaitGrou
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++
m.CommandCounter.IncrError()
break
}
@@ -1020,7 +1020,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGateway(r string, api apigatewayType
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++
m.CommandCounter.IncrError()
}
GetResources, err := sdk.CachedApiGatewayGetResources(m.APIGatewayClient, aws.ToString(m.Caller.Account), r, id)
@@ -1030,7 +1030,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGateway(r string, api apigatewayType
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++
m.CommandCounter.IncrError()
}
for _, stage := range GetStages.Item {
@@ -1059,8 +1059,8 @@ func (m *EndpointsModule) getEndpointsPerAPIGateway(r string, api apigatewayType
func (m *EndpointsModule) getAPIGatewayv2APIsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -1068,16 +1068,16 @@ func (m *EndpointsModule) getAPIGatewayv2APIsPerRegion(r string, wg *sync.WaitGr
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
Items, err := sdk.CachedAPIGatewayv2GetAPIs(m.APIGatewayv2Client, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
for _, api := range Items {
@@ -1090,8 +1090,8 @@ func (m *EndpointsModule) getAPIGatewayv2APIsPerRegion(r string, wg *sync.WaitGr
func (m *EndpointsModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -1099,15 +1099,15 @@ func (m *EndpointsModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGr
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
Items, err := sdk.CachedAPIGatewayv2GetAPIs(m.APIGatewayv2Client, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -1118,7 +1118,7 @@ func (m *EndpointsModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGr
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++
m.CommandCounter.IncrError()
}
for _, item := range GetDomainNames {
@@ -1131,7 +1131,7 @@ func (m *EndpointsModule) getAPIGatewayv2VIPsPerRegion(r string, wg *sync.WaitGr
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++
m.CommandCounter.IncrError()
break
}
@@ -1193,7 +1193,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2
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++
m.CommandCounter.IncrError()
}
for _, stage := range GetStages {
@@ -1211,7 +1211,7 @@ func (m *EndpointsModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2
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++
m.CommandCounter.IncrError()
}
for _, stage := range stages {
@@ -1246,8 +1246,8 @@ func (m *EndpointsModule) getEndpointsPerAPIGatewayv2(r string, api apigatewayV2
func (m *EndpointsModule) getRdsClustersPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -1255,9 +1255,9 @@ func (m *EndpointsModule) getRdsClustersPerRegion(r string, wg *sync.WaitGroup,
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
DBInstances, err := sdk.CachedRDSDescribeDBInstances(m.RDSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
@@ -1265,7 +1265,7 @@ func (m *EndpointsModule) getRdsClustersPerRegion(r string, wg *sync.WaitGroup,
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++
m.CommandCounter.IncrError()
return
}
@@ -1300,8 +1300,8 @@ func (m *EndpointsModule) getRdsClustersPerRegion(r string, wg *sync.WaitGroup,
func (m *EndpointsModule) getRedshiftEndPointsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -1309,9 +1309,9 @@ func (m *EndpointsModule) getRedshiftEndPointsPerRegion(r string, wg *sync.WaitG
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
awsService := "Redshift"
protocol := "https"
@@ -1323,7 +1323,7 @@ func (m *EndpointsModule) getRedshiftEndPointsPerRegion(r string, wg *sync.WaitG
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++
m.CommandCounter.IncrError()
return
}
@@ -1360,8 +1360,8 @@ UNUSED CODE - PLEASE REVIEW AND DELETE IF IT DOESN'T APPLY
func (m *EndpointsModule) getS3EndpointsPerRegion(wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -1369,9 +1369,9 @@ UNUSED CODE - PLEASE REVIEW AND DELETE IF IT DOESN'T APPLY
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// 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).
ListBuckets, _ := m.S3Client.ListBuckets(
@@ -1434,8 +1434,8 @@ UNUSED CODE - PLEASE REVIEW AND DELETE IF IT DOESN'T APPLY
*/
func (m *EndpointsModule) getCloudfrontEndpoints(wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -1443,9 +1443,9 @@ func (m *EndpointsModule) getCloudfrontEndpoints(wg *sync.WaitGroup, semaphore c
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
var PaginationControl *string
var awsService = "Cloudfront"
@@ -1466,7 +1466,7 @@ func (m *EndpointsModule) getCloudfrontEndpoints(wg *sync.WaitGroup, semaphore c
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++
m.CommandCounter.IncrError()
break
}
if ListDistributions.DistributionList.Quantity == nil {
@@ -1546,8 +1546,8 @@ func (m *EndpointsModule) getCloudfrontEndpoints(wg *sync.WaitGroup, semaphore c
func (m *EndpointsModule) getAppRunnerEndpointsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -1555,15 +1555,15 @@ func (m *EndpointsModule) getAppRunnerEndpointsPerRegion(r string, wg *sync.Wait
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
ServiceSummaryList, err := sdk.CachedAppRunnerListServices(m.AppRunnerClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
for _, service := range ServiceSummaryList {
@@ -1590,7 +1590,7 @@ func (m *EndpointsModule) getAppRunnerEndpointsPerRegion(r string, wg *sync.Wait
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1614,7 +1614,7 @@ func (m *EndpointsModule) getAppRunnerEndpointsPerRegion(r string, wg *sync.Wait
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
if DescribeCustomDomains.DNSTarget != nil {
@@ -1667,8 +1667,8 @@ func (m *EndpointsModule) appRunnerDescribeCustomDomain(r string, serviceArn str
func (m *EndpointsModule) getLightsailContainerEndpointsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Endpoint) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -1676,9 +1676,9 @@ func (m *EndpointsModule) getLightsailContainerEndpointsPerRegion(r string, wg *
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
var public = "True"
var protocol = "https"
var port int32 = 443
@@ -1687,7 +1687,7 @@ func (m *EndpointsModule) getLightsailContainerEndpointsPerRegion(r string, wg *
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
if len(containerServices) > 0 {
+45 -45
View File
@@ -105,7 +105,7 @@ func (m *EnvsModule) PrintEnvs(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -290,7 +290,7 @@ func (m *EnvsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan
}
res, _ := servicemap.IsServiceInRegion("ecs", r)
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getECSEnvironmentVariablesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -300,13 +300,13 @@ func (m *EnvsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getLambdaEnvironmentVariablesPerRegion(r, wg, semaphore, dataReceiver)
}
// AppRunner is not supported in the aws service region catalog so we have to run it in all regions
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAppRunnerEnvironmentVariablesPerRegion(r, wg, semaphore, dataReceiver)
@@ -315,7 +315,7 @@ func (m *EnvsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getLightsailEnvironmentVariablesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -325,7 +325,7 @@ func (m *EnvsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getSagemakerEnvironmentVariablesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -334,8 +334,8 @@ func (m *EnvsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan
func (m *EnvsModule) getECSEnvironmentVariablesPerRegion(region string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan EnvironmentVariable) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -343,9 +343,9 @@ func (m *EnvsModule) getECSEnvironmentVariablesPerRegion(region string, wg *sync
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
//var PaginationMarker *string
@@ -364,7 +364,7 @@ func (m *EnvsModule) getECSEnvironmentVariablesPerRegion(region string, wg *sync
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
for _, containerDefinition := range DescribeTaskDefinition.TaskDefinition.ContainerDefinitions {
@@ -390,7 +390,7 @@ func (m *EnvsModule) getTaskDefinitionFamilies(region string) []string {
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -425,8 +425,8 @@ func (m *EnvsModule) getECSEnvironmentVariablesPerDefinition(taskDefinition ecsT
func (m *EnvsModule) getLambdaEnvironmentVariablesPerRegion(region string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan EnvironmentVariable) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -434,14 +434,14 @@ func (m *EnvsModule) getLambdaEnvironmentVariablesPerRegion(region string, wg *s
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
Functions, err := sdk.CachedLambdaListFunctions(m.LambdaClient, aws.ToString(m.Caller.Account), region)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -467,8 +467,8 @@ func (m *EnvsModule) getLambdaEnvironmentVariablesPerFunction(function lambdaTyp
func (m *EnvsModule) getAppRunnerEnvironmentVariablesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan EnvironmentVariable) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -476,16 +476,16 @@ func (m *EnvsModule) getAppRunnerEnvironmentVariablesPerRegion(r string, wg *syn
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
ServiceSummaryList, err := sdk.CachedAppRunnerListServices(m.AppRunnerClient, aws.ToString(m.Caller.Account), r)
if err != nil {
//modLog.Error(err.Error())
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
if len(ServiceSummaryList) > 0 {
@@ -506,7 +506,7 @@ func (m *EnvsModule) getAppRunnerEnvironmentVariablesPerRegion(r string, wg *syn
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -530,8 +530,8 @@ func (m *EnvsModule) getAppRunnerEnvironmentVariablesPerRegion(r string, wg *syn
func (m *EnvsModule) getLightsailEnvironmentVariablesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan EnvironmentVariable) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -539,16 +539,16 @@ func (m *EnvsModule) getLightsailEnvironmentVariablesPerRegion(r string, wg *syn
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
awsService := "Lightsail [Container]"
ContainerServices, err := sdk.CachedLightsailGetContainerServices(m.LightsailClient, aws.ToString(m.Caller.Account), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -574,8 +574,8 @@ func (m *EnvsModule) getLightsailEnvironmentVariablesPerRegion(r string, wg *syn
func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan EnvironmentVariable) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -583,9 +583,9 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
awsService := "Sagemaker"
var PaginationControl *string
@@ -603,7 +603,7 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -621,7 +621,7 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -665,7 +665,7 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -683,7 +683,7 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -726,7 +726,7 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -744,7 +744,7 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -788,7 +788,7 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -805,7 +805,7 @@ func (m *EnvsModule) getSagemakerEnvironmentVariablesPerRegion(r string, wg *syn
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
+16 -16
View File
@@ -245,7 +245,7 @@ func (m *FilesystemsModule) writeLoot(outputDirectory string, verbosity int) {
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
f := filepath.Join(path, "filesystems-mount-commands.txt")
@@ -283,7 +283,7 @@ func (m *FilesystemsModule) writeLoot(outputDirectory string, verbosity int) {
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
fmt.Printf("[%s][%s] Loot written to [%s]\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), f)
if verbosity > 2 {
@@ -297,20 +297,20 @@ func (m *FilesystemsModule) writeLoot(outputDirectory string, verbosity int) {
func (m *FilesystemsModule) getEFSSharesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan FilesystemObject) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
var policy string
DescribeFileSystems, err := sdk.CachedDescribeFileSystems(m.EFSClient, aws.ToString(m.Caller.Account), r)
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -336,7 +336,7 @@ func (m *FilesystemsModule) getEFSSharesPerRegion(r string, wg *sync.WaitGroup,
DescribeMountTargets, err := sdk.CachedDescribeMountTargets(m.EFSClient, aws.ToString(m.Caller.Account), r, id)
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -349,7 +349,7 @@ func (m *FilesystemsModule) getEFSSharesPerRegion(r string, wg *sync.WaitGroup,
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
dataReceiver <- FilesystemObject{
AWSService: awsService,
Region: r,
@@ -381,14 +381,14 @@ func (m *FilesystemsModule) getEFSSharesPerRegion(r string, wg *sync.WaitGroup,
func (m *FilesystemsModule) getFSxSharesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan FilesystemObject) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
var PaginationMarker *string
var PaginationMarker2 *string
@@ -410,7 +410,7 @@ func (m *FilesystemsModule) getFSxSharesPerRegion(r string, wg *sync.WaitGroup,
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
+16 -16
View File
@@ -276,7 +276,7 @@ func (m *IamSimulatorModule) writeLoot(outputDirectory string, verbosity int, pm
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
outFile := filepath.Join(path, "iam-simulator-pmapper-commands.txt")
@@ -292,7 +292,7 @@ func (m *IamSimulatorModule) writeLoot(outputDirectory string, verbosity int, pm
err = os.WriteFile(outFile, []byte(out), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
if verbosity > 2 {
@@ -329,18 +329,18 @@ func (m *IamSimulatorModule) executeChecks(wg *sync.WaitGroup, resource string,
func (m *IamSimulatorModule) getIAMUsers(wg *sync.WaitGroup, actions []string, resource string, dataReceiver chan SimulatorResult) {
defer func() {
wg.Done()
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
ListUsers, err := sdk.CachedIamListUsers(m.IAMClient, aws.ToString(m.Caller.Account))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -369,19 +369,19 @@ func (m *IamSimulatorModule) getIAMUsers(wg *sync.WaitGroup, actions []string, r
func (m *IamSimulatorModule) getIAMRoles(wg *sync.WaitGroup, actions []string, resource string, dataReceiver chan SimulatorResult) {
defer func() {
wg.Done()
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
ListRoles, err := sdk.CachedIamListRoles(m.IAMClient, aws.ToString(m.Caller.Account))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -419,7 +419,7 @@ func (m *IamSimulatorModule) getPolicySimulatorResult(principal *string, actionN
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
m.modLog.Error(fmt.Sprintf("Failed to query actions for %s\n\n", aws.ToString(principal)))
return
}
@@ -464,7 +464,7 @@ func (m *IamSimulatorModule) isPrincipalAnAdmin(principal *string) bool {
)
if err != nil {
m.modLog.Error(err)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
m.modLog.Errorf("Failed admin check on %s", aws.ToString(principal))
return false
}
+23 -21
View File
@@ -122,15 +122,19 @@ func (m *InstancesModule) Instances(filter string, outputDirectory string, verbo
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(instancesToSearch, region, wg, dataReceiver)
}
wg.Wait()
//time.Sleep(time.Second * 2)
// Perform role analysis
// Signal the receiver to stop and wait for it to finish draining the channel.
// This must happen BEFORE role analysis to ensure all MappedInstances are collected.
receiverDone <- true
<-receiverDone
// Perform role analysis (all instances are now in m.MappedInstances)
if m.pmapperError == nil {
for i := range m.MappedInstances {
m.MappedInstances[i].Admin, m.MappedInstances[i].CanPrivEsc = GetPmapperResults(m.SkipAdminCheck, m.pmapperMod, &m.MappedInstances[i].Role)
@@ -144,8 +148,6 @@ func (m *InstancesModule) Instances(filter string, outputDirectory string, verbo
// Send a message to the spinner goroutine to close the channel and stop
spinnerDone <- true
<-spinnerDone
receiverDone <- true
<-receiverDone
// This conditional block will either dump the userData attribute content or the general instances data, depending on what you select via command line.
//fmt.Printf("\n[*] Preparing output...\n\n")
@@ -180,7 +182,7 @@ func (m *InstancesModule) printInstancesUserDataAttributesOnly(outputDirectory s
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
userDataFileName := filepath.Join(path, fmt.Sprintf("%s.txt", m.output.CallingModule))
@@ -212,7 +214,7 @@ func (m *InstancesModule) printInstancesUserDataAttributesOnly(outputDirectory s
err = os.WriteFile(userDataFileName, []byte(userDataOut), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
fmt.Printf("[%s][%s] Loot written to [%s]\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), userDataFileName)
} else {
@@ -343,7 +345,7 @@ func (m *InstancesModule) writeLoot(outputDirectory string, verbosity int) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
privateIPsFilename := filepath.Join(path, "instances-ec2PrivateIPs.txt")
publicIPsFilename := filepath.Join(path, "instances-ec2PublicIPs.txt")
@@ -394,22 +396,22 @@ func (m *InstancesModule) writeLoot(outputDirectory string, verbosity int) {
err = os.WriteFile(privateIPsFilename, []byte(privateIPs), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
err = os.WriteFile(publicIPsFilename, []byte(publicIPs), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
err = os.WriteFile(ssmCommandsFilename, []byte(ssmCommands), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
err = os.WriteFile(ec2InstanceConnectCommandsFilename, []byte(ec2InstanceConnectCommands), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
fmt.Printf("[%s][%s] Loot written to [%s]\n", cyan(m.output.CallingModule), cyan(m.AWSProfile), privateIPsFilename)
@@ -446,17 +448,17 @@ func (m *InstancesModule) executeChecks(instancesToSearch []string, r string, wg
res, err := servicemap.IsServiceInRegion("ec2", r)
if err != nil {
m.modLog.Errorf("Error checking if EC2 is available in region %s: %v", r, err)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
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--
m.CommandCounter.Executing++
m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
m.getDescribeInstances(instancesToSearch, r, dataReceiver)
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
} else {
m.modLog.Infof("Skipping region %s: EC2 not available or check failed", r)
}
@@ -467,7 +469,7 @@ func (m *InstancesModule) getInstanceUserDataAttribute(instanceID *string, regio
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return nil, err
} else {
if UserData == "" {
@@ -487,7 +489,7 @@ func (m *InstancesModule) getDescribeInstances(instancesToSearch []string, regio
Instances, err := sdk.CachedEC2DescribeInstances(m.EC2Client, aws.ToString(m.Caller.Account), region)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -586,7 +588,7 @@ func (m *InstancesModule) getRolesFromInstanceProfiles() {
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
for _, instanceProfile := range ListInstanceProfiles.InstanceProfiles {
+335 -335
View File
File diff suppressed because it is too large. Load diff
+9 -9
View File
@@ -105,7 +105,7 @@ func (m *LambdasModule) PrintLambdas(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -241,7 +241,7 @@ func (m *LambdasModule) executeChecks(r string, wg *sync.WaitGroup, semaphore ch
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getLambdasPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -265,7 +265,7 @@ func (m *LambdasModule) writeLoot(outputDirectory string, verbosity int) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
pullFile := filepath.Join(path, "lambda-get-function-commands.txt")
@@ -289,7 +289,7 @@ func (m *LambdasModule) writeLoot(outputDirectory string, verbosity int) {
err = os.WriteFile(pullFile, []byte(out), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
if verbosity > 2 {
@@ -306,8 +306,8 @@ func (m *LambdasModule) writeLoot(outputDirectory string, verbosity int) {
func (m *LambdasModule) getLambdasPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Lambda) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -319,7 +319,7 @@ func (m *LambdasModule) getLambdasPerRegion(r string, wg *sync.WaitGroup, semaph
functions, err := m.listFunctions(r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, function := range functions {
@@ -360,7 +360,7 @@ func (m *LambdasModule) listFunctions(r string) ([]types.FunctionConfiguration,
)
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return functions, err
}
functions = append(functions, ListFunctions.Functions...)
@@ -389,7 +389,7 @@ func (m *LambdasModule) getResourcePolicy(r string, functionName string) (policy
)
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return projectPolicy, err
}
+66 -61
View File
@@ -50,9 +50,6 @@ var (
# Make sure the host you scan IPv6 from has an IPv6 network interface.
#############################################
`
naclsMutex = sync.RWMutex{}
securityGroupsMutex = sync.RWMutex{}
)
type NetworkPortsModule struct {
@@ -77,11 +74,13 @@ type NetworkPortsModule struct {
ServiceMap *awsservicemap.AwsServiceMap // Shared service map to avoid repeated HTTP requests
// Main module data
IPv4_Private []NetworkService
IPv4_Public []NetworkService
IPv6 []NetworkService
nacls map[string]*[]ec2_types.NetworkAcl
securityGroups map[string]*[]ec2_types.SecurityGroup
IPv4_Private []NetworkService
IPv4_Public []NetworkService
IPv6 []NetworkService
nacls map[string]*[]ec2_types.NetworkAcl
securityGroups map[string]*[]ec2_types.SecurityGroup
naclsMutex sync.RWMutex
securityGroupsMutex sync.RWMutex
CommandCounter internal.CommandCounter
// Used to store output data for pretty printing
@@ -172,7 +171,7 @@ func (m *NetworkPortsModule) PrintNetworkPorts(outputDirectory string) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, dataReceiver)
}
@@ -287,7 +286,7 @@ func (m *NetworkPortsModule) executeChecks(r string, wg *sync.WaitGroup, dataRec
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
m.getEC2NetworkPortsPerRegion(r, dataReceiver)
}
@@ -296,7 +295,7 @@ func (m *NetworkPortsModule) executeChecks(r string, wg *sync.WaitGroup, dataRec
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
m.getECSNetworkPortsPerRegion(r, dataReceiver)
}
@@ -305,7 +304,7 @@ func (m *NetworkPortsModule) executeChecks(r string, wg *sync.WaitGroup, dataRec
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
m.getEFSNetworkPortsPerRegion(r, dataReceiver)
}
@@ -314,7 +313,7 @@ func (m *NetworkPortsModule) executeChecks(r string, wg *sync.WaitGroup, dataRec
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
m.getElastiCacheNetworkPortsPerRegion(r, dataReceiver)
}
@@ -323,7 +322,7 @@ func (m *NetworkPortsModule) executeChecks(r string, wg *sync.WaitGroup, dataRec
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
m.getLBNetworkPortsPerRegion(r, dataReceiver)
}
@@ -332,7 +331,7 @@ func (m *NetworkPortsModule) executeChecks(r string, wg *sync.WaitGroup, dataRec
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
m.getLightsailNetworkPortsPerRegion(r, dataReceiver)
}
@@ -341,7 +340,7 @@ func (m *NetworkPortsModule) executeChecks(r string, wg *sync.WaitGroup, dataRec
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
m.getRdsNetworkPortsPerRegion(r, dataReceiver)
}
@@ -429,8 +428,8 @@ func (m *NetworkPortsModule) writeLootFile(filename string, bannner string, ipv4
func (m *NetworkPortsModule) getEC2NetworkPortsPerRegion(r string, dataReceiver chan NetworkServices) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
securityGroups := m.getEC2SecurityGroupsPerRegion(r)
nacls := m.getEC2NACLsPerRegion(r)
@@ -533,8 +532,8 @@ func (m *NetworkPortsModule) getEC2NetworkPortsPerRegion(r string, dataReceiver
func (m *NetworkPortsModule) getECSNetworkPortsPerRegion(r string, dataReceiver chan NetworkServices) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
securityGroups := m.getEC2SecurityGroupsPerRegion(r)
nacls := m.getEC2NACLsPerRegion(r)
@@ -548,7 +547,7 @@ func (m *NetworkPortsModule) getECSNetworkPortsPerRegion(r string, dataReceiver
service, err := m.describeECSService(serviceArn, &clusterArn, r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -585,7 +584,7 @@ func (m *NetworkPortsModule) getECSNetworkPortsPerRegion(r string, dataReceiver
task, err := m.describeECSTask(taskArn, &clusterArn, r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -668,8 +667,8 @@ func (m *NetworkPortsModule) getECSNetworkPortsPerRegion(r string, dataReceiver
func (m *NetworkPortsModule) getEFSNetworkPortsPerRegion(r string, dataReceiver chan NetworkServices) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
securityGroups := m.getEC2SecurityGroupsPerRegion(r)
nacls := m.getEC2NACLsPerRegion(r)
@@ -731,8 +730,8 @@ func (m *NetworkPortsModule) getEFSNetworkPortsPerRegion(r string, dataReceiver
func (m *NetworkPortsModule) getElastiCacheNetworkPortsPerRegion(r string, dataReceiver chan NetworkServices) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
securityGroups := m.getEC2SecurityGroupsPerRegion(r)
nacls := m.getEC2NACLsPerRegion(r)
@@ -843,8 +842,8 @@ func (m *NetworkPortsModule) getElastiCacheNetworkPortsPerRegion(r string, dataR
func (m *NetworkPortsModule) getLBNetworkPortsPerRegion(r string, dataReceiver chan NetworkServices) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
securityGroups := m.getEC2SecurityGroupsPerRegion(r)
nacls := m.getEC2NACLsPerRegion(r)
@@ -959,8 +958,8 @@ func (m *NetworkPortsModule) getLBNetworkPortsPerRegion(r string, dataReceiver c
func (m *NetworkPortsModule) getLightsailNetworkPortsPerRegion(r string, dataReceiver chan NetworkServices) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
instances := m.getLightsailInstancesPerRegion(r)
@@ -1070,8 +1069,8 @@ func (m *NetworkPortsModule) getLightsailNetworkPortsPerRegion(r string, dataRec
func (m *NetworkPortsModule) getRdsNetworkPortsPerRegion(r string, dataReceiver chan NetworkServices) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}()
securityGroups := m.getEC2SecurityGroupsPerRegion(r)
nacls := m.getEC2NACLsPerRegion(r)
@@ -1143,13 +1142,16 @@ func (m *NetworkPortsModule) getRdsNetworkPortsPerRegion(r string, dataReceiver
}
func (m *NetworkPortsModule) getEC2SecurityGroupsPerRegion(region string) []ec2_types.SecurityGroup {
m.securityGroupsMutex.RLock()
cached, ok := m.securityGroups[region]
m.securityGroupsMutex.RUnlock()
if ok && cached != nil {
return *cached
}
var securityGroups []ec2_types.SecurityGroup
var PaginationControl *string
if m.securityGroups[region] != nil {
return *m.securityGroups[region]
}
for {
DescribeSecurityGroups, err := m.EC2Client.DescribeSecurityGroups(
context.TODO(),
@@ -1162,7 +1164,7 @@ func (m *NetworkPortsModule) getEC2SecurityGroupsPerRegion(region string) []ec2_
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1176,9 +1178,9 @@ func (m *NetworkPortsModule) getEC2SecurityGroupsPerRegion(region string) []ec2_
}
}
securityGroupsMutex.Lock()
m.securityGroupsMutex.Lock()
m.securityGroups[region] = &securityGroups
securityGroupsMutex.Unlock()
m.securityGroupsMutex.Unlock()
return securityGroups
}
@@ -1215,13 +1217,16 @@ func (m *NetworkPortsModule) parseSecurityGroup(group ec2_types.SecurityGroup) S
}
func (m *NetworkPortsModule) getEC2NACLsPerRegion(region string) []ec2_types.NetworkAcl {
m.naclsMutex.RLock()
cached, ok := m.nacls[region]
m.naclsMutex.RUnlock()
if ok && cached != nil {
return *cached
}
var nacls []ec2_types.NetworkAcl
var PaginationControl *string
if m.nacls[region] != nil {
return *m.nacls[region]
}
for {
DescribeNetworkAcls, err := m.EC2Client.DescribeNetworkAcls(
context.TODO(),
@@ -1234,7 +1239,7 @@ func (m *NetworkPortsModule) getEC2NACLsPerRegion(region string) []ec2_types.Net
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1248,9 +1253,9 @@ func (m *NetworkPortsModule) getEC2NACLsPerRegion(region string) []ec2_types.Net
}
}
naclsMutex.Lock()
m.naclsMutex.Lock()
m.nacls[region] = &nacls
naclsMutex.Unlock()
m.naclsMutex.Unlock()
return nacls
}
@@ -1320,7 +1325,7 @@ func (m *NetworkPortsModule) getEC2InstancesPerRegion(region string) []ec2_types
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1359,7 +1364,7 @@ func (m *NetworkPortsModule) getEC2NetworkInterfacesPerRegion(interfaceId string
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1394,7 +1399,7 @@ func (m *NetworkPortsModule) getECSClustersPerRegion(region string) []string {
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1430,7 +1435,7 @@ func (m *NetworkPortsModule) getECSServicesPerRegion(clusterArn *string, region
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1493,7 +1498,7 @@ func (m *NetworkPortsModule) getECSTasksPerRegion(service *string, clusterArn *s
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1553,7 +1558,7 @@ func (m *NetworkPortsModule) getEFSSharesPerRegion(region string) []efs_types.Fi
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1589,7 +1594,7 @@ func (m *NetworkPortsModule) getEFSMountTargetsPerRegion(filesystem *string, reg
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1624,7 +1629,7 @@ func (m *NetworkPortsModule) getElastiCacheClustersPerRegion(region string) []el
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1659,7 +1664,7 @@ func (m *NetworkPortsModule) getElastiCacheSubnetGroupsPerRegion(region string)
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1694,7 +1699,7 @@ func (m *NetworkPortsModule) getElastiCacheReplicationGroupsPerRegion(region str
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1729,7 +1734,7 @@ func (m *NetworkPortsModule) getLightsailInstancesPerRegion(region string) []lig
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1764,7 +1769,7 @@ func (m *NetworkPortsModule) getLoadBalancersPerRegion(region string) []elbv2_ty
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1800,7 +1805,7 @@ func (m *NetworkPortsModule) getLBListenerPorts(arn *string, region string) ([]i
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1850,7 +1855,7 @@ func (m *NetworkPortsModule) getRdsClustersPerRegion(region string) []rds_types.
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -1885,7 +1890,7 @@ func (m *NetworkPortsModule) getRdsInstancesPerRegion(region string) []rds_types
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
+67
View File
@@ -0,0 +1,67 @@
package aws
import (
"fmt"
"sync"
"testing"
ec2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
)
// TestNetworkPortsCacheConcurrentAccess is a regression test for issue #129.
// Pre-fix, the cache lookup in getEC2NACLsPerRegion and getEC2SecurityGroupsPerRegion
// read m.nacls / m.securityGroups without holding a mutex while writes from
// other goroutines were locked, producing a "concurrent map read and map write"
// panic under load. Run with `go test -race ./aws/...` to verify the lock fix.
func TestNetworkPortsCacheConcurrentAccess(t *testing.T) {
m := &NetworkPortsModule{
nacls: make(map[string]*[]ec2_types.NetworkAcl),
securityGroups: make(map[string]*[]ec2_types.SecurityGroup),
}
// Pre-populate one region so reader goroutines hit the cached fast-path
// without needing a live EC2 client.
cachedNACLs := []ec2_types.NetworkAcl{}
m.nacls["cached"] = &cachedNACLs
cachedSGs := []ec2_types.SecurityGroup{}
m.securityGroups["cached"] = &cachedSGs
var wg sync.WaitGroup
const readers = 100
for i := 0; i < readers; i++ {
wg.Add(2)
go func() {
defer wg.Done()
_ = m.getEC2NACLsPerRegion("cached")
}()
go func() {
defer wg.Done()
_ = m.getEC2SecurityGroupsPerRegion("cached")
}()
}
// Writer goroutines populate uncached regions directly through the mutex,
// mirroring what the live functions do after a successful AWS fetch. The
// readers above must not race with these writes.
const writers = 10
for i := 0; i < writers; i++ {
region := fmt.Sprintf("uncached-%d", i)
wg.Add(2)
go func(r string) {
defer wg.Done()
sl := []ec2_types.NetworkAcl{}
m.naclsMutex.Lock()
m.nacls[r] = &sl
m.naclsMutex.Unlock()
}(region)
go func(r string) {
defer wg.Done()
sl := []ec2_types.SecurityGroup{}
m.securityGroupsMutex.Lock()
m.securityGroups[r] = &sl
m.securityGroupsMutex.Unlock()
}(region)
}
wg.Wait()
}
+4 -4
View File
@@ -191,7 +191,7 @@ func (m *OrgModule) ProcessMultipleAccounts(AWSProfiles []string, version string
for _, profile := range AWSProfiles {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.FindMgmtAccounts(profile, version, wg, semaphore, dataReceiver)
wg.Wait()
@@ -244,7 +244,7 @@ func (m *OrgModule) FindMgmtAccounts(profile string, version string, wg *sync.Wa
DescribeOrganization, err := sdk.CachedOrganizationsDescribeOrganization(m.OrganizationsClient, aws.ToString(m.Caller.Account))
if err != nil {
m.modLog.Errorf("Failed to describe organization: %s", err)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -273,7 +273,7 @@ func (m *OrgModule) addOrgAccounts() {
accounts, err := sdk.CachedOrganizationsListAccounts(m.OrganizationsClient, aws.ToString(m.Caller.Account))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
for _, account := range accounts {
@@ -292,7 +292,7 @@ func (m *OrgModule) addOrgAccount() {
DescribeOrganization, err := sdk.CachedOrganizationsDescribeOrganization(m.OrganizationsClient, aws.ToString(m.Caller.Account))
if err != nil {
sharedLogger.Errorf("Failed to describe organization: %s", err)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
m.Accounts = append(m.Accounts, Account{
+9 -9
View File
@@ -171,7 +171,7 @@ func (m *OutboundAssumedRolesModule) PrintOutboundRoleTrusts(days int, outputDir
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -308,10 +308,10 @@ func (m *OutboundAssumedRolesModule) executeChecks(r string, wg *sync.WaitGroup,
}
if res {
// wg.Add(1)
// m.CommandCounter.Total++
// m.CommandCounter.IncrTotal()
// m.getAssumeRoleLogEntriesPerRegion(r, wg, semaphore, dataReceiver)
wg.Add(1)
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
m.getCrossAccountBatchGetImageEntriesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -319,8 +319,8 @@ func (m *OutboundAssumedRolesModule) executeChecks(r string, wg *sync.WaitGroup,
func (m *OutboundAssumedRolesModule) getAssumeRoleLogEntriesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan OutboundAssumeRoleEntry) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -358,7 +358,7 @@ func (m *OutboundAssumedRolesModule) getAssumeRoleLogEntriesPerRegion(r string,
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -412,8 +412,8 @@ func (m *OutboundAssumedRolesModule) getAssumeRoleLogEntriesPerRegion(r string,
// get cross account batch get image entries
func (m *OutboundAssumedRolesModule) getCrossAccountBatchGetImageEntriesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan OutboundAssumeRoleEntry) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -451,7 +451,7 @@ func (m *OutboundAssumedRolesModule) getCrossAccountBatchGetImageEntriesPerRegio
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
+1 -1
View File
@@ -197,7 +197,7 @@ func (m *IamPermissionsModule) GetGAAD() {
GAAD, err := sdk.CachedIAMGetAccountAuthorizationDetails(m.IAMClient, aws.ToString(m.Caller.Account))
if err != nil {
m.modLog.Error(err)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
+1 -1
View File
@@ -446,7 +446,7 @@ func (m *PmapperModule) writeLoot(outputDirectory string, verbosity int) string
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
panic(err.Error())
}
lootFilePath := filepath.Join(path, "pmapper.txt")
+8 -8
View File
@@ -97,7 +97,7 @@ func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosi
// done := make(chan bool)
// go internal.SpinUntil(m.output.CallingModule, &m.CommandCounter, done)
// wg.Add(1)
// m.CommandCounter.Pending++
// m.CommandCounter.IncrPending()
//m.executeChecks(wg)
// wg.Wait()
// done <- true
@@ -237,13 +237,13 @@ func (m *IamPrincipalsModule) PrintIamPrincipals(outputDirectory string, verbosi
/* UNUSED CODE BLOCK - PLEASE REVIEW AND DELETE IF APPLICABLE
func (m *IamPrincipalsModule) executeChecks(wg *sync.WaitGroup) {
defer wg.Done()
m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
m.getIAMUsers()
m.getIAMRoles()
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}
*/
@@ -256,7 +256,7 @@ func (m *IamPrincipalsModule) addIAMUsersToTable() {
ListUsers, err := sdk.CachedIamListUsers(m.IAMClient, aws.ToString(m.Caller.Account))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, user := range ListUsers {
@@ -288,7 +288,7 @@ func (m *IamPrincipalsModule) addIAMRolesToTable() {
ListRoles, err := sdk.CachedIamListRoles(m.IAMClient, aws.ToString(m.Caller.Account))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, role := range ListRoles {
+8 -8
View File
@@ -79,7 +79,7 @@ func (m *RAMModule) PrintRAM(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, dataReceiver)
}
@@ -191,12 +191,12 @@ func (m *RAMModule) executeChecks(r string, wg *sync.WaitGroup, dataReceiver cha
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
m.getRAMResourcesPerRegion(r, dataReceiver)
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
}
}
@@ -235,7 +235,7 @@ func (m *RAMModule) getRAMResourcesPerRegion(r string, dataReceiver chan Resourc
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -259,7 +259,7 @@ func (m *RAMModule) getRAMResourcesPerRegion(r string, dataReceiver chan Resourc
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
+52 -52
View File
@@ -104,7 +104,7 @@ func (m *ResourceTrustsModule) PrintResources(outputDirectory string, verbosity
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver, includeKms)
}
@@ -217,7 +217,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getSNSTopicsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -227,7 +227,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getSQSQueuesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -237,7 +237,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getECRRecordsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -247,7 +247,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getCodeBuildResourcePoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -257,7 +257,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getLambdaPolicyPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -267,7 +267,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getEFSfilesystemPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -277,7 +277,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getSecretsManagerSecretsPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -287,7 +287,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getGlueResourcePoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -298,7 +298,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getKMSPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -310,7 +310,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getAPIGatewayPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -322,7 +322,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getVPCEndpointPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -334,7 +334,7 @@ func (m *ResourceTrustsModule) executeChecks(r string, wg *sync.WaitGroup, semap
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getOpenSearchPoliciesPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -356,8 +356,8 @@ func (m *ResourceTrustsModule) Receiver(receiver chan Resource2, receiverDone ch
func (m *ResourceTrustsModule) getSNSTopicsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -378,7 +378,7 @@ func (m *ResourceTrustsModule) getSNSTopicsPerRegion(r string, wg *sync.WaitGrou
topic, err := cloudFoxSNSClient.getTopicWithAttributes(aws.ToString(t.TopicArn), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
continue
}
parsedArn, err := arn.Parse(aws.ToString(t.TopicArn))
@@ -433,8 +433,8 @@ func (m *ResourceTrustsModule) getSNSTopicsPerRegion(r string, wg *sync.WaitGrou
func (m *ResourceTrustsModule) getS3Buckets(wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -516,8 +516,8 @@ func (m *ResourceTrustsModule) getS3Buckets(wg *sync.WaitGroup, semaphore chan s
func (m *ResourceTrustsModule) getSQSQueuesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -539,7 +539,7 @@ func (m *ResourceTrustsModule) getSQSQueuesPerRegion(r string, wg *sync.WaitGrou
queue, err := cloudFoxSQSClient.getQueueWithAttributes(q, r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
continue
}
@@ -578,8 +578,8 @@ func (m *ResourceTrustsModule) getSQSQueuesPerRegion(r string, wg *sync.WaitGrou
func (m *ResourceTrustsModule) getECRRecordsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -601,7 +601,7 @@ func (m *ResourceTrustsModule) getECRRecordsPerRegion(r string, wg *sync.WaitGro
repoPolicy, err := cloudFoxECRClient.getECRRepositoryPolicy(r, aws.ToString(repo.RepositoryName))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
continue
}
@@ -642,8 +642,8 @@ func (m *ResourceTrustsModule) getECRRecordsPerRegion(r string, wg *sync.WaitGro
func (m *ResourceTrustsModule) getCodeBuildResourcePoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -666,7 +666,7 @@ func (m *ResourceTrustsModule) getCodeBuildResourcePoliciesPerRegion(r string, w
project, err := sdk.CachedCodeBuildBatchGetProjects(cloudFoxCodeBuildClient.CodeBuildClient, aws.ToString(cloudFoxCodeBuildClient.Caller.Account), r, p)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
continue
}
@@ -716,8 +716,8 @@ func (m *ResourceTrustsModule) getCodeBuildResourcePoliciesPerRegion(r string, w
func (m *ResourceTrustsModule) getLambdaPolicyPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -739,7 +739,7 @@ func (m *ResourceTrustsModule) getLambdaPolicyPerRegion(r string, wg *sync.WaitG
functionPolicy, err := cloudFoxLambdaClient.getResourcePolicy(r, aws.ToString(f.FunctionName))
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
continue
}
@@ -781,8 +781,8 @@ func (m *ResourceTrustsModule) getLambdaPolicyPerRegion(r string, wg *sync.WaitG
func (m *ResourceTrustsModule) getEFSfilesystemPoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -804,7 +804,7 @@ func (m *ResourceTrustsModule) getEFSfilesystemPoliciesPerRegion(r string, wg *s
fsPolicy, err := sdk.CachedDescribeFileSystemPolicy(cloudFoxEFSClient.EFSClient, aws.ToString(fs.FileSystemId), r, aws.ToString(m.Caller.Account))
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
continue
}
@@ -851,8 +851,8 @@ func (m *ResourceTrustsModule) getEFSfilesystemPoliciesPerRegion(r string, wg *s
// 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) getSecretsManagerSecretsPoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -874,7 +874,7 @@ func (m *ResourceTrustsModule) getSecretsManagerSecretsPoliciesPerRegion(r strin
secretPolicy, err := sdk.CachedSecretsManagerGetResourcePolicy(cloudFoxSecretsManagerClient, aws.ToString(s.ARN), r, aws.ToString(m.Caller.Account))
if err != nil {
sharedLogger.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
continue
}
@@ -921,8 +921,8 @@ func (m *ResourceTrustsModule) getSecretsManagerSecretsPoliciesPerRegion(r strin
// 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++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
semaphore <- struct{}{}
@@ -942,7 +942,7 @@ func (m *ResourceTrustsModule) getKMSPoliciesPerRegion(r string, wg *sync.WaitGr
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++
m.CommandCounter.IncrError()
continue
}
@@ -985,8 +985,8 @@ func (m *ResourceTrustsModule) getKMSPoliciesPerRegion(r string, wg *sync.WaitGr
func (m *ResourceTrustsModule) getAPIGatewayPoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
semaphore <- struct{}{}
@@ -1016,7 +1016,7 @@ func (m *ResourceTrustsModule) getAPIGatewayPoliciesPerRegion(r string, wg *sync
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++
m.CommandCounter.IncrError()
continue
}
@@ -1063,8 +1063,8 @@ func (m *ResourceTrustsModule) getAPIGatewayPoliciesPerRegion(r string, wg *sync
func (m *ResourceTrustsModule) getVPCEndpointPoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
semaphore <- struct{}{}
@@ -1086,7 +1086,7 @@ func (m *ResourceTrustsModule) getVPCEndpointPoliciesPerRegion(r string, wg *syn
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++
m.CommandCounter.IncrError()
continue
}
@@ -1133,8 +1133,8 @@ func (m *ResourceTrustsModule) getVPCEndpointPoliciesPerRegion(r string, wg *syn
func (m *ResourceTrustsModule) getOpenSearchPoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
semaphore <- struct{}{}
@@ -1153,7 +1153,7 @@ func (m *ResourceTrustsModule) getOpenSearchPoliciesPerRegion(r string, wg *sync
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++
m.CommandCounter.IncrError()
continue
}
@@ -1167,7 +1167,7 @@ func (m *ResourceTrustsModule) getOpenSearchPoliciesPerRegion(r string, wg *sync
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++
m.CommandCounter.IncrError()
continue
}
@@ -1179,7 +1179,7 @@ func (m *ResourceTrustsModule) getOpenSearchPoliciesPerRegion(r string, wg *sync
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++
m.CommandCounter.IncrError()
continue
}
@@ -1226,8 +1226,8 @@ func (m *ResourceTrustsModule) getOpenSearchPoliciesPerRegion(r string, wg *sync
func (m *ResourceTrustsModule) getGlueResourcePoliciesPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Resource2) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
+2 -2
View File
@@ -590,14 +590,14 @@ func (m *RoleTrustsModule) getAllRoleTrusts() {
ListRoles, err := sdk.CachedIamListRoles(m.IAMClient, aws.ToString(m.Caller.Account))
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
for _, role := range ListRoles {
trustsdoc, err := policy.ParseRoleTrustPolicyDocument(role)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
+5 -5
View File
@@ -146,7 +146,7 @@ func (m *Route53Module) writeLoot(outputDirectory string, verbosity int) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
panic(err.Error())
}
route53ARecordsPublicZonesFileName := filepath.Join(path, "route53-A-records-public-Zones.txt")
@@ -168,7 +168,7 @@ func (m *Route53Module) writeLoot(outputDirectory string, verbosity int) {
err = os.WriteFile(route53ARecordsPublicZonesFileName, []byte(route53APublicRecords), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
panic(err.Error())
}
@@ -186,7 +186,7 @@ func (m *Route53Module) writeLoot(outputDirectory string, verbosity int) {
err = os.WriteFile(route53ARecordsPrivateZonesFileName, []byte(route53APrivateRecords), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
panic(err.Error())
}
@@ -212,7 +212,7 @@ func (m *Route53Module) getRoute53Records() {
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -228,7 +228,7 @@ func (m *Route53Module) getRoute53Records() {
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
for _, record := range Records {
+17 -17
View File
@@ -82,7 +82,7 @@ func (m *SecretsModule) PrintSecrets(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -205,7 +205,7 @@ func (m *SecretsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore ch
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getSecretsManagerSecretsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -214,7 +214,7 @@ func (m *SecretsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore ch
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getSSMParametersPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -226,7 +226,7 @@ func (m *SecretsModule) writeLoot(outputDirectory string, verbosity int) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
pullFile := filepath.Join(path, "pull-secrets-commands.txt")
@@ -249,7 +249,7 @@ func (m *SecretsModule) writeLoot(outputDirectory string, verbosity int) {
err = os.WriteFile(pullFile, []byte(out), 0644)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
if verbosity > 2 {
@@ -266,8 +266,8 @@ func (m *SecretsModule) writeLoot(outputDirectory string, verbosity int) {
func (m *SecretsModule) getSecretsManagerSecretsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Secret) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -275,9 +275,9 @@ func (m *SecretsModule) getSecretsManagerSecretsPerRegion(r string, wg *sync.Wai
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
var PaginationControl *string
for {
@@ -292,7 +292,7 @@ func (m *SecretsModule) getSecretsManagerSecretsPerRegion(r string, wg *sync.Wai
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -324,8 +324,8 @@ func (m *SecretsModule) getSecretsManagerSecretsPerRegion(r string, wg *sync.Wai
func (m *SecretsModule) getSSMParametersPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Secret) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -333,9 +333,9 @@ func (m *SecretsModule) getSSMParametersPerRegion(r string, wg *sync.WaitGroup,
defer func() {
<-semaphore
}()
// m.CommandCounter.Total++
m.CommandCounter.Pending--
m.CommandCounter.Executing++
// m.CommandCounter.IncrTotal()
m.CommandCounter.DecrPending()
m.CommandCounter.IncrExecuting()
// "PaginationMarker" is a control variable used for output continuity, as AWS return the output in pages.
var PaginationControl *string
@@ -351,7 +351,7 @@ func (m *SecretsModule) getSSMParametersPerRegion(r string, wg *sync.WaitGroup,
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
+6 -6
View File
@@ -96,7 +96,7 @@ func (m *SNSModule) PrintSNS(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -205,7 +205,7 @@ func (m *SNSModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan s
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getSNSTopicsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -288,8 +288,8 @@ func (m *SNSModule) writeLoot(outputDirectory string, verbosity int, profile str
func (m *SNSModule) getSNSTopicsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan SNSTopic) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -308,7 +308,7 @@ func (m *SNSModule) getSNSTopicsPerRegion(r string, wg *sync.WaitGroup, semaphor
topic, err := m.getTopicWithAttributes(aws.ToString(t.TopicArn), r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
parsedArn, err := arn.Parse(aws.ToString(t.TopicArn))
@@ -427,7 +427,7 @@ func (m *SNSModule) storeAccessPolicy(topic *SNSTopic) {
if err := m.storeFile(f, topic.PolicyJSON); err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+7 -7
View File
@@ -99,7 +99,7 @@ func (m *SQSModule) PrintSQS(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -207,7 +207,7 @@ func (m *SQSModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan s
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getSQSRecordsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -287,8 +287,8 @@ func (m *SQSModule) writeLoot(outputDirectory string, verbosity int, profile str
func (m *SQSModule) getSQSRecordsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Queue) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -301,7 +301,7 @@ func (m *SQSModule) getSQSRecordsPerRegion(r string, wg *sync.WaitGroup, semapho
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -309,7 +309,7 @@ func (m *SQSModule) getSQSRecordsPerRegion(r string, wg *sync.WaitGroup, semapho
queue, err := m.getQueueWithAttributes(url, r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
@@ -437,7 +437,7 @@ func (m *SQSModule) storeAccessPolicy(queue *Queue) {
if err := m.storeFile(f, queue.PolicyJSON); err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+6 -6
View File
@@ -88,7 +88,7 @@ func (m *TagsModule) PrintTags(outputDirectory string, verbosity int) {
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -246,7 +246,7 @@ func (m *TagsModule) countUniqueResourcesWithTags() int {
func (m *TagsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Tag) {
defer wg.Done()
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
m.getTagsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -266,8 +266,8 @@ func (m *TagsModule) Receiver(receiver chan Tag, receiverDone chan bool) {
func (m *TagsModule) getTagsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Tag) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -280,7 +280,7 @@ func (m *TagsModule) getTagsPerRegion(r string, wg *sync.WaitGroup, semaphore ch
resources, err := m.getResources(r)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
//var parsedArn types.Arn
for _, resource := range resources {
@@ -337,7 +337,7 @@ func (m *TagsModule) getResources(r string) ([]types.ResourceTagMapping, error)
)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return resources, err
}
+15 -15
View File
@@ -109,7 +109,7 @@ func (m *WorkloadsModule) PrintWorkloads(outputDirectory string, verbosity int)
for _, region := range m.AWSRegions {
wg.Add(1)
m.CommandCounter.Pending++
m.CommandCounter.IncrPending()
go m.executeChecks(region, wg, semaphore, dataReceiver)
}
@@ -281,14 +281,14 @@ func (m *WorkloadsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
res, _ := servicemap.IsServiceInRegion("ec2", r)
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getEC2WorkloadsPerRegion(r, wg, semaphore, dataReceiver)
}
res, _ = servicemap.IsServiceInRegion("ecs", r)
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getECSWorkloadsPerRegion(r, wg, semaphore, dataReceiver)
}
@@ -298,13 +298,13 @@ func (m *WorkloadsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
m.modLog.Error(err)
}
if res {
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getLambdaWorkloadsPerRegion(r, wg, semaphore, dataReceiver)
}
// AppRunner is not supported in the aws service region catalog so we have to run it in all regions
m.CommandCounter.Total++
m.CommandCounter.IncrTotal()
wg.Add(1)
go m.getAppRunnerWorkloadsPerRegion(r, wg, semaphore, dataReceiver)
@@ -312,8 +312,8 @@ func (m *WorkloadsModule) executeChecks(r string, wg *sync.WaitGroup, semaphore
func (m *WorkloadsModule) getEC2WorkloadsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Workload) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -369,8 +369,8 @@ func (m *WorkloadsModule) getEC2WorkloadsPerRegion(r string, wg *sync.WaitGroup,
func (m *WorkloadsModule) getECSWorkloadsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Workload) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -395,7 +395,7 @@ func (m *WorkloadsModule) getECSWorkloadsPerRegion(r string, wg *sync.WaitGroup,
Tasks, err := sdk.CachedECSDescribeTasks(m.ECSClient, aws.ToString(m.Caller.Account), r, cluster, taskARNs)
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
return
}
@@ -424,8 +424,8 @@ func (m *WorkloadsModule) getECSWorkloadsPerRegion(r string, wg *sync.WaitGroup,
func (m *WorkloadsModule) getLambdaWorkloadsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Workload) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -457,8 +457,8 @@ func (m *WorkloadsModule) getLambdaWorkloadsPerRegion(r string, wg *sync.WaitGro
func (m *WorkloadsModule) getAppRunnerWorkloadsPerRegion(r string, wg *sync.WaitGroup, semaphore chan struct{}, dataReceiver chan Workload) {
defer func() {
m.CommandCounter.Executing--
m.CommandCounter.Complete++
m.CommandCounter.DecrExecuting()
m.CommandCounter.IncrComplete()
wg.Done()
}()
@@ -543,7 +543,7 @@ func (m *WorkloadsModule) getRolesFromInstanceProfiles() {
if err != nil {
m.modLog.Error(err.Error())
m.CommandCounter.Error++
m.CommandCounter.IncrError()
break
}
for _, instanceProfile := range ListInstanceProfiles.InstanceProfiles {
+8 -9
View File
@@ -544,9 +544,6 @@ type OrgAccounts struct {
}
func awsPreRun(cmd *cobra.Command, args []string) {
// Set up Ctrl+C handler (double-press to confirm shutdown)
internal.SetupSignalHandler()
gob.Register(&types.Organization{})
// if multiple profiles were used, ensure the management account is first
@@ -2255,6 +2252,7 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
PmapperDataBasePath: PmapperDataBasePath,
}
ec2UserData.Instances(InstancesFilter, AWSOutputDirectory, Verbosity)
envsMod := aws.EnvsModule{
@@ -2437,12 +2435,13 @@ func runAllChecksCommand(cmd *cobra.Command, args []string) {
roleTrusts.PrintRoleTrusts(AWSOutputDirectory, Verbosity)
pmapperCommand := aws.PmapperModule{
Caller: *caller,
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
Caller: *caller,
AWSProfile: profile,
Goroutines: Goroutines,
WrapTable: AWSWrapTable,
AWSOutputType: AWSOutputType,
AWSTableCols: AWSTableCols,
PmapperDataBasePath: PmapperDataBasePath,
}
pmapperCommand.PrintPmapperData(AWSOutputDirectory, Verbosity)
+25 -253
View File
@@ -2,9 +2,7 @@ package cli
import (
"context"
"encoding/json"
"fmt"
"os"
"strings"
"time"
@@ -14,8 +12,6 @@ import (
"github.com/BishopFox/cloudfox/internal"
gcpinternal "github.com/BishopFox/cloudfox/internal/gcp"
"github.com/spf13/cobra"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
var (
@@ -26,15 +22,6 @@ var (
GCPProjectIDs []string
GCPAllProjects bool
// Service account impersonation
GCPImpersonateSA string
// Service account key file authentication
GCPKeyFile string
// Raw access token authentication
GCPAccessToken string
// Project name mapping (ProjectID -> DisplayName)
GCPProjectNames map[string]string
@@ -44,8 +31,6 @@ var (
GCPVerbosity int
GCPWrapTable bool
GCPFlatOutput bool
GCPQuery string
GCPSQLQuery string
// Refresh cache flag - force re-enumeration even if cache exists
GCPRefreshCache bool
@@ -67,111 +52,22 @@ var (
GCPProjectIDs = nil
GCPProjectNames = make(map[string]string)
// Create session based on auth flags.
// Allowed combinations:
// --access-token (raw token)
// --key-file (SA key file)
// --impersonate-sa (impersonate over ADC)
// --access-token + --impersonate-sa (impersonate using token as base)
// --key-file + --impersonate-sa (impersonate using key as base)
// Disallowed: --access-token + --key-file (both are base credentials)
var gcpSession *gcpinternal.SafeSession
if GCPAccessToken != "" && GCPKeyFile != "" {
GCPLogger.FatalM("--access-token and --key-file cannot be used together (both are base credentials)", "gcp")
}
// Step 1: Create base session from access-token or key-file (if provided)
var baseSession *gcpinternal.SafeSession
if GCPAccessToken != "" {
os.Unsetenv("GOOGLE_CLOUD_QUOTA_PROJECT")
GCPLogger.InfoM("Authenticating with provided access token...", "gcp")
var err error
baseSession, err = gcpinternal.NewSafeSessionFromAccessToken(context.Background(), GCPAccessToken)
if err != nil {
GCPLogger.FatalM(fmt.Sprintf("Failed to authenticate with access token: %v", err), "gcp")
}
// If tokeninfo/userinfo endpoints didn't return an email (common with
// SA tokens that only have the cloud-platform scope), try a project-scoped
// probe using the CRM API to extract the caller from the error response.
if baseSession.GetEmail() == "" && GCPProjectID != "" {
gcpinternal.ProbeIdentityWithProject(context.Background(), baseSession, GCPProjectID)
}
email := baseSession.GetEmail()
if email != "" {
GCPLogger.SuccessM(fmt.Sprintf("Authenticated as %s (from access token)", email), "gcp")
} else {
GCPLogger.WarnM("Authenticated with access token (could not resolve identity)", "gcp")
}
} else if GCPKeyFile != "" {
os.Unsetenv("GOOGLE_CLOUD_QUOTA_PROJECT")
GCPLogger.InfoM(fmt.Sprintf("Authenticating with key file: %s", GCPKeyFile), "gcp")
var err error
baseSession, err = gcpinternal.NewSafeSessionFromKeyFile(context.Background(), GCPKeyFile)
if err != nil {
GCPLogger.FatalM(fmt.Sprintf("Failed to authenticate with key file %s: %v", GCPKeyFile, err), "gcp")
}
GCPLogger.SuccessM(fmt.Sprintf("Authenticated as %s (from key file)", baseSession.GetEmail()), "gcp")
}
// Step 2: Layer impersonation on top (if requested)
if GCPImpersonateSA != "" {
os.Unsetenv("GOOGLE_CLOUD_QUOTA_PROJECT")
var baseTS oauth2.TokenSource
if baseSession != nil {
baseTS = baseSession.GetTokenSource()
GCPLogger.InfoM(fmt.Sprintf("Impersonating %s using %s as base credential...", GCPImpersonateSA, baseSession.GetEmail()), "gcp")
} else {
GCPLogger.InfoM(fmt.Sprintf("Impersonating service account: %s", GCPImpersonateSA), "gcp")
}
var err error
gcpSession, err = gcpinternal.NewSafeSessionWithImpersonation(context.Background(), GCPImpersonateSA, baseTS)
if err != nil {
GCPLogger.FatalM(fmt.Sprintf("Failed to impersonate %s: %v", GCPImpersonateSA, err), "gcp")
}
GCPLogger.SuccessM(fmt.Sprintf("Successfully impersonating %s", GCPImpersonateSA), "gcp")
} else if baseSession != nil {
// No impersonation, use the base session directly
gcpSession = baseSession
} else {
// Set quota project for GCP API calls. ADC may reference a deleted
// or inaccessible quota project, causing all API calls to fail with
// 403/404. Override it with the target project when known.
if GCPProjectID != "" {
os.Setenv("GOOGLE_CLOUD_QUOTA_PROJECT", GCPProjectID)
} else if GCPProjectIDsFilePath != "" {
lines := internal.LoadFileLinesIntoArray(GCPProjectIDsFilePath)
if len(lines) > 0 {
os.Setenv("GOOGLE_CLOUD_QUOTA_PROJECT", lines[0])
}
} else if GCPAllProjects {
// No target project yet. Validate the ADC quota project
// and clear it if the project is inaccessible.
validateADCQuotaProject()
}
}
// Handle project discovery based on flags
// Priority: -p (single project) > -l (project list) > -A (all projects)
if GCPProjectID != "" {
// Single project specified with -p/--project
GCPProjectIDs = append(GCPProjectIDs, GCPProjectID)
resolveProjectNames(GCPProjectIDs, gcpSession)
resolveProjectNames(GCPProjectIDs)
} else if GCPProjectIDsFilePath != "" {
// Project list specified with -l/--project-list
rawProjectIDs := internal.LoadFileLinesIntoArray(GCPProjectIDsFilePath)
GCPProjectIDs = deduplicateProjectIDs(rawProjectIDs)
resolveProjectNames(GCPProjectIDs, gcpSession)
resolveProjectNames(GCPProjectIDs)
} else if GCPAllProjects {
// Discover all accessible projects with -A/--all-projects
GCPLogger.InfoM("Discovering all accessible projects...", "gcp")
orgsSvc := newOrgsService(gcpSession)
var projects []orgsservice.ProjectInfo
err := gcpinternal.RetryWithBackoff(GCPLogger, "gcp", 3, func() error {
var searchErr error
projects, searchErr = orgsSvc.SearchProjects("")
return searchErr
})
orgsSvc := orgsservice.New()
projects, err := orgsSvc.SearchProjects("")
if err != nil {
GCPLogger.FatalM(fmt.Sprintf("Failed to discover projects: %v. Try using -p or -l flags instead.", err), "gcp")
}
@@ -189,53 +85,22 @@ var (
GCPLogger.InfoM("No project scope specified. Use -p, -l, or -A flag.", "gcp")
}
// Create a context with project IDs and names, using signal-aware base context
sigCtx := internal.SetupSignalHandler()
ctx := context.WithValue(sigCtx, "projectIDs", GCPProjectIDs)
// Create a context with project IDs and names
ctx := context.WithValue(context.Background(), "projectIDs", GCPProjectIDs)
ctx = context.WithValue(ctx, "projectNames", GCPProjectNames)
// Set default session so all services pick up impersonation
if gcpSession != nil {
gcpinternal.SetDefaultSession(gcpSession)
}
// Set global query filter if --query or --sqlquery flag is provided
if GCPQuery != "" && GCPSQLQuery != "" {
GCPLogger.FatalM("--query and --sqlquery cannot be used together", "gcp")
}
if GCPQuery != "" {
internal.SetQueryFilter(GCPQuery)
}
if GCPSQLQuery != "" {
internal.SetSQLQueryFilter(GCPSQLQuery)
}
// Authenticate and get account info.
// Check impersonation first since it overrides the effective identity
// even when combined with --access-token or --key-file.
if GCPImpersonateSA != "" {
ctx = context.WithValue(ctx, "account", GCPImpersonateSA)
} else if GCPAccessToken != "" {
email := gcpSession.GetEmail()
if email == "" {
email = "access-token-user"
}
ctx = context.WithValue(ctx, "account", email)
} else if GCPKeyFile != "" {
ctx = context.WithValue(ctx, "account", gcpSession.GetEmail())
} else {
os := oauthservice.NewOAuthService()
principal, err := os.WhoAmI()
if err != nil {
GCPLogger.FatalM(fmt.Sprintf("could not determine default user credential with error %s.\n\nPlease use default application default credentials: https://cloud.google.com/docs/authentication/application-default-credentials\n\nTry: gcloud auth application-default login", err.Error()), "gcp")
}
ctx = context.WithValue(ctx, "account", principal.Email)
// Authenticate and get account info
os := oauthservice.NewOAuthService()
principal, err := os.WhoAmI()
if err != nil {
GCPLogger.FatalM(fmt.Sprintf("could not determine default user credential with error %s.\n\nPlease use default application default credentials: https://cloud.google.com/docs/authentication/application-default-credentials\n\nTry: gcloud auth application-default login", err.Error()), "gcp")
}
ctx = context.WithValue(ctx, "account", principal.Email)
// Build scope hierarchy for hierarchical output (unless --flat-output is set)
if !GCPFlatOutput && len(GCPProjectIDs) > 0 {
GCPLogger.InfoM("Building scope hierarchy for hierarchical output...", "gcp")
orgsSvc := newOrgsService(gcpSession)
orgsSvc := orgsservice.New()
provider := orgsservice.NewHierarchyProvider(orgsSvc)
hierarchy, err := gcpinternal.BuildScopeHierarchy(GCPProjectIDs, provider)
if err != nil {
@@ -288,7 +153,7 @@ var (
// Cache auto-refreshes after 24 hours
// Force refresh when running the organizations command to ensure fresh data
refreshCache := GCPRefreshCache || cmd.Name() == "organizations"
orgCache := loadOrPopulateOrgCache(account, refreshCache, gcpSession)
orgCache := loadOrPopulateOrgCache(account, refreshCache)
if orgCache != nil && orgCache.IsPopulated() {
ctx = gcpinternal.SetOrgCacheInContext(ctx, orgCache)
}
@@ -298,14 +163,6 @@ var (
}
)
// newOrgsService creates an organizations service, using the impersonated session if provided
func newOrgsService(session *gcpinternal.SafeSession) *orgsservice.OrganizationsService {
if session != nil {
return orgsservice.NewWithSession(session)
}
return orgsservice.New()
}
// deduplicateProjectIDs removes duplicates, trims whitespace, and filters empty entries
func deduplicateProjectIDs(projectIDs []string) []string {
seen := make(map[string]bool)
@@ -338,72 +195,15 @@ func deduplicateProjectIDs(projectIDs []string) []string {
return result
}
// validateADCQuotaProject reads the ADC file and checks whether the configured
// quota project is accessible. The Go SDK sends x-goog-user-project on every
// request based on the ADC's quota_project_id. If that project is deleted or
// inaccessible, ALL API calls will fail with 403/404. This function detects
// that condition and clears the quota project so the SDK doesn't send the
// broken header. The caller is responsible for setting a valid quota project
// once a working project is discovered.
func validateADCQuotaProject() {
creds, err := google.FindDefaultCredentials(context.Background())
if err != nil || creds.JSON == nil {
return
}
var adcFile struct {
QuotaProject string `json:"quota_project_id"`
}
if err := json.Unmarshal(creds.JSON, &adcFile); err != nil || adcFile.QuotaProject == "" {
return
}
// Proactively clear the quota project via env var override. If the ADC
// quota project is valid, the SearchProjects call below will succeed and
// we'll restore it. If it's broken, we've already fixed the problem.
os.Setenv("GOOGLE_CLOUD_QUOTA_PROJECT", "")
orgsSvc := orgsservice.New()
projects, err := orgsSvc.SearchProjects("")
if err != nil {
// Can't validate. Leave it cleared (better than a known-broken value).
GCPLogger.WarnM(fmt.Sprintf("Could not validate ADC quota project '%s': %v", adcFile.QuotaProject, err), "gcp")
return
}
// Check if the original quota project is among accessible active projects
for _, p := range projects {
if p.ProjectID == adcFile.QuotaProject && p.State == "ACTIVE" {
// Original quota project is valid, restore it
os.Setenv("GOOGLE_CLOUD_QUOTA_PROJECT", adcFile.QuotaProject)
return
}
}
// Original quota project is not accessible. Pick the first active project.
GCPLogger.WarnM(fmt.Sprintf("ADC quota project '%s' is not accessible or has been deleted. Overriding with first available project.", adcFile.QuotaProject), "gcp")
for _, p := range projects {
if p.State == "ACTIVE" {
os.Setenv("GOOGLE_CLOUD_QUOTA_PROJECT", p.ProjectID)
return
}
}
}
// resolveProjectNames fetches display names for given project IDs
func resolveProjectNames(projectIDs []string, session *gcpinternal.SafeSession) {
func resolveProjectNames(projectIDs []string) {
if len(projectIDs) == 0 {
return
}
orgsSvc := newOrgsService(session)
orgsSvc := orgsservice.New()
// Fetch all accessible projects and build lookup map
var projects []orgsservice.ProjectInfo
err := gcpinternal.RetryWithBackoff(GCPLogger, "gcp", 3, func() error {
var searchErr error
projects, searchErr = orgsSvc.SearchProjects("")
return searchErr
})
projects, err := orgsSvc.SearchProjects("")
if err != nil {
// Non-fatal: we can continue without display names
GCPLogger.InfoM("Could not resolve project names, using project IDs only", "gcp")
@@ -445,17 +245,11 @@ var GCPAllChecksCommand = &cobra.Command{
ctx = gcpinternal.SetAllChecksMode(ctx, true)
cmd.SetContext(ctx)
// Get session from context for impersonation support
var allChecksSession *gcpinternal.SafeSession
if s, ok := ctx.Value("session").(*gcpinternal.SafeSession); ok {
allChecksSession = s
}
// Load or populate org cache for cross-project modules
existingOrgCache := gcpinternal.GetOrgCacheFromContext(ctx)
if existingOrgCache == nil || !existingOrgCache.IsPopulated() {
GCPLogger.InfoM("Loading/enumerating organization data for cross-project analysis...", "all-checks")
orgCache := loadOrPopulateOrgCache(account, GCPRefreshCache, allChecksSession)
orgCache := loadOrPopulateOrgCache(account, GCPRefreshCache)
if orgCache != nil && orgCache.IsPopulated() {
ctx = gcpinternal.SetOrgCacheInContext(ctx, orgCache)
cmd.SetContext(ctx)
@@ -516,7 +310,6 @@ var GCPAllChecksCommand = &cobra.Command{
"bigquery-enum": true,
"bigtable-enum": true,
"spanner-enum": true,
"access-tokens": true, // Local-only, no API calls
}
// Count total modules to execute (excluding self, hidden, and excluded modules)
@@ -551,7 +344,7 @@ var GCPAllChecksCommand = &cobra.Command{
}
// loadOrPopulateOrgCache loads org cache from disk if available, or enumerates and saves it
func loadOrPopulateOrgCache(account string, forceRefresh bool, session *gcpinternal.SafeSession) *gcpinternal.OrgCache {
func loadOrPopulateOrgCache(account string, forceRefresh bool) *gcpinternal.OrgCache {
// Check if cache exists and we're not forcing refresh
if !forceRefresh && gcpinternal.OrgCacheExists(GCPOutputDirectory, account) {
// Check if cache is stale (older than 24 hours)
@@ -575,23 +368,18 @@ func loadOrPopulateOrgCache(account string, forceRefresh bool, session *gcpinter
}
// Enumerate and create cache
cache := enumerateAndCacheOrgs(account, session)
cache := enumerateAndCacheOrgs(account)
return cache
}
// enumerateAndCacheOrgs enumerates all orgs/folders/projects and saves to disk
func enumerateAndCacheOrgs(account string, session *gcpinternal.SafeSession) *gcpinternal.OrgCache {
func enumerateAndCacheOrgs(account string) *gcpinternal.OrgCache {
cache := gcpinternal.NewOrgCache()
orgsSvc := newOrgsService(session)
orgsSvc := orgsservice.New()
// Get all organizations
var orgs []orgsservice.OrganizationInfo
err := gcpinternal.RetryWithBackoff(GCPLogger, "gcp", 3, func() error {
var searchErr error
orgs, searchErr = orgsSvc.SearchOrganizations()
return searchErr
})
orgs, err := orgsSvc.SearchOrganizations()
if err == nil {
for _, org := range orgs {
cache.AddOrganization(gcpinternal.CachedOrganization{
@@ -605,12 +393,7 @@ func enumerateAndCacheOrgs(account string, session *gcpinternal.SafeSession) *gc
}
// Get all folders
var folders []orgsservice.FolderInfo
err = gcpinternal.RetryWithBackoff(GCPLogger, "gcp", 3, func() error {
var searchErr error
folders, searchErr = orgsSvc.SearchAllFolders()
return searchErr
})
folders, err := orgsSvc.SearchAllFolders()
if err == nil {
for _, folder := range folders {
cache.AddFolder(gcpinternal.CachedFolder{
@@ -624,12 +407,7 @@ func enumerateAndCacheOrgs(account string, session *gcpinternal.SafeSession) *gc
}
// Get all projects
var projects []orgsservice.ProjectInfo
err = gcpinternal.RetryWithBackoff(GCPLogger, "gcp", 3, func() error {
var searchErr error
projects, searchErr = orgsSvc.SearchProjects("")
return searchErr
})
projects, err := orgsSvc.SearchProjects("")
if err == nil {
for _, project := range projects {
// Extract project number from Name (format: "projects/123456789")
@@ -726,11 +504,6 @@ func init() {
GCPCommands.PersistentFlags().BoolVarP(&GCPWrapTable, "wrap", "w", false, "Wrap table to fit in terminal (complicates grepping)")
GCPCommands.PersistentFlags().BoolVar(&GCPFlatOutput, "flat-output", false, "Use legacy flat output structure instead of hierarchical per-project directories")
GCPCommands.PersistentFlags().BoolVar(&GCPRefreshCache, "refresh-cache", false, "Force re-enumeration of cached data (cache auto-expires after 24 hours)")
GCPCommands.PersistentFlags().StringVarP(&GCPImpersonateSA, "impersonate-sa", "i", "", "Service account email to impersonate (requires roles/iam.serviceAccountTokenCreator)")
GCPCommands.PersistentFlags().StringVarP(&GCPKeyFile, "key-file", "k", "", "Path to a service account JSON key file for authentication")
GCPCommands.PersistentFlags().StringVar(&GCPAccessToken, "access-token", "", "Raw GCP access token for authentication (non-refreshable)")
GCPCommands.PersistentFlags().StringVarP(&GCPQuery, "query", "q", "", "Filter output rows by substring match (e.g. \"Role:owner,Principal:privesc02\" or plain \"privesc02\")")
GCPCommands.PersistentFlags().StringVar(&GCPSQLQuery, "sqlquery", "", "Filter output with SQL-like syntax (e.g. \"Role CONTAINS owner AND Principal CONTAINS privesc02\")")
// Available commands
GCPCommands.AddCommand(
@@ -799,7 +572,6 @@ func init() {
commands.GCPAccessLevelsCommand,
// Pentest/Exploitation commands
commands.GCPAccessTokensCommand,
commands.GCPPrivescCommand,
commands.GCPOrgPoliciesCommand,
commands.GCPStorageEnumCommand,
-288
View File
@@ -1,288 +0,0 @@
package commands
import (
"fmt"
"sort"
"strings"
accesstokensservice "github.com/BishopFox/cloudfox/gcp/services/accessTokensService"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
"github.com/spf13/cobra"
)
// GCPAccessTokensCommand reads locally cached gcloud credentials.
// It overrides PersistentPreRun to bypass the parent's auth/project requirements
// since it only reads local files — no GCP API calls needed.
var GCPAccessTokensCommand = &cobra.Command{
Use: globals.GCP_ACCESS_TOKENS_MODULE_NAME,
Aliases: []string{"tokens", "creds"},
Short: "Enumerate locally cached gcloud access tokens, refresh tokens, and ADC",
Long: `Reads locally cached gcloud credentials for post-exploitation credential discovery.
Sources checked:
- access_tokens.db Cached OAuth2 access tokens
- credentials.db Cached refresh tokens
- application_default_credentials.json (ADC)
- configurations/config_* All gcloud profiles
- active_config Currently active profile
- GOOGLE_APPLICATION_CREDENTIALS env var (SA key files)
- CLOUDSDK_CONFIG_DIR env var (custom config paths)
This command reads LOCAL FILES ONLY — no GCP API calls are made.
No project flag (-p) or authentication is required.`,
// Override PersistentPreRun to bypass the parent's auth/project resolution.
// Cobra behavior: a child's PersistentPreRun fully replaces the parent's.
PersistentPreRun: func(cmd *cobra.Command, args []string) {
// Intentionally empty — no project flags or OAuth needed
},
Run: runGCPAccessTokensCommand,
}
// AccessTokensModule holds the credential discovery results
type AccessTokensModule struct {
Credentials []accesstokensservice.CredentialSummary
Verbosity int
WrapTable bool
OutputDir string
Format string
}
// AccessTokensOutput implements internal.CloudfoxOutput
type AccessTokensOutput struct {
Table []internal.TableFile
Loot []internal.LootFile
}
func (o AccessTokensOutput) TableFiles() []internal.TableFile { return o.Table }
func (o AccessTokensOutput) LootFiles() []internal.LootFile { return o.Loot }
func runGCPAccessTokensCommand(cmd *cobra.Command, args []string) {
logger := internal.NewLogger()
// Read output flags from the parent command (gcp)
parentCmd := cmd.Parent()
verbosity, _ := parentCmd.PersistentFlags().GetInt("verbosity")
wrap, _ := parentCmd.PersistentFlags().GetBool("wrap")
outputDir, _ := parentCmd.PersistentFlags().GetString("outdir")
format, _ := parentCmd.PersistentFlags().GetString("output")
if format == "" {
format = "all"
}
module := &AccessTokensModule{
Verbosity: verbosity,
WrapTable: wrap,
OutputDir: outputDir,
Format: format,
}
module.Execute(logger)
}
func (m *AccessTokensModule) Execute(logger internal.Logger) {
logger.InfoM("Searching for locally cached gcloud credentials...", globals.GCP_ACCESS_TOKENS_MODULE_NAME)
svc := accesstokensservice.New()
creds, err := svc.GetAllCredentials()
if err != nil {
logger.ErrorM(fmt.Sprintf("Error reading credentials: %v", err), globals.GCP_ACCESS_TOKENS_MODULE_NAME)
return
}
if len(creds) == 0 {
logger.InfoM("No cached credentials found", globals.GCP_ACCESS_TOKENS_MODULE_NAME)
return
}
m.Credentials = creds
// Sort: active tokens with refresh tokens first, then active-only, then expired with refresh, then rest
sort.Slice(m.Credentials, func(i, j int) bool {
return credSortScore(m.Credentials[i]) > credSortScore(m.Credentials[j])
})
logger.SuccessM(fmt.Sprintf("Found %d credential(s)", len(m.Credentials)), globals.GCP_ACCESS_TOKENS_MODULE_NAME)
m.writeOutput(logger)
}
// credSortScore returns a numeric score for sorting (higher = more interesting to a pentester)
func credSortScore(c accesstokensservice.CredentialSummary) int {
score := 0
if c.Validity == "ACTIVE" {
score += 4
}
if c.HasRefresh {
score += 2
}
if c.IsActive {
score += 1
}
return score
}
func (m *AccessTokensModule) getTableHeader() []string {
return []string{
"Account",
"Type",
"Validity",
"Has Refresh Token",
"RAPT Status",
"Profile",
"Active Profile",
"Project",
"Access Token",
}
}
func (m *AccessTokensModule) credentialsToTableBody() [][]string {
var body [][]string
for _, c := range m.Credentials {
hasRefresh := "No"
if c.HasRefresh {
hasRefresh = "Yes"
}
active := "No"
if c.IsActive {
active = "Yes"
}
profile := c.Profile
if profile == "" {
profile = "-"
}
project := c.Project
if project == "" {
project = "-"
}
accessToken := c.AccessToken
if accessToken == "" {
accessToken = "-"
}
body = append(body, []string{
c.Account,
c.Type,
c.Validity,
hasRefresh,
c.RAPTStatus,
profile,
active,
project,
accessToken,
})
}
return body
}
func (m *AccessTokensModule) writeOutput(logger internal.Logger) {
body := m.credentialsToTableBody()
tables := []internal.TableFile{{
Name: "access-tokens",
Header: m.getTableHeader(),
Body: body,
}}
// Build loot files
var lootFiles []internal.LootFile
// Loot 1: Exploitation commands (curl with active access tokens)
var exploitCmds strings.Builder
exploitCmds.WriteString("# Active Access Token Exploitation Commands\n")
exploitCmds.WriteString("# Generated by CloudFox\n\n")
hasExploitCmds := false
for _, c := range m.Credentials {
if c.Type == "access_token" && c.Validity == "ACTIVE" && c.AccessToken != "" {
exploitCmds.WriteString(fmt.Sprintf("# Account: %s (Profile: %s, Project: %s)\n", c.Account, c.Profile, c.Project))
exploitCmds.WriteString(fmt.Sprintf("curl -s -H 'Authorization: Bearer %s' https://www.googleapis.com/oauth2/v1/tokeninfo\n", c.AccessToken))
exploitCmds.WriteString(fmt.Sprintf("curl -s -H 'Authorization: Bearer %s' https://cloudresourcemanager.googleapis.com/v1/projects\n\n", c.AccessToken))
hasExploitCmds = true
}
if c.Type == "sa_key" {
exploitCmds.WriteString(fmt.Sprintf("# Service Account Key: %s\n", c.Account))
exploitCmds.WriteString(fmt.Sprintf("# Source: %s\n", c.Source))
exploitCmds.WriteString(fmt.Sprintf("gcloud auth activate-service-account --key-file=%s\n\n", c.Source))
hasExploitCmds = true
}
}
if hasExploitCmds {
lootFiles = append(lootFiles, internal.LootFile{
Name: "access-tokens-exploitation-commands",
Contents: exploitCmds.String(),
})
}
// Loot 2: Refresh token commands
var refreshCmds strings.Builder
refreshCmds.WriteString("# Refresh Token Commands\n")
refreshCmds.WriteString("# Generated by CloudFox\n")
refreshCmds.WriteString("# Refresh tokens can be used to obtain new access tokens\n\n")
hasRefreshCmds := false
for _, c := range m.Credentials {
if c.HasRefresh && (c.Type == "access_token" || c.Type == "refresh_token") {
refreshCmds.WriteString(fmt.Sprintf("# Account: %s\n", c.Account))
refreshCmds.WriteString("# To extract the refresh token:\n")
refreshCmds.WriteString(fmt.Sprintf("# sqlite3 ~/.config/gcloud/credentials.db \"SELECT value FROM credentials WHERE account_id='%s'\"\n", c.Account))
refreshCmds.WriteString("# Then use it to get a new access token:\n")
refreshCmds.WriteString("# curl -s -X POST https://oauth2.googleapis.com/token \\\n")
refreshCmds.WriteString("# -d 'client_id=<CLIENT_ID>' \\\n")
refreshCmds.WriteString("# -d 'client_secret=<CLIENT_SECRET>' \\\n")
refreshCmds.WriteString("# -d 'refresh_token=<REFRESH_TOKEN>' \\\n")
refreshCmds.WriteString("# -d 'grant_type=refresh_token'\n\n")
hasRefreshCmds = true
}
}
if hasRefreshCmds {
lootFiles = append(lootFiles, internal.LootFile{
Name: "access-tokens-refresh-commands",
Contents: refreshCmds.String(),
})
}
// Loot 3: ADC commands
var adcCmds strings.Builder
adcCmds.WriteString("# Application Default Credentials (ADC) Commands\n")
adcCmds.WriteString("# Generated by CloudFox\n\n")
hasADCCmds := false
for _, c := range m.Credentials {
if c.Type == "adc" {
adcCmds.WriteString(fmt.Sprintf("# ADC Account: %s\n", c.Account))
adcCmds.WriteString(fmt.Sprintf("# Source: %s\n", c.Source))
if c.Project != "" {
adcCmds.WriteString(fmt.Sprintf("# Quota Project: %s\n", c.Project))
}
adcCmds.WriteString("# ADC is used by client libraries and tools like terraform\n")
adcCmds.WriteString("# To use these credentials:\n")
adcCmds.WriteString("# gcloud auth application-default print-access-token\n")
adcCmds.WriteString("# Or copy ~/.config/gcloud/application_default_credentials.json to your attack machine\n\n")
hasADCCmds = true
}
}
if hasADCCmds {
lootFiles = append(lootFiles, internal.LootFile{
Name: "access-tokens-adc-commands",
Contents: adcCmds.String(),
})
}
output := AccessTokensOutput{Table: tables, Loot: lootFiles}
// Use HandleOutputSmart with a local-only scope
err := internal.HandleOutputSmart(
"gcp",
m.Format,
m.OutputDir,
m.Verbosity,
m.WrapTable,
"local",
[]string{"localhost"},
[]string{"localhost"},
"local",
output,
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_ACCESS_TOKENS_MODULE_NAME)
}
}
+6 -6
View File
@@ -200,7 +200,7 @@ func (m *AppEngineModule) processProject(ctx context.Context, projectID string,
app, err := aeService.Apps.Get(projectID).Do()
if err != nil {
if !strings.Contains(err.Error(), "404") {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_APPENGINE_MODULE_NAME,
fmt.Sprintf("Could not get App Engine app in project %s", projectID))
}
@@ -251,7 +251,7 @@ func (m *AppEngineModule) processProject(ctx context.Context, projectID string,
func (m *AppEngineModule) enumerateServices(ctx context.Context, projectID string, aeService *appengine.APIService, logger internal.Logger) {
services, err := aeService.Apps.Services.List(projectID).Do()
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_APPENGINE_MODULE_NAME,
fmt.Sprintf("Could not enumerate App Engine services in project %s", projectID))
return
@@ -288,7 +288,7 @@ func (m *AppEngineModule) enumerateServices(ctx context.Context, projectID strin
func (m *AppEngineModule) enumerateVersions(ctx context.Context, projectID, serviceID, ingressSettings string, aeService *appengine.APIService, logger internal.Logger) {
versions, err := aeService.Apps.Services.Versions.List(projectID, serviceID).Do()
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_APPENGINE_MODULE_NAME,
fmt.Sprintf("Could not enumerate App Engine versions for service %s", serviceID))
return
@@ -362,7 +362,7 @@ func (m *AppEngineModule) enumerateVersions(ctx context.Context, projectID, serv
func (m *AppEngineModule) enumerateFirewallRules(ctx context.Context, projectID string, aeService *appengine.APIService, logger internal.Logger) {
rules, err := aeService.Apps.Firewall.IngressRules.List(projectID).Do()
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_APPENGINE_MODULE_NAME,
fmt.Sprintf("Could not enumerate App Engine firewall rules in project %s", projectID))
return
@@ -776,7 +776,7 @@ func (m *AppEngineModule) writeHierarchicalOutput(ctx context.Context, logger in
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), GCP_APPENGINE_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -823,6 +823,6 @@ func (m *AppEngineModule) writeFlatOutput(ctx context.Context, logger internal.L
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), GCP_APPENGINE_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+5 -10
View File
@@ -9,7 +9,6 @@ import (
artifactregistry "cloud.google.com/go/artifactregistry/apiv1"
ArtifactRegistryService "github.com/BishopFox/cloudfox/gcp/services/artifactRegistryService"
gcpinternal "github.com/BishopFox/cloudfox/internal/gcp"
"google.golang.org/api/option"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
"github.com/spf13/cobra"
@@ -74,12 +73,8 @@ func runGCPArtifactRegistryCommand(cmd *cobra.Command, args []string) {
return // Error already logged
}
// Create Artifact Registry client (uses impersonated credentials if --impersonate-sa is set)
var arOpts []option.ClientOption
if s := gcpinternal.GetDefaultSession(); s != nil {
arOpts = append(arOpts, s.GetClientOption())
}
client, err := artifactregistry.NewClient(cmdCtx.Ctx, arOpts...)
// Create Artifact Registry client
client, err := artifactregistry.NewClient(cmdCtx.Ctx)
if err != nil {
cmdCtx.Logger.ErrorM(fmt.Sprintf("Failed to create Artifact Registry client: %v", err), globals.GCP_ARTIFACT_RESGISTRY_MODULE_NAME)
return
@@ -151,7 +146,7 @@ func (m *ArtifactRegistryModule) processProject(ctx context.Context, projectID s
ars := ArtifactRegistryService.New(m.client)
result, err := ars.RepositoriesAndArtifacts(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_ARTIFACT_RESGISTRY_MODULE_NAME,
fmt.Sprintf("Could not enumerate artifact registries in project %s", projectID))
return
@@ -530,7 +525,7 @@ func (m *ArtifactRegistryModule) writeHierarchicalOutput(ctx context.Context, lo
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_ARTIFACT_RESGISTRY_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -588,6 +583,6 @@ func (m *ArtifactRegistryModule) writeFlatOutput(ctx context.Context, logger int
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_ARTIFACT_RESGISTRY_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+4 -4
View File
@@ -257,7 +257,7 @@ func (m *AssetInventoryModule) processProject(ctx context.Context, projectID str
svc := assetservice.New()
assets, err := svc.ListAssets(projectID, assetTypes)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_ASSET_INVENTORY_MODULE_NAME,
fmt.Sprintf("Could not enumerate assets in project %s", projectID))
return
@@ -283,7 +283,7 @@ func (m *AssetInventoryModule) processProjectIAM(ctx context.Context, projectID
svc := assetservice.New()
assets, err := svc.ListAssetsWithIAM(projectID, assetTypes)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_ASSET_INVENTORY_MODULE_NAME,
fmt.Sprintf("Could not enumerate assets with IAM in project %s", projectID))
return
@@ -309,7 +309,7 @@ func (m *AssetInventoryModule) processProjectCounts(ctx context.Context, project
svc := assetservice.New()
counts, err := svc.GetAssetTypeCounts(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_ASSET_INVENTORY_MODULE_NAME,
fmt.Sprintf("Could not count assets in project %s", projectID))
return
@@ -374,7 +374,7 @@ func (m *AssetInventoryModule) processProjectWithDependencies(ctx context.Contex
break
}
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
parsedErr := gcpinternal.ParseGCPError(err, "cloudasset.googleapis.com")
gcpinternal.HandleGCPError(parsedErr, logger, globals.GCP_ASSET_INVENTORY_MODULE_NAME,
fmt.Sprintf("Could not enumerate assets in project %s", projectID))
+3 -3
View File
@@ -283,7 +283,7 @@ func (m *BackupInventoryModule) enumerateDisks(ctx context.Context, projectID st
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_BACKUPINVENTORY_MODULE_NAME,
fmt.Sprintf("Could not enumerate disks in project %s", projectID))
}
@@ -376,7 +376,7 @@ func (m *BackupInventoryModule) enumerateSnapshots(ctx context.Context, projectI
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_BACKUPINVENTORY_MODULE_NAME,
fmt.Sprintf("Could not enumerate snapshots in project %s", projectID))
}
@@ -445,7 +445,7 @@ func (m *BackupInventoryModule) trackSnapshotProtection(projectID string) {
func (m *BackupInventoryModule) enumerateSQLBackups(ctx context.Context, projectID string, sqlService *sqladmin.Service, logger internal.Logger) {
instances, err := sqlService.Instances.List(projectID).Do()
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_BACKUPINVENTORY_MODULE_NAME,
fmt.Sprintf("Could not enumerate SQL instances in project %s", projectID))
return
+2 -2
View File
@@ -132,7 +132,7 @@ func (m *BeyondCorpModule) processProject(ctx context.Context, projectID string,
// Get app connectors
connectors, err := svc.ListAppConnectors(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_BEYONDCORP_MODULE_NAME,
fmt.Sprintf("Could not list app connectors in project %s", projectID))
}
@@ -146,7 +146,7 @@ func (m *BeyondCorpModule) processProject(ctx context.Context, projectID string,
// Get app connections
connections, err := svc.ListAppConnections(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_BEYONDCORP_MODULE_NAME,
fmt.Sprintf("Could not list app connections in project %s", projectID))
}
+3 -45
View File
@@ -7,8 +7,6 @@ import (
"sync"
BigQueryService "github.com/BishopFox/cloudfox/gcp/services/bigqueryService"
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
"github.com/BishopFox/cloudfox/gcp/shared"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
gcpinternal "github.com/BishopFox/cloudfox/internal/gcp"
@@ -131,46 +129,12 @@ func (m *BigQueryModule) processProject(ctx context.Context, projectID string, l
bqService := BigQueryService.New()
result, err := bqService.BigqueryDatasetsAndTables(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_BIGQUERY_MODULE_NAME,
fmt.Sprintf("Could not enumerate BigQuery in project %s", projectID))
return
}
// Inject inherited project-level IAM bindings
iamSvc := IAMService.New()
projectPolicies, projErr := iamSvc.Policies(projectID, "project")
if projErr == nil {
// Inject into datasets (AccessEntries)
for i := range result.Datasets {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("dataset", pb.Role) {
continue
}
for _, member := range pb.Members {
result.Datasets[i].AccessEntries = append(result.Datasets[i].AccessEntries, BigQueryService.AccessEntry{
Role: pb.Role,
Entity: member,
Source: "Project",
})
}
}
}
// Inject into tables
for i := range result.Tables {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("table", pb.Role) {
continue
}
result.Tables[i].IAMBindings = append(result.Tables[i].IAMBindings, BigQueryService.TableIAMBinding{
Role: pb.Role,
Members: pb.Members,
Source: "Project",
})
}
}
}
// Thread-safe store per-project
m.mu.Lock()
m.ProjectDatasets[projectID] = result.Datasets
@@ -297,7 +261,6 @@ func (m *BigQueryModule) getDatasetHeader() []string {
"IAM Binding Role",
"Principal Type",
"IAM Binding Principal",
"Binding Source",
}
}
@@ -313,7 +276,6 @@ func (m *BigQueryModule) getTableHeader() []string {
"Public",
"IAM Binding Role",
"IAM Binding Principal",
"Binding Source",
}
}
@@ -344,7 +306,6 @@ func (m *BigQueryModule) datasetsToTableBody(datasets []BigQueryService.Bigquery
role,
memberType,
entry.Entity,
shared.BindingSource(entry.Source),
})
}
} else {
@@ -357,7 +318,6 @@ func (m *BigQueryModule) datasetsToTableBody(datasets []BigQueryService.Bigquery
"-",
"-",
"-",
"-",
})
}
}
@@ -384,7 +344,6 @@ func (m *BigQueryModule) tablesToTableBody(tables []BigQueryService.BigqueryTabl
publicStatus,
"-",
"-",
"-",
})
} else {
for _, binding := range table.IAMBindings {
@@ -399,7 +358,6 @@ func (m *BigQueryModule) tablesToTableBody(tables []BigQueryService.BigqueryTabl
publicStatus,
binding.Role,
member,
shared.BindingSource(binding.Source),
})
}
}
@@ -467,7 +425,7 @@ func (m *BigQueryModule) writeHierarchicalOutput(ctx context.Context, logger int
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_BIGQUERY_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -521,6 +479,6 @@ func (m *BigQueryModule) writeFlatOutput(ctx context.Context, logger internal.Lo
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_BIGQUERY_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+1 -1
View File
@@ -128,7 +128,7 @@ func (m *BigQueryEnumModule) processProject(ctx context.Context, projectID strin
resources, err := svc.EnumerateSensitiveResources(projectID, m.MaxTables, m.SampleData, m.MaxRows)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_BIGQUERYENUM_MODULE_NAME,
fmt.Sprintf("Could not scan BigQuery in project %s", projectID))
return
+1 -1
View File
@@ -118,7 +118,7 @@ func (m *BigtableModule) processProject(ctx context.Context, projectID string, l
svc := bigtableservice.New()
result, err := svc.ListInstances(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_BIGTABLE_MODULE_NAME,
fmt.Sprintf("Could not enumerate Bigtable instances in project %s", projectID))
return
+1 -1
View File
@@ -103,7 +103,7 @@ func (m *BigtableEnumModule) processProject(ctx context.Context, projectID strin
resources, err := svc.EnumerateSensitiveResources(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_BIGTABLEENUM_MODULE_NAME,
fmt.Sprintf("Could not scan Bigtable in project %s", projectID))
return
+3 -3
View File
@@ -214,7 +214,7 @@ func (m *BucketEnumModule) processProject(ctx context.Context, projectID string,
// Get list of buckets
buckets, err := svc.GetBucketsList(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_STORAGEENUM_MODULE_NAME,
fmt.Sprintf("Could not enumerate buckets in project %s", projectID))
return
@@ -230,7 +230,7 @@ func (m *BucketEnumModule) processProject(ctx context.Context, projectID string,
for _, bucketName := range buckets {
objects, err := svc.EnumerateAllBucketObjects(bucketName, projectID, m.MaxObjects)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_STORAGEENUM_MODULE_NAME,
fmt.Sprintf("Could not enumerate bucket %s in project %s", bucketName, projectID))
continue
@@ -263,7 +263,7 @@ func (m *BucketEnumModule) processProject(ctx context.Context, projectID string,
for _, bucketName := range buckets {
files, err := svc.EnumerateBucketSensitiveFiles(bucketName, projectID, m.MaxObjects)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_STORAGEENUM_MODULE_NAME,
fmt.Sprintf("Could not scan bucket %s in project %s", bucketName, projectID))
continue
+3 -25
View File
@@ -7,7 +7,6 @@ import (
"sync"
CloudStorageService "github.com/BishopFox/cloudfox/gcp/services/cloudStorageService"
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
"github.com/BishopFox/cloudfox/gcp/shared"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
@@ -156,30 +155,12 @@ func (m *BucketsModule) processProject(ctx context.Context, projectID string, lo
cs := CloudStorageService.New()
buckets, err := cs.Buckets(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_STORAGE_MODULE_NAME,
fmt.Sprintf("Could not enumerate buckets in project %s", projectID))
return
}
// Inject inherited project-level IAM bindings into each bucket
iamSvc := IAMService.New()
projectPolicies, projErr := iamSvc.Policies(projectID, "project")
if projErr == nil {
for i := range buckets {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("bucket", pb.Role) {
continue
}
buckets[i].IAMBindings = append(buckets[i].IAMBindings, CloudStorageService.IAMBinding{
Role: pb.Role,
Members: pb.Members,
Source: "Project",
})
}
}
}
// Thread-safe store per-project
m.mu.Lock()
m.ProjectBuckets[projectID] = buckets
@@ -324,7 +305,7 @@ func (m *BucketsModule) writeHierarchicalOutput(ctx context.Context, logger inte
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_STORAGE_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -376,7 +357,7 @@ func (m *BucketsModule) writeFlatOutput(ctx context.Context, logger internal.Log
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_STORAGE_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -396,7 +377,6 @@ func (m *BucketsModule) getTableHeader() []string {
"IAM Binding Role",
"Principal Type",
"IAM Binding Principal",
"Binding Source",
"Principal Attack Paths",
}
}
@@ -474,7 +454,6 @@ func (m *BucketsModule) bucketsToTableBody(buckets []CloudStorageService.BucketI
binding.Role,
memberType,
member,
shared.BindingSource(binding.Source),
attackPaths,
})
}
@@ -496,7 +475,6 @@ func (m *BucketsModule) bucketsToTableBody(buckets []CloudStorageService.BucketI
"-",
"-",
"-",
"-",
})
}
}
+4 -4
View File
@@ -167,7 +167,7 @@ func (m *CertManagerModule) processProject(ctx context.Context, projectID string
// Get Certificate Manager certs
certs, err := svc.GetCertificates(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CERTMANAGER_MODULE_NAME,
fmt.Sprintf("Could not enumerate certificates in project %s", projectID))
}
@@ -175,7 +175,7 @@ func (m *CertManagerModule) processProject(ctx context.Context, projectID string
// Get classic SSL certs
sslCerts, err := svc.GetSSLCertificates(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CERTMANAGER_MODULE_NAME,
fmt.Sprintf("Could not enumerate SSL certificates in project %s", projectID))
}
@@ -183,7 +183,7 @@ func (m *CertManagerModule) processProject(ctx context.Context, projectID string
// Get certificate maps
certMaps, err := svc.GetCertificateMaps(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CERTMANAGER_MODULE_NAME,
fmt.Sprintf("Could not enumerate certificate maps in project %s", projectID))
}
@@ -377,6 +377,6 @@ func (m *CertManagerModule) writeFlatOutput(ctx context.Context, logger internal
"project", m.ProjectIDs, scopeNames, m.Account, output)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_CERTMANAGER_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+2 -2
View File
@@ -133,7 +133,7 @@ func (m *CloudArmorModule) processProject(ctx context.Context, projectID string,
// Get security policies
policies, err := svc.GetSecurityPolicies(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CLOUDARMOR_MODULE_NAME,
fmt.Sprintf("Could not enumerate Cloud Armor security policies in project %s", projectID))
}
@@ -141,7 +141,7 @@ func (m *CloudArmorModule) processProject(ctx context.Context, projectID string,
// Get unprotected LBs
unprotectedLBs, err := svc.GetUnprotectedLoadBalancers(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CLOUDARMOR_MODULE_NAME,
fmt.Sprintf("Could not enumerate unprotected load balancers in project %s", projectID))
}
+3 -3
View File
@@ -126,7 +126,7 @@ func (m *CloudBuildModule) processProject(ctx context.Context, projectID string,
// Get triggers
triggers, err := cbSvc.ListTriggers(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CLOUDBUILD_MODULE_NAME,
fmt.Sprintf("Could not enumerate Cloud Build triggers in project %s", projectID))
}
@@ -134,7 +134,7 @@ func (m *CloudBuildModule) processProject(ctx context.Context, projectID string,
// Get recent builds
builds, err := cbSvc.ListBuilds(projectID, 20)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CLOUDBUILD_MODULE_NAME,
fmt.Sprintf("Could not enumerate Cloud Build builds in project %s", projectID))
}
@@ -518,6 +518,6 @@ func (m *CloudBuildModule) writeFlatOutput(ctx context.Context, logger internal.
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_CLOUDBUILD_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+8 -50
View File
@@ -7,8 +7,6 @@ import (
"sync"
CloudRunService "github.com/BishopFox/cloudfox/gcp/services/cloudrunService"
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
"github.com/BishopFox/cloudfox/gcp/shared"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
gcpinternal "github.com/BishopFox/cloudfox/internal/gcp"
@@ -175,34 +173,13 @@ func (m *CloudRunModule) processProject(ctx context.Context, projectID string, l
}
m.mu.Unlock()
// Fetch project-level IAM for inherited binding injection
iamSvc := IAMService.New()
projectPolicies, _ := iamSvc.Policies(projectID, "project")
// Get services
services, err := cs.Services(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CLOUDRUN_MODULE_NAME,
fmt.Sprintf("Could not enumerate Cloud Run services in project %s", projectID))
} else {
// Inject inherited project-level IAM bindings into services
if projectPolicies != nil {
for i := range services {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("cloudrun", pb.Role) {
continue
}
for _, member := range pb.Members {
services[i].IAMBindings = append(services[i].IAMBindings, CloudRunService.IAMBinding{
Role: pb.Role,
Member: member,
Source: "Project",
})
}
}
}
}
m.mu.Lock()
m.ProjectServices[projectID] = services
for _, svc := range services {
@@ -214,27 +191,10 @@ func (m *CloudRunModule) processProject(ctx context.Context, projectID string, l
// Get jobs
jobs, err := cs.Jobs(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CLOUDRUN_MODULE_NAME,
fmt.Sprintf("Could not enumerate Cloud Run jobs in project %s", projectID))
} else {
// Inject inherited project-level IAM bindings into jobs
if projectPolicies != nil {
for i := range jobs {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("cloudrun", pb.Role) {
continue
}
for _, member := range pb.Members {
jobs[i].IAMBindings = append(jobs[i].IAMBindings, CloudRunService.IAMBinding{
Role: pb.Role,
Member: member,
Source: "Project",
})
}
}
}
}
m.mu.Lock()
m.ProjectJobs[projectID] = jobs
for _, job := range jobs {
@@ -431,7 +391,7 @@ func (m *CloudRunModule) writeHierarchicalOutput(ctx context.Context, logger int
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_CLOUDRUN_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -476,7 +436,7 @@ func (m *CloudRunModule) writeFlatOutput(ctx context.Context, logger internal.Lo
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_CLOUDRUN_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -494,7 +454,7 @@ func (m *CloudRunModule) buildTablesForProject(projectID string, services []Clou
servicesHeader := []string{
"Project", "Type", "Name", "Region", "Status", "URL", "Ingress", "Public",
"Service Account", "SA Attack Paths", "Default SA", "Image", "VPC Access",
"Min/Max", "IAM Binding Role", "IAM Binding Principal", "Binding Source",
"Min/Max", "IAM Binding Role", "IAM Binding Principal",
}
var servicesBody [][]string
@@ -537,7 +497,6 @@ func (m *CloudRunModule) buildTablesForProject(projectID string, services []Clou
formatIngress(svc.IngressSettings), publicStatus, svc.ServiceAccount,
attackPaths, defaultSA, svc.ContainerImage, vpcAccess, scaling,
binding.Role, binding.Member,
shared.BindingSource(binding.Source),
})
}
} else {
@@ -546,7 +505,7 @@ func (m *CloudRunModule) buildTablesForProject(projectID string, services []Clou
m.GetProjectName(svc.ProjectID), "Service", svc.Name, svc.Region, status, svc.URL,
formatIngress(svc.IngressSettings), publicStatus, svc.ServiceAccount,
attackPaths, defaultSA, svc.ContainerImage, vpcAccess, scaling,
"-", "-", "-",
"-", "-",
})
}
}
@@ -563,7 +522,7 @@ func (m *CloudRunModule) buildTablesForProject(projectID string, services []Clou
jobsHeader := []string{
"Project", "Type", "Name", "Region", "Status", "Service Account", "SA Attack Paths", "Default SA",
"Image", "VPC Access", "Tasks", "Parallelism", "Last Execution",
"IAM Binding Role", "IAM Binding Principal", "Binding Source",
"IAM Binding Role", "IAM Binding Principal",
}
var jobsBody [][]string
@@ -606,7 +565,6 @@ func (m *CloudRunModule) buildTablesForProject(projectID string, services []Clou
job.ServiceAccount, jobAttackPaths, defaultSA, job.ContainerImage, vpcAccess,
fmt.Sprintf("%d", job.TaskCount), fmt.Sprintf("%d", job.Parallelism),
lastExec, binding.Role, binding.Member,
shared.BindingSource(binding.Source),
})
}
} else {
@@ -615,7 +573,7 @@ func (m *CloudRunModule) buildTablesForProject(projectID string, services []Clou
m.GetProjectName(job.ProjectID), "Job", job.Name, job.Region, status,
job.ServiceAccount, jobAttackPaths, defaultSA, job.ContainerImage, vpcAccess,
fmt.Sprintf("%d", job.TaskCount), fmt.Sprintf("%d", job.Parallelism),
lastExec, "-", "-", "-",
lastExec, "-", "-",
})
}
}
+3 -3
View File
@@ -147,7 +147,7 @@ func (m *CloudSQLModule) processProject(ctx context.Context, projectID string, l
cs := CloudSQLService.New()
instances, err := cs.Instances(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CLOUDSQL_MODULE_NAME,
fmt.Sprintf("Could not enumerate Cloud SQL in project %s", projectID))
return
@@ -403,7 +403,7 @@ func (m *CloudSQLModule) writeHierarchicalOutput(ctx context.Context, logger int
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_CLOUDSQL_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -453,7 +453,7 @@ func (m *CloudSQLModule) writeFlatOutput(ctx context.Context, logger internal.Lo
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_CLOUDSQL_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+2 -2
View File
@@ -1852,7 +1852,7 @@ func (m *ComplianceDashboardModule) writeHierarchicalOutput(ctx context.Context,
err := internal.HandleHierarchicalOutputSmart("gcp", m.Format, m.Verbosity, m.WrapTable, pathBuilder, outputData)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), GCP_COMPLIANCEDASHBOARD_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -1979,7 +1979,7 @@ func (m *ComplianceDashboardModule) writeFlatOutput(ctx context.Context, logger
output,
)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_COMPLIANCEDASHBOARD_MODULE_NAME,
"Could not write output")
}
+1 -1
View File
@@ -104,7 +104,7 @@ func (m *ComposerModule) processProject(ctx context.Context, projectID string, l
svc := composerservice.New()
environments, err := svc.ListEnvironments(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_COMPOSER_MODULE_NAME,
fmt.Sprintf("Could not enumerate Composer environments in project %s", projectID))
return
+7 -7
View File
@@ -259,7 +259,7 @@ func (m *CostSecurityModule) analyzeComputeInstances(ctx context.Context, projec
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_COSTSECURITY_MODULE_NAME,
fmt.Sprintf("Could not enumerate compute instances in project %s", projectID))
}
@@ -525,7 +525,7 @@ func (m *CostSecurityModule) findOrphanedDisks(ctx context.Context, projectID st
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_COSTSECURITY_MODULE_NAME,
fmt.Sprintf("Could not enumerate disks in project %s", projectID))
}
@@ -583,7 +583,7 @@ func (m *CostSecurityModule) findOrphanedIPs(ctx context.Context, projectID stri
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_COSTSECURITY_MODULE_NAME,
fmt.Sprintf("Could not enumerate addresses in project %s", projectID))
}
@@ -592,7 +592,7 @@ func (m *CostSecurityModule) findOrphanedIPs(ctx context.Context, projectID stri
func (m *CostSecurityModule) analyzeSQLInstances(ctx context.Context, projectID string, sqlService *sqladmin.Service, logger internal.Logger) {
instances, err := sqlService.Instances.List(projectID).Do()
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_COSTSECURITY_MODULE_NAME,
fmt.Sprintf("Could not enumerate SQL instances in project %s", projectID))
return
@@ -642,7 +642,7 @@ func (m *CostSecurityModule) analyzeSQLInstances(ctx context.Context, projectID
func (m *CostSecurityModule) analyzeStorageBuckets(ctx context.Context, projectID string, storageService *storage.Service, logger internal.Logger) {
buckets, err := storageService.Buckets.List(projectID).Do()
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_COSTSECURITY_MODULE_NAME,
fmt.Sprintf("Could not enumerate storage buckets in project %s", projectID))
return
@@ -1011,7 +1011,7 @@ func (m *CostSecurityModule) writeHierarchicalOutput(ctx context.Context, logger
err := internal.HandleHierarchicalOutputSmart("gcp", m.Format, m.Verbosity, m.WrapTable, pathBuilder, outputData)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), GCP_COSTSECURITY_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -1166,6 +1166,6 @@ func (m *CostSecurityModule) writeFlatOutput(ctx context.Context, logger interna
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), GCP_COSTSECURITY_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+7 -7
View File
@@ -142,7 +142,7 @@ func (m *CrossProjectModule) Execute(ctx context.Context, logger internal.Logger
// Analyze cross-project bindings
bindings, err := svc.AnalyzeCrossProjectAccess(m.ProjectIDs, m.OrgCache)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CROSSPROJECT_MODULE_NAME,
"Could not analyze cross-project access")
} else {
@@ -152,7 +152,7 @@ func (m *CrossProjectModule) Execute(ctx context.Context, logger internal.Logger
// Get cross-project service accounts
sas, err := svc.GetCrossProjectServiceAccounts(m.ProjectIDs)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CROSSPROJECT_MODULE_NAME,
"Could not get cross-project service accounts")
} else {
@@ -162,7 +162,7 @@ func (m *CrossProjectModule) Execute(ctx context.Context, logger internal.Logger
// Find lateral movement paths
paths, err := svc.FindLateralMovementPaths(m.ProjectIDs, m.OrgCache)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CROSSPROJECT_MODULE_NAME,
"Could not find lateral movement paths")
} else {
@@ -172,7 +172,7 @@ func (m *CrossProjectModule) Execute(ctx context.Context, logger internal.Logger
// Find cross-project logging sinks
sinks, err := svc.FindCrossProjectLoggingSinks(m.ProjectIDs)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CROSSPROJECT_MODULE_NAME,
"Could not find cross-project logging sinks")
} else {
@@ -182,7 +182,7 @@ func (m *CrossProjectModule) Execute(ctx context.Context, logger internal.Logger
// Find cross-project Pub/Sub exports
pubsubExports, err := svc.FindCrossProjectPubSubExports(m.ProjectIDs)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_CROSSPROJECT_MODULE_NAME,
"Could not find cross-project Pub/Sub exports")
} else {
@@ -606,7 +606,7 @@ func (m *CrossProjectModule) writeHierarchicalOutput(ctx context.Context, logger
err := internal.HandleHierarchicalOutputSmart("gcp", m.Format, m.Verbosity, m.WrapTable, pathBuilder, outputData)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_CROSSPROJECT_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -656,7 +656,7 @@ func (m *CrossProjectModule) writeFlatOutput(ctx context.Context, logger interna
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output for project %s: %v", targetProject, err), globals.GCP_CROSSPROJECT_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
}
+3 -3
View File
@@ -703,7 +703,7 @@ func (m *DataExfiltrationModule) processProject(ctx context.Context, projectID s
func (m *DataExfiltrationModule) findPublicSnapshots(ctx context.Context, projectID string, logger internal.Logger) {
computeService, err := compute.NewService(ctx)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_DATAEXFILTRATION_MODULE_NAME,
fmt.Sprintf("Could not create Compute service in project %s", projectID))
return
@@ -848,7 +848,7 @@ func (m *DataExfiltrationModule) findPublicImages(ctx context.Context, projectID
func (m *DataExfiltrationModule) findPublicBuckets(ctx context.Context, projectID string, logger internal.Logger) {
storageService, err := storage.NewService(ctx)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_DATAEXFILTRATION_MODULE_NAME,
fmt.Sprintf("Could not create Storage service in project %s", projectID))
return
@@ -1705,6 +1705,6 @@ func (m *DataExfiltrationModule) writeFlatOutput(ctx context.Context, logger int
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), GCP_DATAEXFILTRATION_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+1 -1
View File
@@ -103,7 +103,7 @@ func (m *DataflowModule) processProject(ctx context.Context, projectID string, l
svc := dataflowservice.New()
jobs, err := svc.ListJobs(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_DATAFLOW_MODULE_NAME,
fmt.Sprintf("Could not list Dataflow jobs in project %s", projectID))
return
+1 -1
View File
@@ -104,7 +104,7 @@ func (m *DataprocModule) processProject(ctx context.Context, projectID string, l
clusters, err := svc.ListClusters(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_DATAPROC_MODULE_NAME,
fmt.Sprintf("Could not list Dataproc clusters in project %s", projectID))
return
+4 -4
View File
@@ -177,7 +177,7 @@ func (m *DNSModule) processProject(ctx context.Context, projectID string, logger
// Get zones
zones, err := ds.Zones(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_DNS_MODULE_NAME,
fmt.Sprintf("Could not enumerate DNS zones in project %s", projectID))
return
@@ -204,7 +204,7 @@ func (m *DNSModule) processProject(ctx context.Context, projectID string, logger
// Get records for each zone (outside of lock to avoid holding mutex across API call)
records, err := ds.Records(projectID, zone.Name)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_DNS_MODULE_NAME,
fmt.Sprintf("Could not enumerate DNS records in zone %s", zone.Name))
continue
@@ -486,7 +486,7 @@ func (m *DNSModule) writeHierarchicalOutput(ctx context.Context, logger internal
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_DNS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -545,6 +545,6 @@ func (m *DNSModule) writeFlatOutput(ctx context.Context, logger internal.Logger)
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_DNS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+2 -2
View File
@@ -144,7 +144,7 @@ func (m *DomainWideDelegationModule) processProject(ctx context.Context, project
svc := domainwidedelegationservice.New()
accounts, err := svc.GetDWDServiceAccounts(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_DOMAINWIDEDELEGATION_MODULE_NAME,
fmt.Sprintf("Could not check DWD service accounts in project %s", projectID))
return
@@ -753,6 +753,6 @@ func (m *DomainWideDelegationModule) writeFlatOutput(ctx context.Context, logger
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_DOMAINWIDEDELEGATION_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+2 -2
View File
@@ -167,7 +167,7 @@ func (m *EndpointsModule) processProject(ctx context.Context, projectID string,
computeService, err := compute.NewService(ctx)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, "endpoints",
fmt.Sprintf("Could not create Compute service in project %s", projectID))
} else {
@@ -1532,6 +1532,6 @@ func (m *EndpointsModule) writeFlatOutput(ctx context.Context, logger internal.L
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), "endpoints")
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+1 -1
View File
@@ -86,7 +86,7 @@ func (m *FilestoreModule) processProject(ctx context.Context, projectID string,
svc := filestoreservice.New()
instances, err := svc.ListInstances(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_FILESTORE_MODULE_NAME,
fmt.Sprintf("Could not enumerate Filestore instances in project %s", projectID))
return
+5 -5
View File
@@ -187,7 +187,7 @@ func (m *FirewallModule) processProject(ctx context.Context, projectID string, l
var err error
networks, err = ns.Networks(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_FIREWALL_MODULE_NAME,
fmt.Sprintf("Could not enumerate networks in project %s", projectID))
}
@@ -195,7 +195,7 @@ func (m *FirewallModule) processProject(ctx context.Context, projectID string, l
// Get subnets
subnets, err = ns.Subnets(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_FIREWALL_MODULE_NAME,
fmt.Sprintf("Could not enumerate subnets in project %s", projectID))
}
@@ -203,7 +203,7 @@ func (m *FirewallModule) processProject(ctx context.Context, projectID string, l
// Get firewall rules
rules, err = ns.FirewallRulesEnhanced(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_FIREWALL_MODULE_NAME,
fmt.Sprintf("Could not enumerate firewall rules in project %s", projectID))
}
@@ -530,7 +530,7 @@ func (m *FirewallModule) writeHierarchicalOutput(ctx context.Context, logger int
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_FIREWALL_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -576,7 +576,7 @@ func (m *FirewallModule) writeFlatOutput(ctx context.Context, logger internal.Lo
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_FIREWALL_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+3 -27
View File
@@ -9,7 +9,6 @@ import (
"github.com/BishopFox/cloudfox/gcp/shared"
FunctionsService "github.com/BishopFox/cloudfox/gcp/services/functionsService"
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
gcpinternal "github.com/BishopFox/cloudfox/internal/gcp"
@@ -149,32 +148,12 @@ func (m *FunctionsModule) processProject(ctx context.Context, projectID string,
fs := FunctionsService.New()
functions, err := fs.Functions(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_FUNCTIONS_MODULE_NAME,
fmt.Sprintf("Could not enumerate functions in project %s", projectID))
return
}
// Inject inherited project-level IAM bindings into each function
iamSvc := IAMService.New()
projectPolicies, projErr := iamSvc.Policies(projectID, "project")
if projErr == nil {
for i := range functions {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("function", pb.Role) {
continue
}
for _, member := range pb.Members {
functions[i].IAMBindings = append(functions[i].IAMBindings, FunctionsService.IAMBinding{
Role: pb.Role,
Member: member,
Source: "Project",
})
}
}
}
}
// Thread-safe store per-project
m.mu.Lock()
m.ProjectFunctions[projectID] = functions
@@ -350,7 +329,7 @@ func (m *FunctionsModule) writeHierarchicalOutput(ctx context.Context, logger in
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_FUNCTIONS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -393,7 +372,7 @@ func (m *FunctionsModule) writeFlatOutput(ctx context.Context, logger internal.L
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_FUNCTIONS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -516,7 +495,6 @@ func (m *FunctionsModule) getTableHeader() []string {
"VPC Access",
"IAM Binding Role",
"IAM Binding Principal",
"Binding Source",
}
}
@@ -594,7 +572,6 @@ func (m *FunctionsModule) functionsToTableBody(functions []FunctionsService.Func
vpcAccess,
binding.Role,
binding.Member,
shared.BindingSource(binding.Source),
})
}
} else {
@@ -615,7 +592,6 @@ func (m *FunctionsModule) functionsToTableBody(functions []FunctionsService.Func
vpcAccess,
"-",
"-",
"-",
})
}
}
+3 -3
View File
@@ -166,7 +166,7 @@ func (m *GKEModule) processProject(ctx context.Context, projectID string, logger
gs := GKEService.New()
clusters, nodePools, err := gs.Clusters(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_GKE_MODULE_NAME,
fmt.Sprintf("Could not enumerate GKE clusters in project %s", projectID))
return
@@ -295,7 +295,7 @@ func (m *GKEModule) writeHierarchicalOutput(ctx context.Context, logger internal
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_GKE_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -340,7 +340,7 @@ func (m *GKEModule) writeFlatOutput(ctx context.Context, logger internal.Logger)
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_GKE_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+1 -5
View File
@@ -290,7 +290,6 @@ func (m *HiddenAdminsModule) analyzeOrganizationIAM(ctx context.Context, logger
policy, err := orgsClient.GetIamPolicy(ctx, &iampb.GetIamPolicyRequest{
Resource: org.Name,
Options: &iampb.GetPolicyOptions{RequestedPolicyVersion: 3},
})
if err != nil {
continue
@@ -333,7 +332,6 @@ func (m *HiddenAdminsModule) analyzeFolderIAM(ctx context.Context, logger intern
policy, err := foldersClient.GetIamPolicy(ctx, &iampb.GetIamPolicyRequest{
Resource: folder.Name,
Options: &iampb.GetPolicyOptions{RequestedPolicyVersion: 3},
})
if err != nil {
continue
@@ -354,9 +352,7 @@ func (m *HiddenAdminsModule) analyzeProjectIAM(ctx context.Context, logger inter
return
}
policy, err := crmService.Projects.GetIamPolicy(projectID, &crmv1.GetIamPolicyRequest{
Options: &crmv1.GetPolicyOptions{RequestedPolicyVersion: 3},
}).Do()
policy, err := crmService.Projects.GetIamPolicy(projectID, &crmv1.GetIamPolicyRequest{}).Do()
if err != nil {
return
}
+20 -256
View File
@@ -7,7 +7,6 @@ import (
"sync"
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
resourceiamservice "github.com/BishopFox/cloudfox/gcp/services/resourceIAMService"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
gcpinternal "github.com/BishopFox/cloudfox/internal/gcp"
@@ -79,28 +78,6 @@ var highPrivilegeRoles = map[string]bool{
"roles/orgpolicy.policyAdmin": true,
}
// adminRoles are roles that grant broad administrative control. Used as a
// fallback for the Admin column when FoxMapper data is not available.
var adminRoles = map[string]bool{
"roles/owner": true,
"roles/editor": true,
"roles/resourcemanager.projectIamAdmin": true,
"roles/resourcemanager.folderAdmin": true,
"roles/resourcemanager.folderIamAdmin": true,
"roles/resourcemanager.organizationAdmin": true,
"roles/iam.securityAdmin": true,
"roles/iam.roleAdmin": true,
}
// isAdminRole returns "Yes" if the role is a known admin role, "" otherwise.
// Used as a fallback when FoxMapper is not available.
func isAdminRole(role string) string {
if adminRoles[role] {
return "Yes"
}
return ""
}
// ------------------------------
// Module Struct with embedded BaseGCPModule
// ------------------------------
@@ -108,12 +85,11 @@ type IAMModule struct {
gcpinternal.BaseGCPModule
// Module-specific fields - using enhanced data
ScopeBindings []IAMService.ScopeBinding
ServiceAccounts []IAMService.ServiceAccountInfo
CustomRoles []IAMService.CustomRole
Groups []IAMService.GroupInfo
MFAStatus map[string]*IAMService.MFAStatus
ResourceBindings []resourceiamservice.ResourceIAMBinding
ScopeBindings []IAMService.ScopeBinding
ServiceAccounts []IAMService.ServiceAccountInfo
CustomRoles []IAMService.CustomRole
Groups []IAMService.GroupInfo
MFAStatus map[string]*IAMService.MFAStatus
// Per-scope loot for inheritance-aware output
OrgLoot map[string]*internal.LootFile // orgID -> loot commands
@@ -156,12 +132,11 @@ func runGCPIAMCommand(cmd *cobra.Command, args []string) {
// Create module instance
module := &IAMModule{
BaseGCPModule: gcpinternal.NewBaseGCPModule(cmdCtx),
ScopeBindings: []IAMService.ScopeBinding{},
ServiceAccounts: []IAMService.ServiceAccountInfo{},
CustomRoles: []IAMService.CustomRole{},
Groups: []IAMService.GroupInfo{},
MFAStatus: make(map[string]*IAMService.MFAStatus),
ResourceBindings: []resourceiamservice.ResourceIAMBinding{},
ScopeBindings: []IAMService.ScopeBinding{},
ServiceAccounts: []IAMService.ServiceAccountInfo{},
CustomRoles: []IAMService.CustomRole{},
Groups: []IAMService.GroupInfo{},
MFAStatus: make(map[string]*IAMService.MFAStatus),
OrgLoot: make(map[string]*internal.LootFile),
FolderLoot: make(map[string]*internal.LootFile),
ProjectLoot: make(map[string]*internal.LootFile),
@@ -196,7 +171,7 @@ func (m *IAMModule) Execute(ctx context.Context, logger internal.Logger) {
iamService := IAMService.New()
iamData, err := iamService.CombinedIAMEnhanced(ctx, m.ProjectIDs, m.ProjectNames)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_IAM_MODULE_NAME, "Failed to enumerate IAM")
return
}
@@ -207,16 +182,6 @@ func (m *IAMModule) Execute(ctx context.Context, logger internal.Logger) {
m.Groups = iamData.Groups
m.MFAStatus = iamData.MFAStatus
// Enumerate resource-level IAM bindings (SA, buckets, secrets, functions, etc.)
resourceIAMSvc := resourceiamservice.New()
for _, projectID := range m.ProjectIDs {
resourceBindings, err := resourceIAMSvc.GetAllResourceIAM(ctx, projectID)
if err != nil {
continue
}
m.ResourceBindings = append(m.ResourceBindings, resourceBindings...)
}
// Try to enumerate group memberships to build reverse lookup
enrichedGroups := iamService.GetGroupMemberships(ctx, m.Groups)
m.Groups = enrichedGroups
@@ -255,9 +220,8 @@ func (m *IAMModule) Execute(ctx context.Context, logger internal.Logger) {
}
}
logger.SuccessM(fmt.Sprintf("Found %d binding(s) across %d org(s), %d folder(s), %d project(s); %d resource-level binding(s); %d SA(s), %d custom role(s), %d group(s)",
logger.SuccessM(fmt.Sprintf("Found %d binding(s) across %d org(s), %d folder(s), %d project(s); %d SA(s), %d custom role(s), %d group(s)",
len(m.ScopeBindings), orgCount, folderCount, projectCount,
len(m.ResourceBindings),
len(m.ServiceAccounts), len(m.CustomRoles), len(m.Groups)), globals.GCP_IAM_MODULE_NAME)
// Write output
@@ -667,11 +631,9 @@ func (m *IAMModule) buildTables() []internal.TableFile {
// Add scope bindings (one row per binding)
for _, sb := range m.ScopeBindings {
// Check admin status: FoxMapper (granular) > role-based fallback
// Check admin status from FoxMapper only - shows Org/Folder/Project or No
// This is different from "high privilege roles" - Admin means broad IAM control
adminStatus := gcpinternal.GetAdminStatusFromCache(m.FoxMapperCache, sb.MemberEmail)
if adminStatus == "" {
adminStatus = isAdminRole(sb.Role)
}
if adminStatus == "" {
adminStatus = "No"
}
@@ -736,91 +698,6 @@ func (m *IAMModule) buildTables() []internal.TableFile {
})
}
// Add resource-level IAM bindings (one row per binding)
for _, rb := range m.ResourceBindings {
memberType := resourceiamservice.DetermineMemberType(rb.Member)
memberEmail := rb.MemberEmail
// Check admin status: FoxMapper (granular) > role-based fallback
adminStatus := gcpinternal.GetAdminStatusFromCache(m.FoxMapperCache, memberEmail)
if adminStatus == "" {
adminStatus = isAdminRole(rb.Role)
}
if adminStatus == "" {
adminStatus = "No"
}
isCustom := "No"
if strings.HasPrefix(rb.Role, "projects/") || strings.HasPrefix(rb.Role, "organizations/") {
isCustom = "Yes"
}
condition := "No"
if rb.HasCondition && rb.ConditionTitle != "" {
condition = rb.ConditionTitle
} else if rb.HasCondition {
condition = "Yes"
}
// Get MFA status
mfa := "-"
if memberType == "User" {
if status, ok := m.MFAStatus[memberEmail]; ok {
if status.Error != "" {
mfa = "Unknown"
} else if status.HasMFA {
mfa = "Yes"
} else {
mfa = "No"
}
}
} else if memberType == "ServiceAccount" {
mfa = "N/A"
}
// Get groups this member belongs to
groups := "-"
if memberGroups, ok := m.MemberToGroups[memberEmail]; ok && len(memberGroups) > 0 {
groups = strings.Join(memberGroups, ", ")
}
// Check for federated identity
federated := formatFederatedInfo(parseFederatedIdentity(memberEmail))
// Check attack paths for service account principals
attackPaths := "-"
if memberType == "ServiceAccount" {
attackPaths = gcpinternal.GetAttackSummaryFromCaches(m.FoxMapperCache, nil, memberEmail)
}
body = append(body, []string{
rb.ResourceType,
rb.ResourceID,
rb.ResourceName,
memberType,
memberEmail,
rb.Role,
adminStatus,
isCustom,
"-",
condition,
mfa,
groups,
federated,
attackPaths,
})
}
// Build SA email -> roles lookup from scope bindings for admin fallback.
// ServiceAccountsBasic() doesn't populate the Roles field, so we
// extract roles from the already-enumerated bindings.
saRolesMap := make(map[string][]string)
for _, sb := range m.ScopeBindings {
if sb.MemberType == "ServiceAccount" {
saRolesMap[sb.MemberEmail] = append(saRolesMap[sb.MemberEmail], sb.Role)
}
}
// Add service accounts
for _, sa := range m.ServiceAccounts {
hasKeys := "No"
@@ -839,16 +716,8 @@ func (m *IAMModule) buildTables() []internal.TableFile {
groups = strings.Join(memberGroups, ", ")
}
// Check admin status: FoxMapper (granular) > role-based fallback
// Check admin status from FoxMapper
adminStatus := gcpinternal.GetAdminStatusFromCache(m.FoxMapperCache, sa.Email)
if adminStatus == "" {
for _, role := range saRolesMap[sa.Email] {
if adminRoles[role] {
adminStatus = "Yes"
break
}
}
}
if adminStatus == "" {
adminStatus = "No"
}
@@ -1095,7 +964,7 @@ func (m *IAMModule) writeHierarchicalOutput(ctx context.Context, logger internal
err := internal.HandleHierarchicalOutputSmart("gcp", m.Format, m.Verbosity, m.WrapTable, pathBuilder, outputData)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_IAM_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -1129,12 +998,6 @@ func (m *IAMModule) writeHierarchicalOutputTee(ctx context.Context, logger inter
}
}
// Build reverse lookup: for each resource ID, which project it belongs to
resourceToProject := make(map[string]string)
for _, rb := range m.ResourceBindings {
resourceToProject[rb.ResourceID] = rb.ProjectID
}
// Create a row router that routes based on scope type and OrgCache
rowRouter := func(row []string) []string {
// Row format: [ScopeType, ScopeID, ScopeName, ...]
@@ -1158,11 +1021,6 @@ func (m *IAMModule) writeHierarchicalOutputTee(ctx context.Context, logger inter
}
return m.ProjectIDs
default:
// Resource-level binding (serviceAccount, bucket, secret, etc.)
// Route to the project that owns this resource
if projectID, ok := resourceToProject[scopeID]; ok {
return []string{projectID}
}
return nil
}
}
@@ -1183,7 +1041,7 @@ func (m *IAMModule) writeHierarchicalOutputTee(ctx context.Context, logger inter
err := internal.HandleHierarchicalOutputTee(config)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing tee streaming output: %v", err), globals.GCP_IAM_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -1241,11 +1099,8 @@ func (m *IAMModule) buildTablesForProject(projectID string) []internal.TableFile
continue
}
// Check admin status: FoxMapper (granular) > role-based fallback
// Check admin status from FoxMapper only - shows Org/Folder/Project or No
adminStatus := gcpinternal.GetAdminStatusFromCache(m.FoxMapperCache, sb.MemberEmail)
if adminStatus == "" {
adminStatus = isAdminRole(sb.Role)
}
if adminStatus == "" {
adminStatus = "No"
}
@@ -1306,89 +1161,6 @@ func (m *IAMModule) buildTablesForProject(projectID string) []internal.TableFile
})
}
// Add resource-level IAM bindings for this project
for _, rb := range m.ResourceBindings {
if rb.ProjectID != projectID {
continue
}
memberType := resourceiamservice.DetermineMemberType(rb.Member)
memberEmail := rb.MemberEmail
// Check admin status: FoxMapper (granular) > role-based fallback
adminStatus := gcpinternal.GetAdminStatusFromCache(m.FoxMapperCache, memberEmail)
if adminStatus == "" {
adminStatus = isAdminRole(rb.Role)
}
if adminStatus == "" {
adminStatus = "No"
}
isCustom := "No"
if strings.HasPrefix(rb.Role, "projects/") || strings.HasPrefix(rb.Role, "organizations/") {
isCustom = "Yes"
}
condition := "No"
if rb.HasCondition && rb.ConditionTitle != "" {
condition = rb.ConditionTitle
} else if rb.HasCondition {
condition = "Yes"
}
mfa := "-"
if memberType == "User" {
if status, ok := m.MFAStatus[memberEmail]; ok {
if status.Error != "" {
mfa = "Unknown"
} else if status.HasMFA {
mfa = "Yes"
} else {
mfa = "No"
}
}
} else if memberType == "ServiceAccount" {
mfa = "N/A"
}
groups := "-"
if memberGroups, ok := m.MemberToGroups[memberEmail]; ok && len(memberGroups) > 0 {
groups = strings.Join(memberGroups, ", ")
}
federated := formatFederatedInfo(parseFederatedIdentity(memberEmail))
attackPaths := "-"
if memberType == "ServiceAccount" {
attackPaths = gcpinternal.GetAttackSummaryFromCaches(m.FoxMapperCache, nil, memberEmail)
}
body = append(body, []string{
rb.ResourceType,
rb.ResourceID,
rb.ResourceName,
memberType,
memberEmail,
rb.Role,
adminStatus,
isCustom,
"-",
condition,
mfa,
groups,
federated,
attackPaths,
})
}
// Build SA email -> roles lookup from scope bindings for admin fallback
saRolesMap := make(map[string][]string)
for _, sb := range m.ScopeBindings {
if sb.MemberType == "ServiceAccount" {
saRolesMap[sb.MemberEmail] = append(saRolesMap[sb.MemberEmail], sb.Role)
}
}
// Add service accounts for this project only
for _, sa := range m.ServiceAccounts {
if sa.ProjectID != projectID {
@@ -1410,16 +1182,8 @@ func (m *IAMModule) buildTablesForProject(projectID string) []internal.TableFile
groups = strings.Join(memberGroups, ", ")
}
// Check admin status: FoxMapper (granular) > role-based fallback
// Check admin status from FoxMapper
adminStatus := gcpinternal.GetAdminStatusFromCache(m.FoxMapperCache, sa.Email)
if adminStatus == "" {
for _, role := range saRolesMap[sa.Email] {
if adminRoles[role] {
adminStatus = "Yes"
break
}
}
}
if adminStatus == "" {
adminStatus = "No"
}
@@ -1566,6 +1330,6 @@ func (m *IAMModule) writeFlatOutput(ctx context.Context, logger internal.Logger)
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_IAM_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+1 -1
View File
@@ -99,7 +99,7 @@ func (m *IAPModule) processProject(ctx context.Context, projectID string, logger
// Get tunnel destination groups
groups, err := svc.ListTunnelDestGroups(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_IAP_MODULE_NAME,
fmt.Sprintf("Could not enumerate IAP tunnel groups in project %s", projectID))
} else {
+2 -6
View File
@@ -376,7 +376,7 @@ func (m *IdentityFederationModule) writeHierarchicalOutput(ctx context.Context,
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_IDENTITY_FEDERATION_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -420,7 +420,7 @@ func (m *IdentityFederationModule) writeFlatOutput(ctx context.Context, logger i
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_IDENTITY_FEDERATION_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -448,7 +448,6 @@ func (m *IdentityFederationModule) buildTables(
"Display Name",
"State",
"Disabled",
"Full Resource Path",
}
var poolsBody [][]string
@@ -463,7 +462,6 @@ func (m *IdentityFederationModule) buildTables(
pool.DisplayName,
pool.State,
disabled,
pool.Name,
})
}
@@ -484,7 +482,6 @@ func (m *IdentityFederationModule) buildTables(
"OIDC Issuer / AWS Account",
"Trust Scope",
"Access Condition",
"Full Resource Path",
}
var providersBody [][]string
@@ -511,7 +508,6 @@ func (m *IdentityFederationModule) buildTables(
issuerOrAccount,
trustScope,
attrCond,
p.Name,
})
}
+15 -62
View File
@@ -9,8 +9,6 @@ import (
"sync"
ComputeEngineService "github.com/BishopFox/cloudfox/gcp/services/computeEngineService"
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
orgpolicyservice "github.com/BishopFox/cloudfox/gcp/services/orgpolicyService"
"github.com/BishopFox/cloudfox/gcp/shared"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
@@ -41,7 +39,6 @@ Security Columns:
- BroadScopes: Has cloud-platform or other broad OAuth scopes
- OSLogin: OS Login enabled (recommended for access control)
- OSLogin2FA: OS Login with 2FA required
- OSLoginPolicy: Whether compute.requireOsLogin org policy is enforced (inherited)
- BlockProjKeys: Instance blocks project-wide SSH keys
- SerialPort: Serial port access enabled (security risk if exposed)
- CanIPForward: Can forward packets (potential for lateral movement)
@@ -58,12 +55,11 @@ type InstancesModule struct {
gcpinternal.BaseGCPModule
// Module-specific fields - per-project for hierarchical output
ProjectInstances map[string][]ComputeEngineService.ComputeEngineInfo // projectID -> instances
ProjectMetadata map[string]*ComputeEngineService.ProjectMetadataInfo // projectID -> metadata
ProjectOSLoginPolicy map[string]string // projectID -> "Enforced", "Not Enforced", "Unknown"
LootMap map[string]map[string]*internal.LootFile // projectID -> loot files
FoxMapperCache *gcpinternal.FoxMapperCache // FoxMapper graph data (preferred)
mu sync.Mutex
ProjectInstances map[string][]ComputeEngineService.ComputeEngineInfo // projectID -> instances
ProjectMetadata map[string]*ComputeEngineService.ProjectMetadataInfo // projectID -> metadata
LootMap map[string]map[string]*internal.LootFile // projectID -> loot files
FoxMapperCache *gcpinternal.FoxMapperCache // FoxMapper graph data (preferred)
mu sync.Mutex
}
// ------------------------------
@@ -89,11 +85,10 @@ func runGCPInstancesCommand(cmd *cobra.Command, args []string) {
// Create module instance
module := &InstancesModule{
BaseGCPModule: gcpinternal.NewBaseGCPModule(cmdCtx),
ProjectInstances: make(map[string][]ComputeEngineService.ComputeEngineInfo),
ProjectMetadata: make(map[string]*ComputeEngineService.ProjectMetadataInfo),
ProjectOSLoginPolicy: make(map[string]string),
LootMap: make(map[string]map[string]*internal.LootFile),
BaseGCPModule: gcpinternal.NewBaseGCPModule(cmdCtx),
ProjectInstances: make(map[string][]ComputeEngineService.ComputeEngineInfo),
ProjectMetadata: make(map[string]*ComputeEngineService.ProjectMetadataInfo),
LootMap: make(map[string]map[string]*internal.LootFile),
}
// Execute enumeration
@@ -147,47 +142,16 @@ func (m *InstancesModule) processProject(ctx context.Context, projectID string,
ces := ComputeEngineService.New()
instances, projectMeta, err := ces.InstancesWithMetadata(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_INSTANCES_MODULE_NAME,
fmt.Sprintf("Could not enumerate instances in project %s", projectID))
return
}
// Inject inherited project-level IAM bindings into each instance
iamSvc := IAMService.New()
projectPolicies, projErr := iamSvc.Policies(projectID, "project")
if projErr == nil {
for i := range instances {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("instance", pb.Role) {
continue
}
for _, member := range pb.Members {
instances[i].IAMBindings = append(instances[i].IAMBindings, ComputeEngineService.IAMBinding{
Role: pb.Role,
Member: member,
Source: "Project",
})
}
}
}
}
// Check effective compute.requireOsLogin org policy for this project
orgPolicySvc := orgpolicyservice.New()
effectivePolicy, policyErr := orgPolicySvc.GetEffectivePolicy("project", projectID, "compute.requireOsLogin")
osLoginPolicy := "Unknown"
if policyErr == nil && effectivePolicy != nil && effectivePolicy.Enforced {
osLoginPolicy = "Enforced"
} else if policyErr == nil {
osLoginPolicy = "Not Enforced"
}
// Thread-safe store per-project
m.mu.Lock()
m.ProjectInstances[projectID] = instances
m.ProjectMetadata[projectID] = projectMeta
m.ProjectOSLoginPolicy[projectID] = osLoginPolicy
// Initialize loot for this project
if m.LootMap[projectID] == nil {
@@ -618,7 +582,7 @@ func (m *InstancesModule) writeHierarchicalOutput(ctx context.Context, logger in
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_INSTANCES_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -699,7 +663,7 @@ func (m *InstancesModule) writeFlatOutput(ctx context.Context, logger internal.L
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_INSTANCES_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -708,7 +672,7 @@ func (m *InstancesModule) writeFlatOutput(ctx context.Context, logger internal.L
// - Identity: Project, Name, Type, Zone, State, Machine Type
// - Network: External IP, Internal IP, IP Forward
// - Service Account: Service Account, SA Attack Paths, Scopes, Default SA, Broad Scopes
// - Access Control: OS Login, OS Login 2FA, OS Login Policy, Block Proj Keys, Serial Port
// - Access Control: OS Login, OS Login 2FA, Block Proj Keys, Serial Port
// - Protection: Delete Protect, Last Snapshot
// - Hardware Security: Shielded VM, Secure Boot, vTPM, Integrity, Confidential
// - Disk Encryption: Encryption, KMS Key
@@ -735,7 +699,6 @@ func (m *InstancesModule) getInstancesTableHeader() []string {
// Access Control
"OS Login",
"OS Login 2FA",
"OS Login Policy",
"Block Proj Keys",
"Serial Port",
// Protection
@@ -753,7 +716,6 @@ func (m *InstancesModule) getInstancesTableHeader() []string {
// IAM
"IAM Binding Role",
"IAM Binding Principal",
"Binding Source",
}
}
@@ -923,12 +885,6 @@ func (m *InstancesModule) instancesToTableBody(instances []ComputeEngineService.
kmsKey = "-"
}
// OS Login Policy display
osLoginPolicy := "Unknown"
if val, ok := m.ProjectOSLoginPolicy[instance.ProjectID]; ok {
osLoginPolicy = val
}
// Instance type for contextual display
instType := instance.InstanceType
if instType == "" {
@@ -960,7 +916,6 @@ func (m *InstancesModule) instancesToTableBody(instances []ComputeEngineService.
// Access Control
shared.BoolToYesNo(instance.OSLoginEnabled),
shared.BoolToYesNo(instance.OSLogin2FAEnabled),
osLoginPolicy,
shared.BoolToYesNo(instance.BlockProjectSSHKeys),
shared.BoolToYesNo(instance.SerialPortEnabled),
// Protection - Delete protection is NOT expected for managed instances (they're ephemeral)
@@ -981,20 +936,18 @@ func (m *InstancesModule) instancesToTableBody(instances []ComputeEngineService.
// If instance has IAM bindings, create one row per binding
if len(instance.IAMBindings) > 0 {
for _, binding := range instance.IAMBindings {
row := make([]string, len(baseRow)+3)
row := make([]string, len(baseRow)+2)
copy(row, baseRow)
row[len(baseRow)] = binding.Role
row[len(baseRow)+1] = binding.Member
row[len(baseRow)+2] = shared.BindingSource(binding.Source)
body = append(body, row)
}
} else {
// No IAM bindings - single row
row := make([]string, len(baseRow)+3)
row := make([]string, len(baseRow)+2)
copy(row, baseRow)
row[len(baseRow)] = "-"
row[len(baseRow)+1] = "-"
row[len(baseRow)+2] = "-"
body = append(body, row)
}
}
+2 -2
View File
@@ -523,7 +523,7 @@ func (m *KeysModule) writeHierarchicalOutput(ctx context.Context, logger interna
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_KEYS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -569,6 +569,6 @@ func (m *KeysModule) writeFlatOutput(ctx context.Context, logger internal.Logger
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_KEYS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+4 -28
View File
@@ -7,7 +7,6 @@ import (
"sync"
KMSService "github.com/BishopFox/cloudfox/gcp/services/kmsService"
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
"github.com/BishopFox/cloudfox/gcp/shared"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
@@ -171,7 +170,7 @@ func (m *KMSModule) processProject(ctx context.Context, projectID string, logger
// Get key rings
keyRings, err := ks.KeyRings(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_KMS_MODULE_NAME,
fmt.Sprintf("Could not enumerate KMS key rings in project %s", projectID))
return
@@ -180,31 +179,11 @@ func (m *KMSModule) processProject(ctx context.Context, projectID string, logger
// Get crypto keys
keys, err := ks.CryptoKeys(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_KMS_MODULE_NAME,
fmt.Sprintf("Could not enumerate KMS keys in project %s", projectID))
}
// Inject inherited project-level IAM bindings into each key
iamSvc := IAMService.New()
projectPolicies, projErr := iamSvc.Policies(projectID, "project")
if projErr == nil {
for i := range keys {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("cryptoKey", pb.Role) {
continue
}
for _, member := range pb.Members {
keys[i].IAMBindings = append(keys[i].IAMBindings, KMSService.IAMBinding{
Role: pb.Role,
Member: member,
Source: "Project",
})
}
}
}
}
// Thread-safe store per-project
m.mu.Lock()
m.ProjectKeyRings[projectID] = keyRings
@@ -316,7 +295,6 @@ func (m *KMSModule) getKeysHeader() []string {
"Public Decrypt",
"IAM Binding Role",
"IAM Binding Principal",
"Binding Source",
}
}
@@ -363,7 +341,6 @@ func (m *KMSModule) keysToTableBody(keys []KMSService.CryptoKeyInfo) [][]string
shared.BoolToYesNo(key.IsPublicDecrypt),
binding.Role,
binding.Member,
shared.BindingSource(binding.Source),
})
}
} else {
@@ -382,7 +359,6 @@ func (m *KMSModule) keysToTableBody(keys []KMSService.CryptoKeyInfo) [][]string
shared.BoolToYesNo(key.IsPublicDecrypt),
"-",
"-",
"-",
})
}
}
@@ -473,7 +449,7 @@ func (m *KMSModule) writeHierarchicalOutput(ctx context.Context, logger internal
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_KMS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -536,7 +512,7 @@ func (m *KMSModule) writeFlatOutput(ctx context.Context, logger internal.Logger)
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_KMS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+2 -2
View File
@@ -399,7 +399,7 @@ func (m *LateralMovementModule) findImpersonationChains(ctx context.Context, pro
// Get all service accounts (without keys - not needed for impersonation analysis)
serviceAccounts, err := iamService.ServiceAccountsBasic(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_LATERALMOVEMENT_MODULE_NAME,
fmt.Sprintf("Could not get service accounts in project %s", projectID))
return
@@ -1009,6 +1009,6 @@ func (m *LateralMovementModule) writeFlatOutput(ctx context.Context, logger inte
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), GCP_LATERALMOVEMENT_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+3 -3
View File
@@ -133,7 +133,7 @@ func (m *LoadBalancersModule) processProject(ctx context.Context, projectID stri
// Get load balancers
lbs, err := svc.ListLoadBalancers(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_LOADBALANCERS_MODULE_NAME,
fmt.Sprintf("Could not list load balancers in project %s", projectID))
} else {
@@ -148,7 +148,7 @@ func (m *LoadBalancersModule) processProject(ctx context.Context, projectID stri
// Get SSL policies
sslPolicies, err := svc.ListSSLPolicies(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_LOADBALANCERS_MODULE_NAME,
fmt.Sprintf("Could not list SSL policies in project %s", projectID))
} else {
@@ -160,7 +160,7 @@ func (m *LoadBalancersModule) processProject(ctx context.Context, projectID stri
// Get backend services
backends, err := svc.ListBackendServices(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_LOADBALANCERS_MODULE_NAME,
fmt.Sprintf("Could not list backend services in project %s", projectID))
} else {
+1 -1
View File
@@ -130,7 +130,7 @@ func (m *LogEnumModule) processProject(ctx context.Context, projectID string, lo
entries, err := svc.EnumerateSensitiveLogs(projectID, m.Hours, m.MaxEntries, m.LogNameFilter)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_LOGGINGENUM_MODULE_NAME,
fmt.Sprintf("Could not scan logs in project %s", projectID))
return
+4 -4
View File
@@ -175,7 +175,7 @@ func (m *LoggingModule) processProject(ctx context.Context, projectID string, lo
// Get sinks
sinks, err := ls.Sinks(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_LOGGING_MODULE_NAME,
fmt.Sprintf("Could not enumerate logging sinks in project %s", projectID))
} else {
@@ -185,7 +185,7 @@ func (m *LoggingModule) processProject(ctx context.Context, projectID string, lo
// Get metrics
metrics, err := ls.Metrics(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_LOGGING_MODULE_NAME,
fmt.Sprintf("Could not enumerate log metrics in project %s", projectID))
} else {
@@ -545,7 +545,7 @@ func (m *LoggingModule) writeHierarchicalOutput(ctx context.Context, logger inte
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_LOGGING_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -616,7 +616,7 @@ func (m *LoggingModule) writeFlatOutput(ctx context.Context, logger internal.Log
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_LOGGING_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+1 -1
View File
@@ -95,7 +95,7 @@ func (m *MemorystoreModule) processProject(ctx context.Context, projectID string
svc := memorystoreservice.New()
instances, err := svc.ListRedisInstances(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_MEMORYSTORE_MODULE_NAME,
fmt.Sprintf("Could not list Redis instances in project %s", projectID))
return
+4 -4
View File
@@ -273,7 +273,7 @@ func (m *MonitoringAlertsModule) enumerateAlertPolicies(ctx context.Context, pro
break
}
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_MONITORINGALERTS_MODULE_NAME,
fmt.Sprintf("Could not enumerate alert policies in project %s", projectID))
break
@@ -347,7 +347,7 @@ func (m *MonitoringAlertsModule) enumerateNotificationChannels(ctx context.Conte
break
}
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_MONITORINGALERTS_MODULE_NAME,
fmt.Sprintf("Could not enumerate notification channels in project %s", projectID))
break
@@ -399,7 +399,7 @@ func (m *MonitoringAlertsModule) enumerateUptimeChecks(ctx context.Context, proj
break
}
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_MONITORINGALERTS_MODULE_NAME,
fmt.Sprintf("Could not enumerate uptime checks in project %s", projectID))
break
@@ -896,7 +896,7 @@ func (m *MonitoringAlertsModule) writeFlatOutput(ctx context.Context, logger int
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), GCP_MONITORINGALERTS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+6 -6
View File
@@ -347,7 +347,7 @@ func (m *NetworkTopologyModule) enumerateNetworks(ctx context.Context, projectID
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_NETWORKTOPOLOGY_MODULE_NAME,
fmt.Sprintf("Could not list networks in project %s", projectID))
}
@@ -400,7 +400,7 @@ func (m *NetworkTopologyModule) enumerateSubnets(ctx context.Context, projectID
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_NETWORKTOPOLOGY_MODULE_NAME,
fmt.Sprintf("Could not list subnets in project %s", projectID))
}
@@ -474,7 +474,7 @@ func (m *NetworkTopologyModule) enumerateRoutes(ctx context.Context, projectID s
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_NETWORKTOPOLOGY_MODULE_NAME,
fmt.Sprintf("Could not list routes in project %s", projectID))
}
@@ -524,7 +524,7 @@ func (m *NetworkTopologyModule) enumerateCloudNAT(ctx context.Context, projectID
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_NETWORKTOPOLOGY_MODULE_NAME,
fmt.Sprintf("Could not list Cloud NAT in project %s", projectID))
}
@@ -561,7 +561,7 @@ func (m *NetworkTopologyModule) checkSharedVPCHost(ctx context.Context, projectI
return nil
})
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, GCP_NETWORKTOPOLOGY_MODULE_NAME,
fmt.Sprintf("Could not list XPN resources in project %s", projectID))
}
@@ -1751,6 +1751,6 @@ func (m *NetworkTopologyModule) writeFlatOutput(ctx context.Context, logger inte
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), GCP_NETWORKTOPOLOGY_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+1 -1
View File
@@ -124,7 +124,7 @@ func (m *NotebooksModule) processProject(ctx context.Context, projectID string,
// Get instances
instances, err := svc.ListInstances(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_NOTEBOOKS_MODULE_NAME,
fmt.Sprintf("Could not list notebook instances in project %s", projectID))
} else {
+2 -2
View File
@@ -924,7 +924,7 @@ func (m *OrganizationsModule) writeHierarchicalOutput(ctx context.Context, logge
err := internal.HandleHierarchicalOutputSmart("gcp", m.Format, m.Verbosity, m.WrapTable, pathBuilder, outputData)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_ORGANIZATIONS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -956,6 +956,6 @@ func (m *OrganizationsModule) writeFlatOutput(ctx context.Context, logger intern
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_ORGANIZATIONS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+47 -217
View File
@@ -1,14 +1,13 @@
package commands
import (
"github.com/BishopFox/cloudfox/gcp/shared"
"context"
"fmt"
"strings"
"sync"
organizationsservice "github.com/BishopFox/cloudfox/gcp/services/organizationsService"
orgpolicyservice "github.com/BishopFox/cloudfox/gcp/services/orgpolicyService"
"github.com/BishopFox/cloudfox/gcp/shared"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
gcpinternal "github.com/BishopFox/cloudfox/internal/gcp"
@@ -24,9 +23,6 @@ var GCPOrgPoliciesCommand = &cobra.Command{
Organization policies control security constraints across GCP resources. This module
identifies policies that may be misconfigured or weakened, creating security risks.
Enumerates policies at organization, folder, and project levels. Org and folder level
enumeration requires orgpolicy.policies.list at those scopes and is best-effort.
Security-Relevant Policies Analyzed:
- Domain restrictions (iam.allowedPolicyMemberDomains)
- Service account key controls (iam.disableServiceAccountKeyCreation)
@@ -48,9 +44,7 @@ Risk Indicators:
type OrgPoliciesModule struct {
gcpinternal.BaseGCPModule
ProjectPolicies map[string][]orgpolicyservice.OrgPolicyInfo // projectID -> policies
OrgPolicies map[string][]orgpolicyservice.OrgPolicyInfo // orgID -> policies
FolderPolicies map[string][]orgpolicyservice.OrgPolicyInfo // folderID -> policies
LootMap map[string]map[string]*internal.LootFile // scopeID -> loot files
LootMap map[string]map[string]*internal.LootFile // projectID -> loot files
mu sync.Mutex
}
@@ -71,18 +65,12 @@ func runGCPOrgPoliciesCommand(cmd *cobra.Command, args []string) {
module := &OrgPoliciesModule{
BaseGCPModule: gcpinternal.NewBaseGCPModule(cmdCtx),
ProjectPolicies: make(map[string][]orgpolicyservice.OrgPolicyInfo),
OrgPolicies: make(map[string][]orgpolicyservice.OrgPolicyInfo),
FolderPolicies: make(map[string][]orgpolicyservice.OrgPolicyInfo),
LootMap: make(map[string]map[string]*internal.LootFile),
}
module.Execute(cmdCtx.Ctx, cmdCtx.Logger)
}
func (m *OrgPoliciesModule) Execute(ctx context.Context, logger internal.Logger) {
// Enumerate org-level and folder-level policies (best-effort)
m.enumerateOrgAndFolderPolicies(logger)
// Enumerate project-level policies
m.RunProjectEnumeration(ctx, logger, m.ProjectIDs, globals.GCP_ORGPOLICIES_MODULE_NAME, m.processProject)
allPolicies := m.getAllPolicies()
@@ -95,91 +83,8 @@ func (m *OrgPoliciesModule) Execute(ctx context.Context, logger internal.Logger)
m.writeOutput(ctx, logger)
}
func (m *OrgPoliciesModule) enumerateOrgAndFolderPolicies(logger internal.Logger) {
orgSvc := organizationsservice.New()
policySvc := orgpolicyservice.New()
// Discover organizations
orgs, err := orgSvc.SearchOrganizations()
if err != nil {
if globals.GCP_VERBOSITY >= globals.GCP_VERBOSE_ERRORS {
logger.InfoM("Could not enumerate organizations (may lack permissions)", globals.GCP_ORGPOLICIES_MODULE_NAME)
}
} else {
for _, org := range orgs {
orgID := strings.TrimPrefix(org.Name, "organizations/")
if globals.GCP_VERBOSITY >= globals.GCP_VERBOSE_ERRORS {
logger.InfoM(fmt.Sprintf("Enumerating org policies for organization: %s (%s)", org.DisplayName, orgID), globals.GCP_ORGPOLICIES_MODULE_NAME)
}
policies, err := policySvc.ListOrganizationPolicies(orgID, org.DisplayName)
if err != nil {
if globals.GCP_VERBOSITY >= globals.GCP_VERBOSE_ERRORS {
gcpinternal.HandleGCPError(err, logger, globals.GCP_ORGPOLICIES_MODULE_NAME,
fmt.Sprintf("Could not enumerate org policies for organization %s", orgID))
}
continue
}
m.mu.Lock()
m.OrgPolicies[orgID] = policies
m.initLootForScope(orgID)
for _, policy := range policies {
m.addPolicyToLoot(orgID, policy)
}
m.mu.Unlock()
if len(policies) > 0 {
logger.SuccessM(fmt.Sprintf("Found %d org-level policy(ies) for organization %s", len(policies), org.DisplayName), globals.GCP_ORGPOLICIES_MODULE_NAME)
}
}
}
// Discover folders
folders, err := orgSvc.SearchAllFolders()
if err != nil {
if globals.GCP_VERBOSITY >= globals.GCP_VERBOSE_ERRORS {
logger.InfoM("Could not enumerate folders (may lack permissions)", globals.GCP_ORGPOLICIES_MODULE_NAME)
}
} else {
for _, folder := range folders {
folderID := strings.TrimPrefix(folder.Name, "folders/")
if globals.GCP_VERBOSITY >= globals.GCP_VERBOSE_ERRORS {
logger.InfoM(fmt.Sprintf("Enumerating org policies for folder: %s (%s)", folder.DisplayName, folderID), globals.GCP_ORGPOLICIES_MODULE_NAME)
}
policies, err := policySvc.ListFolderPolicies(folderID, folder.DisplayName)
if err != nil {
if globals.GCP_VERBOSITY >= globals.GCP_VERBOSE_ERRORS {
gcpinternal.HandleGCPError(err, logger, globals.GCP_ORGPOLICIES_MODULE_NAME,
fmt.Sprintf("Could not enumerate org policies for folder %s", folderID))
}
continue
}
m.mu.Lock()
m.FolderPolicies[folderID] = policies
m.initLootForScope(folderID)
for _, policy := range policies {
m.addPolicyToLoot(folderID, policy)
}
m.mu.Unlock()
if len(policies) > 0 {
logger.SuccessM(fmt.Sprintf("Found %d folder-level policy(ies) for folder %s", len(policies), folder.DisplayName), globals.GCP_ORGPOLICIES_MODULE_NAME)
}
}
}
}
func (m *OrgPoliciesModule) getAllPolicies() []orgpolicyservice.OrgPolicyInfo {
var all []orgpolicyservice.OrgPolicyInfo
for _, policies := range m.OrgPolicies {
all = append(all, policies...)
}
for _, policies := range m.FolderPolicies {
all = append(all, policies...)
}
for _, policies := range m.ProjectPolicies {
all = append(all, policies...)
}
@@ -192,23 +97,24 @@ func (m *OrgPoliciesModule) processProject(ctx context.Context, projectID string
}
m.mu.Lock()
m.initLootForScope(projectID)
if m.LootMap[projectID] == nil {
m.LootMap[projectID] = make(map[string]*internal.LootFile)
m.LootMap[projectID]["orgpolicies-commands"] = &internal.LootFile{
Name: "orgpolicies-commands",
Contents: "# Organization Policy Commands\n# Generated by CloudFox\n# WARNING: Only use with proper authorization\n\n",
}
}
m.mu.Unlock()
svc := orgpolicyservice.New()
policies, err := svc.ListProjectPolicies(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_ORGPOLICIES_MODULE_NAME,
fmt.Sprintf("Could not enumerate org policies in project %s", projectID))
return
}
// Set ScopeName from project name map
for i := range policies {
policies[i].ScopeName = m.GetProjectName(projectID)
}
m.mu.Lock()
m.ProjectPolicies[projectID] = policies
for _, policy := range policies {
@@ -217,18 +123,8 @@ func (m *OrgPoliciesModule) processProject(ctx context.Context, projectID string
m.mu.Unlock()
}
func (m *OrgPoliciesModule) initLootForScope(scopeID string) {
if m.LootMap[scopeID] == nil {
m.LootMap[scopeID] = make(map[string]*internal.LootFile)
m.LootMap[scopeID]["orgpolicies-commands"] = &internal.LootFile{
Name: "orgpolicies-commands",
Contents: "# Organization Policy Commands\n# Generated by CloudFox\n# WARNING: Only use with proper authorization\n\n",
}
}
}
func (m *OrgPoliciesModule) addPolicyToLoot(scopeID string, policy orgpolicyservice.OrgPolicyInfo) {
lootFile := m.LootMap[scopeID]["orgpolicies-commands"]
func (m *OrgPoliciesModule) addPolicyToLoot(projectID string, policy orgpolicyservice.OrgPolicyInfo) {
lootFile := m.LootMap[projectID]["orgpolicies-commands"]
if lootFile == nil {
return
}
@@ -238,19 +134,13 @@ func (m *OrgPoliciesModule) addPolicyToLoot(scopeID string, policy orgpolicyserv
constraintName = strings.TrimPrefix(constraintName, "constraints/")
}
// Scope label for loot comments
scopeLabel := fmt.Sprintf("%s: %s", policy.ScopeType, policy.ScopeID)
if policy.ScopeName != "" {
scopeLabel = fmt.Sprintf("%s: %s (%s)", policy.ScopeType, policy.ScopeName, policy.ScopeID)
}
lootFile.Contents += fmt.Sprintf(
"# =============================================================================\n"+
"# CONSTRAINT: %s\n"+
"# =============================================================================\n"+
"# Scope: %s\n",
"# Project: %s\n",
policy.Constraint,
scopeLabel,
policy.ProjectID,
)
if policy.Description != "" {
@@ -272,56 +162,22 @@ func (m *OrgPoliciesModule) addPolicyToLoot(scopeID string, policy orgpolicyserv
lootFile.Contents += fmt.Sprintf("# Denied Values: %s\n", strings.Join(policy.DeniedValues, ", "))
}
// Build enumeration commands based on scope type
lootFile.Contents += "\n# === ENUMERATION COMMANDS ===\n\n"
switch policy.ScopeType {
case "organization":
lootFile.Contents += fmt.Sprintf(
lootFile.Contents += fmt.Sprintf(
"\n# === ENUMERATION COMMANDS ===\n\n"+
"# Describe this policy:\n"+
"gcloud org-policies describe %s --organization=%s\n\n"+
"# Get effective policy (includes inheritance):\n"+
"gcloud org-policies describe %s --organization=%s --effective\n\n"+
"# List all constraints for this organization:\n"+
"gcloud org-policies list --organization=%s\n\n",
constraintName, policy.ScopeID,
constraintName, policy.ScopeID,
policy.ScopeID,
)
case "folder":
lootFile.Contents += fmt.Sprintf(
"# Describe this policy:\n"+
"gcloud org-policies describe %s --folder=%s\n\n"+
"# Get effective policy (includes inheritance):\n"+
"gcloud org-policies describe %s --folder=%s --effective\n\n"+
"# List all constraints for this folder:\n"+
"gcloud org-policies list --folder=%s\n\n",
constraintName, policy.ScopeID,
constraintName, policy.ScopeID,
policy.ScopeID,
)
default: // project
lootFile.Contents += fmt.Sprintf(
"# Describe this policy:\n"+
"gcloud org-policies describe %s --project=%s\n\n"+
"# Get effective policy (includes inheritance):\n"+
"gcloud org-policies describe %s --project=%s --effective\n\n"+
"# List all constraints for this project:\n"+
"gcloud org-policies list --project=%s\n\n",
constraintName, policy.ScopeID,
constraintName, policy.ScopeID,
policy.ScopeID,
)
}
"gcloud org-policies describe %s --project=%s\n\n"+
"# Get effective policy (includes inheritance):\n"+
"gcloud org-policies describe %s --project=%s --effective\n\n"+
"# List all constraints for this project:\n"+
"gcloud org-policies list --project=%s\n\n",
constraintName, policy.ProjectID,
constraintName, policy.ProjectID,
policy.ProjectID,
)
// Exploit/bypass commands based on specific constraint types
lootFile.Contents += "# === EXPLOIT / BYPASS COMMANDS ===\n\n"
// For exploit commands, use project ID if available, otherwise use scope ID
targetProject := policy.ProjectID
if targetProject == "" {
targetProject = "<PROJECT_ID>"
}
switch constraintName {
case "iam.allowedPolicyMemberDomains":
if policy.AllowAll {
@@ -329,7 +185,7 @@ func (m *OrgPoliciesModule) addPolicyToLoot(scopeID string, policy orgpolicyserv
lootFile.Contents += fmt.Sprintf(
"# Grant access to external identity:\n"+
"gcloud projects add-iam-policy-binding %s --member=user:[email protected] --role=roles/viewer\n\n",
targetProject,
policy.ProjectID,
)
} else if !policy.Enforced {
lootFile.Contents += "# [FINDING] Domain restriction is NOT ENFORCED\n\n"
@@ -340,7 +196,7 @@ func (m *OrgPoliciesModule) addPolicyToLoot(scopeID string, policy orgpolicyserv
lootFile.Contents += "# [FINDING] SA key creation is NOT restricted - create keys for persistence:\n"
lootFile.Contents += fmt.Sprintf(
"gcloud iam service-accounts keys create /tmp/sa-key.json --iam-account=SA_EMAIL@%s.iam.gserviceaccount.com\n\n",
targetProject,
policy.ProjectID,
)
} else {
lootFile.Contents += "# SA key creation is restricted - try alternative persistence methods:\n" +
@@ -353,7 +209,7 @@ func (m *OrgPoliciesModule) addPolicyToLoot(scopeID string, policy orgpolicyserv
lootFile.Contents += "# [FINDING] SA creation is NOT restricted - create backdoor service accounts:\n"
lootFile.Contents += fmt.Sprintf(
"gcloud iam service-accounts create cloudfox-backdoor --display-name='System Service' --project=%s\n\n",
targetProject,
policy.ProjectID,
)
}
@@ -369,7 +225,7 @@ func (m *OrgPoliciesModule) addPolicyToLoot(scopeID string, policy orgpolicyserv
lootFile.Contents += fmt.Sprintf(
"# Add SSH key to project metadata:\n"+
"gcloud compute project-info add-metadata --metadata=ssh-keys=\"attacker:ssh-rsa AAAA...\" --project=%s\n\n",
targetProject,
policy.ProjectID,
)
}
@@ -427,9 +283,8 @@ func (m *OrgPoliciesModule) writeOutput(ctx context.Context, logger internal.Log
func (m *OrgPoliciesModule) getHeader() []string {
return []string{
"Scope Type",
"Scope ID",
"Scope Name",
"Project Name",
"Project ID",
"Constraint",
"Description",
"Enforced",
@@ -459,15 +314,9 @@ func (m *OrgPoliciesModule) policiesToTableBody(policies []orgpolicyservice.OrgP
deniedValues = strings.Join(policy.DeniedValues, ", ")
}
scopeName := policy.ScopeName
if scopeName == "" {
scopeName = "-"
}
body = append(body, []string{
policy.ScopeType,
policy.ScopeID,
scopeName,
m.GetProjectName(policy.ProjectID),
policy.ProjectID,
policy.Constraint,
description,
shared.BoolToYesNo(policy.Enforced),
@@ -481,9 +330,9 @@ func (m *OrgPoliciesModule) policiesToTableBody(policies []orgpolicyservice.OrgP
return body
}
func (m *OrgPoliciesModule) buildTablesForScope(scopeID string, policies []orgpolicyservice.OrgPolicyInfo) []internal.TableFile {
func (m *OrgPoliciesModule) buildTablesForProject(projectID string) []internal.TableFile {
var tableFiles []internal.TableFile
if len(policies) > 0 {
if policies, ok := m.ProjectPolicies[projectID]; ok && len(policies) > 0 {
tableFiles = append(tableFiles, internal.TableFile{
Name: "orgpolicies",
Header: m.getHeader(),
@@ -493,43 +342,24 @@ func (m *OrgPoliciesModule) buildTablesForScope(scopeID string, policies []orgpo
return tableFiles
}
func (m *OrgPoliciesModule) collectLootForScope(scopeID string) []internal.LootFile {
var lootFiles []internal.LootFile
if scopeLoot, ok := m.LootMap[scopeID]; ok {
for _, loot := range scopeLoot {
if loot != nil && loot.Contents != "" && !strings.HasSuffix(loot.Contents, "# WARNING: Only use with proper authorization\n\n") {
lootFiles = append(lootFiles, *loot)
}
}
}
return lootFiles
}
func (m *OrgPoliciesModule) writeHierarchicalOutput(ctx context.Context, logger internal.Logger) {
outputData := internal.HierarchicalOutputData{
OrgLevelData: make(map[string]internal.CloudfoxOutput),
FolderLevelData: make(map[string]internal.CloudfoxOutput),
ProjectLevelData: make(map[string]internal.CloudfoxOutput),
}
// Org-level data
for orgID, policies := range m.OrgPolicies {
tableFiles := m.buildTablesForScope(orgID, policies)
lootFiles := m.collectLootForScope(orgID)
outputData.OrgLevelData[orgID] = OrgPoliciesOutput{Table: tableFiles, Loot: lootFiles}
}
for projectID := range m.ProjectPolicies {
tableFiles := m.buildTablesForProject(projectID)
// Folder-level data
for folderID, policies := range m.FolderPolicies {
tableFiles := m.buildTablesForScope(folderID, policies)
lootFiles := m.collectLootForScope(folderID)
outputData.FolderLevelData[folderID] = OrgPoliciesOutput{Table: tableFiles, Loot: lootFiles}
}
var lootFiles []internal.LootFile
if projectLoot, ok := m.LootMap[projectID]; ok {
for _, loot := range projectLoot {
if loot != nil && loot.Contents != "" && !strings.HasSuffix(loot.Contents, "# WARNING: Only use with proper authorization\n\n") {
lootFiles = append(lootFiles, *loot)
}
}
}
// Project-level data
for projectID, policies := range m.ProjectPolicies {
tableFiles := m.buildTablesForScope(projectID, policies)
lootFiles := m.collectLootForScope(projectID)
outputData.ProjectLevelData[projectID] = OrgPoliciesOutput{Table: tableFiles, Loot: lootFiles}
}
@@ -554,8 +384,8 @@ func (m *OrgPoliciesModule) writeFlatOutput(ctx context.Context, logger internal
}
var lootFiles []internal.LootFile
for _, scopeLoot := range m.LootMap {
for _, loot := range scopeLoot {
for _, projectLoot := range m.LootMap {
for _, loot := range projectLoot {
if loot != nil && loot.Contents != "" && !strings.HasSuffix(loot.Contents, "# WARNING: Only use with proper authorization\n\n") {
lootFiles = append(lootFiles, *loot)
}
+4 -149
View File
@@ -9,7 +9,6 @@ import (
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
orgsservice "github.com/BishopFox/cloudfox/gcp/services/organizationsService"
resourceiamservice "github.com/BishopFox/cloudfox/gcp/services/resourceIAMService"
"github.com/BishopFox/cloudfox/globals"
"github.com/BishopFox/cloudfox/internal"
gcpinternal "github.com/BishopFox/cloudfox/internal/gcp"
@@ -327,7 +326,7 @@ func (m *PermissionsModule) processProject(ctx context.Context, projectID string
iamService := IAMService.New()
entityPerms, groupInfos, err := iamService.GetAllEntityPermissionsWithGroupExpansion(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_PERMISSIONS_MODULE_NAME,
fmt.Sprintf("Could not enumerate permissions in project %s", projectID))
return
@@ -387,138 +386,6 @@ func (m *PermissionsModule) processProject(ctx context.Context, projectID string
}
}
// Enumerate SA-level IAM bindings (resource-level permissions on service accounts)
saList, saErr := iamService.ServiceAccountsBasic(projectID)
if saErr == nil {
saCtx := context.Background()
saBindingCount := 0
for _, sa := range saList {
saBindings, err := iamService.GetServiceAccountIAMBindings(saCtx, sa.Email, projectID)
if err != nil {
continue
}
for _, binding := range saBindings {
// Get permissions for this role
permissions, err := iamService.GetRolePermissions(saCtx, binding.Role)
if err != nil {
continue
}
for _, member := range binding.Members {
memberType := IAMService.GetMemberType(member)
memberEmail := extractMemberEmail(member)
for _, perm := range permissions {
isHighPriv := isHighPrivilegePermission(perm)
exploded := ExplodedPermission{
Entity: member,
EntityType: memberType,
EntityEmail: memberEmail,
Permission: perm,
Role: binding.Role,
RoleType: IAMService.GetRoleType(binding.Role),
ResourceScope: fmt.Sprintf("serviceAccount/%s", sa.Email),
ResourceScopeType: "serviceAccount",
ResourceScopeID: sa.Email,
ResourceScopeName: sa.Email,
IsInherited: false,
HasCondition: binding.HasCondition,
EffectiveProject: projectID,
ProjectName: m.GetProjectName(projectID),
IsHighPrivilege: isHighPriv,
}
if binding.ConditionInfo != nil {
exploded.ConditionTitle = binding.ConditionInfo.Title
exploded.Condition = binding.ConditionInfo.Title
}
// Detect cross-project access
if memberType == "ServiceAccount" {
saProject := extractProjectFromPrincipal(memberEmail, m.OrgCache)
if saProject != "" && saProject != projectID {
exploded.IsCrossProject = true
exploded.SourceProject = saProject
}
}
projectPerms = append(projectPerms, exploded)
saBindingCount++
}
}
}
}
if saBindingCount > 0 && globals.GCP_VERBOSITY >= globals.GCP_VERBOSE_ERRORS {
logger.InfoM(fmt.Sprintf("Enumerated %d SA-level permission entries across %d service account(s)", saBindingCount, len(saList)), globals.GCP_PERMISSIONS_MODULE_NAME)
}
}
// Enumerate resource-level IAM bindings (buckets, datasets, secrets, KMS, functions, Cloud Run, instances)
resourceIAMSvc := resourceiamservice.New()
resourceBindings, resourceErr := resourceIAMSvc.GetAllResourceIAM(ctx, projectID)
if resourceErr == nil && len(resourceBindings) > 0 {
resCtx := context.Background()
resourcePermCount := 0
for _, rb := range resourceBindings {
// Skip serviceAccount type here since we already handled it above
if rb.ResourceType == "serviceAccount" {
continue
}
// Get permissions for this role
permissions, err := iamService.GetRolePermissions(resCtx, rb.Role)
if err != nil {
continue
}
memberType := IAMService.GetMemberType(rb.Member)
memberEmail := extractMemberEmail(rb.Member)
for _, perm := range permissions {
isHighPriv := isHighPrivilegePermission(perm)
exploded := ExplodedPermission{
Entity: rb.Member,
EntityType: memberType,
EntityEmail: memberEmail,
Permission: perm,
Role: rb.Role,
RoleType: IAMService.GetRoleType(rb.Role),
ResourceScope: fmt.Sprintf("%s/%s", rb.ResourceType, rb.ResourceID),
ResourceScopeType: rb.ResourceType,
ResourceScopeID: rb.ResourceID,
ResourceScopeName: rb.ResourceName,
IsInherited: false,
HasCondition: rb.HasCondition,
EffectiveProject: projectID,
ProjectName: m.GetProjectName(projectID),
IsHighPrivilege: isHighPriv,
}
if rb.HasCondition && rb.ConditionTitle != "" {
exploded.ConditionTitle = rb.ConditionTitle
exploded.Condition = rb.ConditionTitle
}
// Detect cross-project access
if memberType == "ServiceAccount" {
saProject := extractProjectFromPrincipal(memberEmail, m.OrgCache)
if saProject != "" && saProject != projectID {
exploded.IsCrossProject = true
exploded.SourceProject = saProject
}
}
projectPerms = append(projectPerms, exploded)
resourcePermCount++
}
}
if resourcePermCount > 0 && globals.GCP_VERBOSITY >= globals.GCP_VERBOSE_ERRORS {
logger.InfoM(fmt.Sprintf("Enumerated %d resource-level permission entries in project %s", resourcePermCount, projectID), globals.GCP_PERMISSIONS_MODULE_NAME)
}
}
m.mu.Lock()
// Store per-project permissions
m.ProjectPerms[projectID] = append(m.ProjectPerms[projectID], projectPerms...)
@@ -568,23 +435,11 @@ func (m *PermissionsModule) getScopeName(scopeType, scopeID string) string {
return scopeID
case "folder":
return scopeID // Could be enhanced to lookup folder names
case "serviceAccount", "bucket", "dataset", "topic", "subscription",
"secret", "cryptoKey", "function", "cloudrun", "instance":
return scopeID // Resource ID is the scope name
default:
return scopeID
}
}
// extractMemberEmail strips the type prefix from a member string (e.g., "user:[email protected]" -> "[email protected]")
func extractMemberEmail(member string) string {
parts := strings.SplitN(member, ":", 2)
if len(parts) == 2 {
return parts[1]
}
return member
}
func parseConditionTitle(condition string) string {
// Try to extract title from condition if it looks like a struct
if strings.Contains(condition, "title:") {
@@ -1264,7 +1119,7 @@ func (m *PermissionsModule) writeHierarchicalOutput(ctx context.Context, logger
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_PERMISSIONS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -1352,7 +1207,7 @@ func (m *PermissionsModule) writeHierarchicalOutputTee(ctx context.Context, logg
err := internal.HandleHierarchicalOutputTee(config)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing tee streaming output: %v", err), globals.GCP_PERMISSIONS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -1425,7 +1280,7 @@ func (m *PermissionsModule) writeFlatOutput(ctx context.Context, logger internal
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_PERMISSIONS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+4 -4
View File
@@ -167,7 +167,7 @@ func (m *PrivateServiceConnectModule) processProject(ctx context.Context, projec
// Get PSC endpoints
pscEndpoints, err := svc.GetPrivateServiceConnectEndpoints(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, "private-service-connect",
fmt.Sprintf("Could not get PSC endpoints in project %s", projectID))
}
@@ -175,7 +175,7 @@ func (m *PrivateServiceConnectModule) processProject(ctx context.Context, projec
// Get private connections
privateConns, err := svc.GetPrivateConnections(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, "private-service-connect",
fmt.Sprintf("Could not get private connections in project %s", projectID))
}
@@ -183,7 +183,7 @@ func (m *PrivateServiceConnectModule) processProject(ctx context.Context, projec
// Get service attachments
attachments, err := svc.GetServiceAttachments(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, "private-service-connect",
fmt.Sprintf("Could not get service attachments in project %s", projectID))
}
@@ -553,6 +553,6 @@ func (m *PrivateServiceConnectModule) writeFlatOutput(ctx context.Context, logge
"project", m.ProjectIDs, scopeNames, m.Account, output)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), "private-service-connect")
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+2 -2
View File
@@ -1173,7 +1173,7 @@ func (m *PublicAccessModule) writeHierarchicalOutput(ctx context.Context, logger
err := internal.HandleHierarchicalOutputSmart("gcp", m.Format, m.Verbosity, m.WrapTable, pathBuilder, outputData)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_PUBLICACCESS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -1259,7 +1259,7 @@ func (m *PublicAccessModule) writeFlatOutput(ctx context.Context, logger interna
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_PUBLICACCESS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+4 -45
View File
@@ -6,7 +6,6 @@ import (
"strings"
"sync"
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
PubSubService "github.com/BishopFox/cloudfox/gcp/services/pubsubService"
"github.com/BishopFox/cloudfox/gcp/shared"
"github.com/BishopFox/cloudfox/globals"
@@ -171,7 +170,7 @@ func (m *PubSubModule) processProject(ctx context.Context, projectID string, log
// Get topics
topicsResult, err := ps.Topics(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_PUBSUB_MODULE_NAME,
fmt.Sprintf("Could not enumerate Pub/Sub topics in project %s", projectID))
} else {
@@ -181,47 +180,13 @@ func (m *PubSubModule) processProject(ctx context.Context, projectID string, log
// Get subscriptions
subsResult, err := ps.Subscriptions(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_PUBSUB_MODULE_NAME,
fmt.Sprintf("Could not enumerate Pub/Sub subscriptions in project %s", projectID))
} else {
subs = subsResult
}
// Inject inherited project-level IAM bindings
iamSvc := IAMService.New()
projectPolicies, projErr := iamSvc.Policies(projectID, "project")
if projErr == nil {
for i := range topics {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("topic", pb.Role) {
continue
}
for _, member := range pb.Members {
topics[i].IAMBindings = append(topics[i].IAMBindings, PubSubService.IAMBinding{
Role: pb.Role,
Member: member,
Source: "Project",
})
}
}
}
for i := range subs {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("subscription", pb.Role) {
continue
}
for _, member := range pb.Members {
subs[i].IAMBindings = append(subs[i].IAMBindings, PubSubService.IAMBinding{
Role: pb.Role,
Member: member,
Source: "Project",
})
}
}
}
}
// Thread-safe store per-project
m.mu.Lock()
m.ProjectTopics[projectID] = topics
@@ -650,7 +615,6 @@ func (m *PubSubModule) getTopicsHeader() []string {
"Public Publish",
"IAM Binding Role",
"IAM Binding Principal",
"Binding Source",
}
}
@@ -669,7 +633,6 @@ func (m *PubSubModule) getSubsHeader() []string {
"Public Subscribe",
"IAM Binding Role",
"IAM Binding Principal",
"Binding Source",
}
}
@@ -725,7 +688,6 @@ func (m *PubSubModule) topicsToTableBody(topics []PubSubService.TopicInfo) [][]s
publicPublish,
binding.Role,
binding.Member,
shared.BindingSource(binding.Source),
})
}
} else {
@@ -739,7 +701,6 @@ func (m *PubSubModule) topicsToTableBody(topics []PubSubService.TopicInfo) [][]s
publicPublish,
"-",
"-",
"-",
})
}
}
@@ -821,7 +782,6 @@ func (m *PubSubModule) subsToTableBody(subs []PubSubService.SubscriptionInfo) []
publicSubscribe,
binding.Role,
binding.Member,
shared.BindingSource(binding.Source),
})
}
} else {
@@ -839,7 +799,6 @@ func (m *PubSubModule) subsToTableBody(subs []PubSubService.SubscriptionInfo) []
publicSubscribe,
"-",
"-",
"-",
})
}
}
@@ -907,7 +866,7 @@ func (m *PubSubModule) writeHierarchicalOutput(ctx context.Context, logger inter
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_PUBSUB_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -956,7 +915,7 @@ func (m *PubSubModule) writeFlatOutput(ctx context.Context, logger internal.Logg
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_PUBSUB_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+3 -50
View File
@@ -30,8 +30,6 @@ Supported Resource Types:
- Cloud KMS keys
- Cloud Functions
- Cloud Run services
- Service Accounts
- Compute Instances
Key Findings:
- Public access (allUsers/allAuthenticatedUsers)
@@ -147,7 +145,7 @@ func (m *ResourceIAMModule) processProject(ctx context.Context, projectID string
svc := resourceiamservice.New()
bindings, err := svc.GetAllResourceIAM(ctx, projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_RESOURCEIAM_MODULE_NAME,
fmt.Sprintf("Could not enumerate resource IAM in project %s", projectID))
return
@@ -277,28 +275,6 @@ func (m *ResourceIAMModule) addResourceToLoot(b resourceiamservice.ResourceIAMBi
b.ResourceID, b.ProjectID,
b.ResourceID, b.ProjectID,
)
case "serviceAccount":
lootFile.Contents += fmt.Sprintf(
"# Service Account: %s (Member: %s, Role: %s)\n"+
"gcloud iam service-accounts describe %s --project=%s\n"+
"gcloud iam service-accounts get-iam-policy %s --project=%s\n"+
"gcloud iam service-accounts keys list --iam-account=%s --project=%s\n\n",
b.ResourceID, b.Member, b.Role,
b.ResourceID, b.ProjectID,
b.ResourceID, b.ProjectID,
b.ResourceID, b.ProjectID,
)
case "instance":
// Extract zone from ResourceName (projects/{proj}/zones/{zone}/instances/{name})
zone := extractZoneFromResourceName(b.ResourceName)
lootFile.Contents += fmt.Sprintf(
"# Compute Instance: %s (Member: %s, Role: %s)\n"+
"gcloud compute instances describe %s --zone=%s --project=%s\n"+
"gcloud compute instances get-iam-policy %s --zone=%s --project=%s\n\n",
b.ResourceID, b.Member, b.Role,
b.ResourceID, zone, b.ProjectID,
b.ResourceID, zone, b.ProjectID,
)
}
}
@@ -330,32 +306,9 @@ func (m *ResourceIAMModule) addPublicResourceToLoot(b resourceiamservice.Resourc
"# Cloud Run service may be publicly accessible\ngcloud run services describe %s --project=%s\n\n",
b.ResourceID, b.ProjectID,
)
case "serviceAccount":
lootFile.Contents += fmt.Sprintf(
"# Service account has public IAM binding\ngcloud iam service-accounts describe %s --project=%s\n\n",
b.ResourceID, b.ProjectID,
)
case "instance":
zone := extractZoneFromResourceName(b.ResourceName)
lootFile.Contents += fmt.Sprintf(
"# Compute instance has public IAM binding\ngcloud compute instances describe %s --zone=%s --project=%s\n\n",
b.ResourceID, zone, b.ProjectID,
)
}
}
// extractZoneFromResourceName extracts the zone from a resource name like
// "projects/{proj}/zones/{zone}/instances/{name}"
func extractZoneFromResourceName(resourceName string) string {
parts := strings.Split(resourceName, "/")
for i, part := range parts {
if part == "zones" && i+1 < len(parts) {
return parts[i+1]
}
}
return ""
}
// resourceKey creates a unique key for a resource to group bindings
func resourceKey(b resourceiamservice.ResourceIAMBinding) string {
return fmt.Sprintf("%s|%s|%s", b.ProjectID, b.ResourceType, b.ResourceName)
@@ -509,7 +462,7 @@ func (m *ResourceIAMModule) writeHierarchicalOutput(ctx context.Context, logger
err := internal.HandleHierarchicalOutputSmart("gcp", m.Format, m.Verbosity, m.WrapTable, pathBuilder, outputData)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_RESOURCEIAM_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -644,6 +597,6 @@ func (m *ResourceIAMModule) writeFlatOutput(ctx context.Context, logger internal
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_RESOURCEIAM_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+3 -3
View File
@@ -142,7 +142,7 @@ func (m *SchedulerModule) processProject(ctx context.Context, projectID string,
jobs, err := ss.Jobs(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_SCHEDULER_MODULE_NAME,
fmt.Sprintf("Could not enumerate Scheduler jobs in project %s", projectID))
return
@@ -346,7 +346,7 @@ func (m *SchedulerModule) writeHierarchicalOutput(ctx context.Context, logger in
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_SCHEDULER_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -396,7 +396,7 @@ func (m *SchedulerModule) writeFlatOutput(ctx context.Context, logger internal.L
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_SCHEDULER_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+5 -32
View File
@@ -8,8 +8,6 @@ import (
secretmanager "cloud.google.com/go/secretmanager/apiv1"
SecretsService "github.com/BishopFox/cloudfox/gcp/services/secretsService"
IAMService "github.com/BishopFox/cloudfox/gcp/services/iamService"
"google.golang.org/api/option"
"github.com/BishopFox/cloudfox/gcp/shared"
gcpinternal "github.com/BishopFox/cloudfox/internal/gcp"
"github.com/BishopFox/cloudfox/globals"
@@ -80,12 +78,8 @@ func runGCPSecretsCommand(cmd *cobra.Command, args []string) {
return // Error already logged
}
// Create Secret Manager client (uses impersonated credentials if --impersonate-sa is set)
var smOpts []option.ClientOption
if s := gcpinternal.GetDefaultSession(); s != nil {
smOpts = append(smOpts, s.GetClientOption())
}
client, err := secretmanager.NewClient(cmdCtx.Ctx, smOpts...)
// Create Secret Manager client
client, err := secretmanager.NewClient(cmdCtx.Ctx)
if err != nil {
cmdCtx.Logger.ErrorM(fmt.Sprintf("Failed to create Secret Manager client: %v", err), globals.GCP_SECRETS_MODULE_NAME)
return
@@ -151,30 +145,12 @@ func (m *SecretsModule) processProject(ctx context.Context, projectID string, lo
ss := SecretsService.New(m.client)
secrets, err := ss.Secrets(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_SECRETS_MODULE_NAME,
fmt.Sprintf("Could not enumerate secrets in project %s", projectID))
return
}
// Inject inherited project-level IAM bindings into each secret
iamSvc := IAMService.New()
projectPolicies, projErr := iamSvc.Policies(projectID, "project")
if projErr == nil {
for i := range secrets {
for _, pb := range projectPolicies {
if !shared.IsInheritedRole("secret", pb.Role) {
continue
}
secrets[i].IAMBindings = append(secrets[i].IAMBindings, SecretsService.IAMBinding{
Role: pb.Role,
Members: pb.Members,
Source: "Project",
})
}
}
}
// Thread-safe store per-project
m.mu.Lock()
m.ProjectSecrets[projectID] = secrets
@@ -350,7 +326,7 @@ func (m *SecretsModule) writeHierarchicalOutput(ctx context.Context, logger inte
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_SECRETS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -402,7 +378,7 @@ func (m *SecretsModule) writeFlatOutput(ctx context.Context, logger internal.Log
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_SECRETS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -423,7 +399,6 @@ func (m *SecretsModule) getTableHeader() []string {
"IAM Binding Role",
"Principal Type",
"IAM Binding Principal",
"Binding Source",
"Principal Attack Paths",
}
}
@@ -497,7 +472,6 @@ func (m *SecretsModule) secretsToTableBody(secrets []SecretsService.SecretInfo)
binding.Role,
memberType,
member,
shared.BindingSource(binding.Source),
attackPaths,
})
}
@@ -520,7 +494,6 @@ func (m *SecretsModule) secretsToTableBody(secrets []SecretsService.SecretInfo)
"-",
"-",
"-",
"-",
})
}
}
+3 -3
View File
@@ -237,7 +237,7 @@ func (m *SecurityCenterModule) processProject(ctx context.Context, projectID str
break
}
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
parsedErr := gcpinternal.ParseGCPError(err, "securitycenter.googleapis.com")
gcpinternal.HandleGCPError(parsedErr, logger, GCP_SECURITYCENTER_MODULE_NAME,
fmt.Sprintf("Project %s", projectID))
@@ -544,7 +544,7 @@ func (m *SecurityCenterModule) writeHierarchicalOutput(ctx context.Context, logg
err := internal.HandleHierarchicalOutputSmart("gcp", m.Format, m.Verbosity, m.WrapTable, pathBuilder, outputData)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), GCP_SECURITYCENTER_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -680,6 +680,6 @@ func (m *SecurityCenterModule) writeFlatOutput(ctx context.Context, logger inter
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), GCP_SECURITYCENTER_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+75 -120
View File
@@ -36,41 +36,6 @@ Column Descriptions:
Run: runGCPServiceAccountsCommand,
}
// SAIAMBinding represents a raw IAM binding on a service account (role + member)
type SAIAMBinding struct {
Role string
Member string
Source string // "SA" (direct on SA resource) or "Project" (inherited from project IAM)
}
// saAccessRoles are project-level roles that implicitly grant access to all
// service accounts in the project. When a principal holds one of these at the
// project level, they can interact with every SA in that project.
var saAccessRoles = map[string]bool{
"roles/owner": true,
"roles/editor": true,
"roles/iam.serviceAccountAdmin": true,
"roles/iam.serviceAccountKeyAdmin": true,
"roles/iam.serviceAccountTokenCreator": true,
"roles/iam.serviceAccountUser": true,
"roles/iam.workloadIdentityUser": true,
"roles/iam.serviceAccountOpenIdTokenCreator": true,
}
// saRelevantPermissions are individual permissions that grant meaningful access
// to service accounts. Custom roles containing any of these should be treated
// as SA-access roles for inherited binding purposes.
var saRelevantPermissions = map[string]bool{
"iam.serviceAccounts.getAccessToken": true,
"iam.serviceAccountKeys.create": true,
"iam.serviceAccounts.signBlob": true,
"iam.serviceAccounts.signJwt": true,
"iam.serviceAccounts.implicitDelegation": true,
"iam.serviceAccounts.actAs": true,
"iam.serviceAccounts.setIamPolicy": true,
"iam.serviceAccounts.getOpenIdToken": true,
}
// ServiceAccountAnalysis extends ServiceAccountInfo with security analysis
type ServiceAccountAnalysis struct {
IAMService.ServiceAccountInfo
@@ -81,8 +46,6 @@ type ServiceAccountAnalysis struct {
HasOldKeys bool // Keys older than 90 days
// Pentest: Impersonation analysis
ImpersonationInfo *IAMService.SAImpersonationInfo
// Raw IAM bindings on this service account (actual roles, not friendly names)
RawIAMBindings []SAIAMBinding
}
// ------------------------------
@@ -201,7 +164,7 @@ func (m *ServiceAccountsModule) processProject(ctx context.Context, projectID st
// Fallback to basic enumeration if impersonation analysis fails
serviceAccounts, err = iamService.ServiceAccounts(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_SERVICEACCOUNTS_MODULE_NAME,
fmt.Sprintf("Could not enumerate service accounts in project %s", projectID))
return
@@ -227,70 +190,6 @@ func (m *ServiceAccountsModule) processProject(ctx context.Context, projectID st
// Silently skip if we can't get roles - user may not have IAM permissions
}
// Get raw SA-level IAM bindings for each service account (direct bindings)
saIAMBindingsMap := make(map[string][]SAIAMBinding)
bindingCtx := context.Background()
for _, sa := range serviceAccounts {
rawBindings, err := iamService.GetServiceAccountIAMBindings(bindingCtx, sa.Email, projectID)
if err == nil {
for _, pb := range rawBindings {
for _, member := range pb.Members {
saIAMBindingsMap[sa.Email] = append(saIAMBindingsMap[sa.Email], SAIAMBinding{
Role: pb.Role,
Member: member,
Source: "SA",
})
}
}
}
}
// Get project-level IAM bindings that grant implicit access to all SAs.
// These are inherited, not set directly on the SA resource.
projectBindings, err := iamService.Policies(projectID, "project")
if err == nil {
// Cache for custom role resolution so we only resolve each role once
resolvedRoles := make(map[string]bool) // role -> hasSAPermissions
roleCtx := context.Background()
for _, pb := range projectBindings {
include := saAccessRoles[pb.Role]
// For roles not in the hardcoded list, resolve permissions to check
// for SA-relevant permissions (catches custom roles like privesc_02_createSAKey)
if !include {
if cached, ok := resolvedRoles[pb.Role]; ok {
include = cached
} else {
perms, permErr := iamService.GetRolePermissions(roleCtx, pb.Role)
if permErr == nil {
for _, p := range perms {
if saRelevantPermissions[p] {
include = true
break
}
}
}
resolvedRoles[pb.Role] = include
}
}
if !include {
continue
}
for _, member := range pb.Members {
// Add this inherited binding to every SA in the project
for _, sa := range serviceAccounts {
saIAMBindingsMap[sa.Email] = append(saIAMBindingsMap[sa.Email], SAIAMBinding{
Role: pb.Role,
Member: member,
Source: "Project",
})
}
}
}
}
// Analyze each service account
var analyzedSAs []ServiceAccountAnalysis
for _, sa := range serviceAccounts {
@@ -303,10 +202,6 @@ func (m *ServiceAccountsModule) processProject(ctx context.Context, projectID st
if roles, ok := saRoles[sa.Email]; ok {
analyzed.Roles = roles
}
// Attach raw IAM bindings
if bindings, ok := saIAMBindingsMap[sa.Email]; ok {
analyzed.RawIAMBindings = bindings
}
analyzedSAs = append(analyzedSAs, analyzed)
}
@@ -586,7 +481,6 @@ func (m *ServiceAccountsModule) getTableHeader() []string {
// Impersonation
"IAM Binding Role",
"IAM Binding Principal",
"Binding Source",
}
}
@@ -647,24 +541,85 @@ func (m *ServiceAccountsModule) serviceAccountsToTableBody(serviceAccounts []Ser
}
}
// Format roles for display (full role names)
rolesDisplay := "-"
if len(sa.Roles) > 0 {
rolesDisplay = strings.Join(sa.Roles, ", ")
}
// Format roles for display
rolesDisplay := IAMService.FormatRolesShort(sa.Roles)
// Build IAM binding rows from raw bindings (actual roles, not friendly names)
// Build IAM bindings from impersonation info
// Row order: Identity (Project, Email, Display Name, Disabled, Default SA),
// Keys (User Managed Keys, Google Managed Keys, Oldest Key Age),
// Permissions (DWD, Roles, SA Attack Paths),
// Impersonation (IAM Binding Role, IAM Binding Principal)
hasBindings := false
if len(sa.RawIAMBindings) > 0 {
for _, binding := range sa.RawIAMBindings {
email := extractEmailFromMember(binding.Member)
if sa.ImpersonationInfo != nil {
for _, member := range sa.ImpersonationInfo.TokenCreators {
email := extractEmailFromMember(member)
if email != sa.Email {
hasBindings = true
body = append(body, []string{
m.GetProjectName(sa.ProjectID), sa.Email, sa.DisplayName, disabled, defaultSA,
userKeys, googleKeys, oldestKeyAge,
dwd, rolesDisplay, attackPaths,
binding.Role, binding.Member, binding.Source,
"TokenCreator", member,
})
}
}
for _, member := range sa.ImpersonationInfo.KeyCreators {
email := extractEmailFromMember(member)
if email != sa.Email {
hasBindings = true
body = append(body, []string{
m.GetProjectName(sa.ProjectID), sa.Email, sa.DisplayName, disabled, defaultSA,
userKeys, googleKeys, oldestKeyAge,
dwd, rolesDisplay, attackPaths,
"KeyAdmin", member,
})
}
}
for _, member := range sa.ImpersonationInfo.ActAsUsers {
email := extractEmailFromMember(member)
if email != sa.Email {
hasBindings = true
body = append(body, []string{
m.GetProjectName(sa.ProjectID), sa.Email, sa.DisplayName, disabled, defaultSA,
userKeys, googleKeys, oldestKeyAge,
dwd, rolesDisplay, attackPaths,
"ActAs", member,
})
}
}
for _, member := range sa.ImpersonationInfo.SAAdmins {
email := extractEmailFromMember(member)
if email != sa.Email {
hasBindings = true
body = append(body, []string{
m.GetProjectName(sa.ProjectID), sa.Email, sa.DisplayName, disabled, defaultSA,
userKeys, googleKeys, oldestKeyAge,
dwd, rolesDisplay, attackPaths,
"SAAdmin", member,
})
}
}
for _, member := range sa.ImpersonationInfo.SignBlobUsers {
email := extractEmailFromMember(member)
if email != sa.Email {
hasBindings = true
body = append(body, []string{
m.GetProjectName(sa.ProjectID), sa.Email, sa.DisplayName, disabled, defaultSA,
userKeys, googleKeys, oldestKeyAge,
dwd, rolesDisplay, attackPaths,
"SignBlob", member,
})
}
}
for _, member := range sa.ImpersonationInfo.SignJwtUsers {
email := extractEmailFromMember(member)
if email != sa.Email {
hasBindings = true
body = append(body, []string{
m.GetProjectName(sa.ProjectID), sa.Email, sa.DisplayName, disabled, defaultSA,
userKeys, googleKeys, oldestKeyAge,
dwd, rolesDisplay, attackPaths,
"SignJwt", member,
})
}
}
@@ -675,7 +630,7 @@ func (m *ServiceAccountsModule) serviceAccountsToTableBody(serviceAccounts []Ser
m.GetProjectName(sa.ProjectID), sa.Email, sa.DisplayName, disabled, defaultSA,
userKeys, googleKeys, oldestKeyAge,
dwd, rolesDisplay, attackPaths,
"-", "-", "-",
"-", "-",
})
}
}
@@ -722,7 +677,7 @@ func (m *ServiceAccountsModule) writeHierarchicalOutput(ctx context.Context, log
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_SERVICEACCOUNTS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -768,7 +723,7 @@ func (m *ServiceAccountsModule) writeFlatOutput(ctx context.Context, logger inte
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_SERVICEACCOUNTS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+3 -3
View File
@@ -140,7 +140,7 @@ func (m *ServiceAgentsModule) processProject(ctx context.Context, projectID stri
svc := serviceagentsservice.New()
agents, err := svc.GetServiceAgents(projectID, m.OrgCache)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_SERVICEAGENTS_MODULE_NAME,
fmt.Sprintf("Could not get service agents in project %s", projectID))
return
@@ -292,7 +292,7 @@ func (m *ServiceAgentsModule) writeHierarchicalOutput(ctx context.Context, logge
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_SERVICEAGENTS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -345,7 +345,7 @@ func (m *ServiceAgentsModule) writeFlatOutput(ctx context.Context, logger intern
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_SERVICEAGENTS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+3 -3
View File
@@ -118,7 +118,7 @@ func (m *SourceReposModule) processProject(ctx context.Context, projectID string
svc := sourcereposservice.New()
repos, err := svc.ListRepos(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_SOURCEREPOS_MODULE_NAME,
fmt.Sprintf("Could not list repos in project %s", projectID))
return
@@ -263,7 +263,7 @@ func (m *SourceReposModule) writeHierarchicalOutput(ctx context.Context, logger
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing hierarchical output: %v", err), globals.GCP_SOURCEREPOS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
@@ -325,7 +325,7 @@ func (m *SourceReposModule) writeFlatOutput(ctx context.Context, logger internal
)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_SOURCEREPOS_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+2 -2
View File
@@ -98,7 +98,7 @@ func (m *SpannerModule) processProject(ctx context.Context, projectID string, lo
svc := spannerservice.New()
result, err := svc.ListInstancesAndDatabases(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_SPANNER_MODULE_NAME,
fmt.Sprintf("Could not list Spanner instances in project %s", projectID))
return
@@ -459,6 +459,6 @@ func (m *SpannerModule) writeFlatOutput(ctx context.Context, logger internal.Log
"project", m.ProjectIDs, scopeNames, m.Account, output)
if err != nil {
logger.ErrorM(fmt.Sprintf("Error writing output: %v", err), globals.GCP_SPANNER_MODULE_NAME)
m.CommandCounter.Error++
m.CommandCounter.IncrError()
}
}
+1 -1
View File
@@ -103,7 +103,7 @@ func (m *SpannerEnumModule) processProject(ctx context.Context, projectID string
resources, err := svc.EnumerateSensitiveResources(projectID)
if err != nil {
m.CommandCounter.Error++
m.CommandCounter.IncrError()
gcpinternal.HandleGCPError(err, logger, globals.GCP_SPANNERENUM_MODULE_NAME,
fmt.Sprintf("Could not scan Spanner in project %s", projectID))
return
Loaded 100 of 168 files, more files were not shown because too many files have changed in this diff. Show more