mirror of
https://github.com/BishopFox/cloudfox.git
synced 2026-11-11 01:31:28 -10:00
Compare commits
8
Commits
jb/gcp-dev
..
v2.0.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba4ff4701a | ||
|
|
81be56e006 | ||
|
|
494443d7ce | ||
|
|
3d3cfc6c0c | ||
|
|
1b0925877d | ||
|
|
7727d1d08c | ||
|
|
c7f81dc5cc | ||
|
|
008fb84d23 |
No files matched your search
@@ -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/*
|
||||
@@ -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"
|
||||
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
+9
-9
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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{
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
"-",
|
||||
"-",
|
||||
"-",
|
||||
"-",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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, "-", "-",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
"-",
|
||||
"-",
|
||||
"-",
|
||||
"-",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in new issue
Block a user