feat(gcp): add retry to avoid quota limit errors (#8412)

Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
This commit is contained in:
Daniel Barranquero
2025-08-06 11:59:41 +02:00
committed by GitHub
parent fc69e195e4
commit 196c17d44d
26 changed files with 409 additions and 125 deletions

View File

@@ -50,6 +50,49 @@ The GCP provider implementation follows the general [Provider structure](./provi
- **Location:** [`prowler/providers/gcp/lib/`](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/gcp/lib/)
- **Purpose:** Helpers for argument parsing, mutelist management, and other cross-cutting concerns.
## Retry Configuration
GCP services implement automatic retry functionality for rate limiting errors (HTTP 429). This is configured centrally and must be included in all API calls:
### Required Implementation
```python
from prowler.providers.gcp.config import DEFAULT_RETRY_ATTEMPTS
# In discovery.build()
client = discovery.build(
service, version, credentials=credentials,
num_retries=DEFAULT_RETRY_ATTEMPTS
)
# In request.execute()
response = request.execute(num_retries=DEFAULT_RETRY_ATTEMPTS)
```
### Configuration
- **Default Value**: 3 attempts (configurable in `prowler/providers/gcp/config.py`)
- **Command Line Flag**: `--gcp-retries-max-attempts` for runtime configuration
- **Error Types**: HTTP 429 and quota exceeded errors
- **Backoff Strategy**: Exponential backoff with randomization
### Example Service Implementation
```python
def _get_instances(self):
for project_id in self.project_ids:
try:
client = discovery.build(
"compute", "v1", credentials=self.credentials,
num_retries=DEFAULT_RETRY_ATTEMPTS
)
request = client.instances().list(project=project_id)
response = request.execute(num_retries=DEFAULT_RETRY_ATTEMPTS)
# Process response...
except Exception as error:
logger.error(f"{error.__class__.__name__}: {error}")
```
## Specific Patterns in GCP Services
The generic service pattern is described in [service page](./services.md#service-structure-and-initialisation). You can find all the currently implemented services in the following locations:
@@ -69,6 +112,7 @@ The best reference to understand how to implement a new service is following the
- Resource discovery and attribute collection can be parallelized using `self.__threading_call__`, typically by region/zone or resource.
- All GCP resources are represented as Pydantic `BaseModel` classes, providing type safety and structured access to resource attributes.
- Each GCP API calls are wrapped in try/except blocks, always logging errors.
- **Retry Configuration**: All `request.execute()` calls must include `num_retries=DEFAULT_RETRY_ATTEMPTS` for automatic retry on rate limiting errors (HTTP 429).
- Tags and additional attributes that cannot be retrieved from the default call should be collected and stored for each resource using dedicated methods and threading.
## Specific Patterns in GCP Checks

View File

@@ -671,6 +671,16 @@ prowler azure --az-cli-auth --subscription-ids <subscription ID 1> <subscription
prowler gcp --project-ids <Project ID 1> <Project ID 2> ... <Project ID N>
```
- **GCP Retry Configuration**
To configure the maximum number of retry attempts for Google Cloud SDK API calls, use the `--gcp-retries-max-attempts` flag:
```console
prowler gcp --gcp-retries-max-attempts 5
```
This is useful when experiencing quota exceeded errors (HTTP 429) to increase the number of automatic retry attempts.
#### Kubernetes
Prowler enables security scanning of Kubernetes clusters, supporting both **in-cluster** and **external** execution.

View File

@@ -0,0 +1,95 @@
# GCP Retry Configuration in Prowler
Prowler's GCP Provider uses Google Cloud Python SDK's integrated retry mechanism to automatically retry API calls when encountering rate limiting errors (HTTP 429).
## Quick Configuration
### Using Command Line Flag (Recommended)
```bash
prowler gcp --gcp-retries-max-attempts 5
```
### Using Configuration File
Modify `prowler/providers/gcp/config.py`:
```python
DEFAULT_RETRY_ATTEMPTS = 5 # Default: 3
```
## How It Works
- **Automatic Detection**: Handles HTTP 429 and quota exceeded errors
- **Exponential Backoff**: Each retry uses randomized exponential backoff
- **Centralized Config**: All GCP services use the same retry configuration
- **Transparent**: No additional code needed in services
## Error Examples Handled
```
HttpError 429 when requesting https://cloudresourcemanager.googleapis.com/v1/projects/vms-uat-eiger:getIamPolicy?alt=json returned "Quota exceeded for quota metric 'Read requests' and limit 'Read requests per minute'"
```
## Implementation
### Client-Level Configuration
```python
from prowler.providers.gcp.config import DEFAULT_RETRY_ATTEMPTS
client = discovery.build(
service, version, credentials=credentials,
num_retries=DEFAULT_RETRY_ATTEMPTS
)
```
### Request-Level Configuration
```python
response = request.execute(num_retries=DEFAULT_RETRY_ATTEMPTS)
```
## Services with Retry Support
All major GCP services are covered:
- Cloud Resource Manager, Compute Engine, IAM
- BigQuery, KMS, Cloud Storage, Monitoring
- DNS, Logging, Cloud SQL, GKE, API Keys, DataProc
## Validation
### Debug Logging
```bash
prowler gcp --log-level DEBUG --log-file debuglogs.txt --project-id your-project-id
```
### Check for Retry Messages
```bash
grep -i "sleeping\|retry\|quota exceeded" debuglogs.txt
```
### Expected Output
```
"Sleeping 1.52 seconds before retry 1 of 3"
"Sleeping 3.23 seconds before retry 2 of 3"
```
## Testing in Real Environment
1. **Reduce API Quotas** in GCP Console:
- APIs & Services > Quotas
- Reduce "Read requests per minute" for Compute Engine API
- Reduce "Policy Read Requests per minute" for IAM API
2. **Run Prowler** with debug logging
3. **Monitor logs** for retry messages
## Troubleshooting
If experiencing rate limiting:
1. Use `--gcp-retries-max-attempts` flag to increase attempts
2. Request quota increases from Google Cloud support
3. Optimize scanning to reduce simultaneous API calls
4. Verify retry functionality with debug logging
## Official References
- [Google Cloud Python Client Libraries](https://cloud.google.com/python/docs)
- [Google Cloud Quotas](https://cloud.google.com/docs/quotas)
- [Google API Core Retry](https://googleapis.dev/python/google-api-core/latest/retry.html)