mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-31 07:44:21 +00:00
Co-authored-by: Pablo F.G <pablo.fernandez@prowler.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
293 lines
9.5 KiB
Markdown
293 lines
9.5 KiB
Markdown
# Prowler API Configuration Reference
|
|
|
|
## Settings File Structure
|
|
|
|
```text
|
|
api/src/backend/config/
|
|
├── django/
|
|
│ ├── base.py # Base settings (all environments)
|
|
│ ├── devel.py # Development overrides
|
|
│ ├── production.py # Production settings
|
|
│ └── testing.py # Test settings
|
|
├── settings/
|
|
│ ├── celery.py # Celery broker/backend config
|
|
│ ├── partitions.py # Table partitioning settings
|
|
│ ├── sentry.py # Error tracking + exception filtering
|
|
│ └── social_login.py # OAuth/SAML providers
|
|
├── celery.py # Celery app instance + RLSTask
|
|
├── custom_logging.py # NDJSON/Human-readable formatters
|
|
├── env.py # django-environ setup
|
|
└── urls.py # Root URL config
|
|
```
|
|
|
|
---
|
|
|
|
## REST Framework Configuration
|
|
|
|
### Complete `REST_FRAMEWORK` Settings
|
|
|
|
```python
|
|
REST_FRAMEWORK = {
|
|
# Schema Generation (JSON:API compatible)
|
|
"DEFAULT_SCHEMA_CLASS": "drf_spectacular_jsonapi.schemas.openapi.JsonApiAutoSchema",
|
|
|
|
# Authentication (JWT + API Key)
|
|
"DEFAULT_AUTHENTICATION_CLASSES": (
|
|
"api.authentication.CombinedJWTOrAPIKeyAuthentication",
|
|
),
|
|
|
|
# Pagination
|
|
"PAGE_SIZE": 10,
|
|
"DEFAULT_PAGINATION_CLASS": "drf_spectacular_jsonapi.schemas.pagination.JsonApiPageNumberPagination",
|
|
|
|
# Custom exception handler (JSON:API format)
|
|
"EXCEPTION_HANDLER": "api.exceptions.custom_exception_handler",
|
|
|
|
# Parsers (JSON:API compatible)
|
|
"DEFAULT_PARSER_CLASSES": (
|
|
"rest_framework_json_api.parsers.JSONParser",
|
|
"rest_framework.parsers.FormParser",
|
|
"rest_framework.parsers.MultiPartParser",
|
|
),
|
|
|
|
# Custom renderer with RLS context support
|
|
"DEFAULT_RENDERER_CLASSES": ("api.renderers.APIJSONRenderer",),
|
|
|
|
# Metadata
|
|
"DEFAULT_METADATA_CLASS": "rest_framework_json_api.metadata.JSONAPIMetadata",
|
|
|
|
# Filter Backends
|
|
"DEFAULT_FILTER_BACKENDS": (
|
|
"rest_framework_json_api.filters.QueryParameterValidationFilter",
|
|
"rest_framework_json_api.filters.OrderingFilter",
|
|
"rest_framework_json_api.django_filters.backends.DjangoFilterBackend",
|
|
"rest_framework.filters.SearchFilter",
|
|
),
|
|
|
|
# JSON:API search parameter
|
|
"SEARCH_PARAM": "filter[search]",
|
|
|
|
# Test settings
|
|
"TEST_REQUEST_RENDERER_CLASSES": ("rest_framework_json_api.renderers.JSONRenderer",),
|
|
"TEST_REQUEST_DEFAULT_FORMAT": "vnd.api+json",
|
|
|
|
# Uniform exception format
|
|
"JSON_API_UNIFORM_EXCEPTIONS": True,
|
|
|
|
# Throttling
|
|
"DEFAULT_THROTTLE_CLASSES": ["rest_framework.throttling.ScopedRateThrottle"],
|
|
"DEFAULT_THROTTLE_RATES": {
|
|
"token-obtain": env("DJANGO_THROTTLE_TOKEN_OBTAIN", default=None),
|
|
"dj_rest_auth": None,
|
|
},
|
|
}
|
|
```
|
|
|
|
### Throttling Configuration
|
|
|
|
| Scope | Environment Variable | Default | Format |
|
|
|-------|---------------------|---------|--------|
|
|
| `token-obtain` | `DJANGO_THROTTLE_TOKEN_OBTAIN` | `None` (disabled) | `"X/minute"`, `"X/hour"`, `"X/day"` |
|
|
| `dj_rest_auth` | N/A | `None` (disabled) | Same |
|
|
|
|
**To enable throttling:**
|
|
```bash
|
|
DJANGO_THROTTLE_TOKEN_OBTAIN="10/minute" # Limit token endpoint to 10 requests/minute
|
|
```
|
|
|
|
---
|
|
|
|
## JWT Configuration (SIMPLE_JWT)
|
|
|
|
```python
|
|
SIMPLE_JWT = {
|
|
# Token Lifetimes
|
|
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=30), # DJANGO_ACCESS_TOKEN_LIFETIME
|
|
"REFRESH_TOKEN_LIFETIME": timedelta(minutes=1440), # DJANGO_REFRESH_TOKEN_LIFETIME (24h)
|
|
|
|
# Token Rotation
|
|
"ROTATE_REFRESH_TOKENS": True,
|
|
"BLACKLIST_AFTER_ROTATION": True,
|
|
|
|
# Cryptographic Settings
|
|
"ALGORITHM": "RS256", # Asymmetric (requires key pair)
|
|
"SIGNING_KEY": env.str("DJANGO_TOKEN_SIGNING_KEY", ""),
|
|
"VERIFYING_KEY": env.str("DJANGO_TOKEN_VERIFYING_KEY", ""),
|
|
|
|
# JWT Claims
|
|
"TOKEN_TYPE_CLAIM": "typ",
|
|
"JTI_CLAIM": "jti",
|
|
"USER_ID_FIELD": "id",
|
|
"USER_ID_CLAIM": "sub",
|
|
|
|
# Issuer/Audience
|
|
"AUDIENCE": env.str("DJANGO_JWT_AUDIENCE", "https://api.prowler.com"),
|
|
"ISSUER": env.str("DJANGO_JWT_ISSUER", "https://api.prowler.com"),
|
|
|
|
# Custom Serializers
|
|
"TOKEN_OBTAIN_SERIALIZER": "api.serializers.TokenSerializer",
|
|
"TOKEN_REFRESH_SERIALIZER": "api.serializers.TokenRefreshSerializer",
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Database Configuration
|
|
|
|
### 4-Database Architecture
|
|
|
|
```python
|
|
DATABASES = {
|
|
"default": {...}, # Alias to prowler_user (RLS enabled)
|
|
"prowler_user": {...}, # RLS-enabled connection
|
|
"admin": {...}, # Admin connection (bypasses RLS)
|
|
"replica": {...}, # Read replica (RLS enabled)
|
|
"admin_replica": {...}, # Admin on replica
|
|
"neo4j": {...}, # Graph database (attack paths)
|
|
}
|
|
```
|
|
|
|
### Environment Variables
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `POSTGRES_DB` | `prowler_db` | Database name |
|
|
| `POSTGRES_USER` | `prowler_user` | API user (RLS-constrained) |
|
|
| `POSTGRES_PASSWORD` | - | API user password |
|
|
| `POSTGRES_HOST` | `postgres-db` | Database host |
|
|
| `POSTGRES_PORT` | `5432` | Database port |
|
|
| `POSTGRES_ADMIN_USER` | `prowler` | Admin user (migrations) |
|
|
| `POSTGRES_ADMIN_PASSWORD` | - | Admin password |
|
|
| `POSTGRES_REPLICA_HOST` | - | Replica host (optional) |
|
|
| `POSTGRES_REPLICA_MAX_ATTEMPTS` | `3` | Retry attempts before fallback |
|
|
| `POSTGRES_REPLICA_RETRY_BASE_DELAY` | `0.5` | Base delay for exponential backoff |
|
|
|
|
---
|
|
|
|
## Celery Configuration
|
|
|
|
### Broker/Backend
|
|
|
|
```python
|
|
VALKEY_SCHEME = env("VALKEY_SCHEME", default="redis")
|
|
VALKEY_USERNAME = env("VALKEY_USERNAME", default="")
|
|
VALKEY_PASSWORD = env("VALKEY_PASSWORD", default="")
|
|
VALKEY_HOST = env("VALKEY_HOST", default="valkey")
|
|
VALKEY_PORT = env("VALKEY_PORT", default="6379")
|
|
VALKEY_DB = env("VALKEY_DB", default="0")
|
|
|
|
CELERY_BROKER_URL = _build_celery_broker_url(
|
|
VALKEY_SCHEME,
|
|
VALKEY_USERNAME,
|
|
VALKEY_PASSWORD,
|
|
VALKEY_HOST,
|
|
VALKEY_PORT,
|
|
VALKEY_DB,
|
|
)
|
|
CELERY_RESULT_BACKEND = "django-db" # Store results in PostgreSQL
|
|
CELERY_TASK_TRACK_STARTED = True
|
|
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True
|
|
```
|
|
|
|
### Task Visibility
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `DJANGO_BROKER_VISIBILITY_TIMEOUT` | `86400` (24h) | Task visibility timeout |
|
|
| `DJANGO_CELERY_DEADLOCK_ATTEMPTS` | `5` | Deadlock retry attempts |
|
|
|
|
---
|
|
|
|
## Partitioning Configuration
|
|
|
|
```python
|
|
PSQLEXTRA_PARTITIONING_MANAGER = "api.partitions.manager"
|
|
FINDINGS_TABLE_PARTITION_MONTHS = env.int("FINDINGS_TABLE_PARTITION_MONTHS", 1)
|
|
FINDINGS_TABLE_PARTITION_COUNT = env.int("FINDINGS_TABLE_PARTITION_COUNT", 7)
|
|
FINDINGS_TABLE_PARTITION_MAX_AGE_MONTHS = env.int("...", None) # Optional cleanup
|
|
```
|
|
|
|
---
|
|
|
|
## Application Settings
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `DJANGO_DEBUG` | `False` | Debug mode |
|
|
| `DJANGO_ALLOWED_HOSTS` | `["localhost"]` | Allowed hosts |
|
|
| `DJANGO_CACHE_MAX_AGE` | `3600` | HTTP cache max-age |
|
|
| `DJANGO_STALE_WHILE_REVALIDATE` | `60` | Stale-while-revalidate time |
|
|
| `DJANGO_FINDINGS_MAX_DAYS_IN_RANGE` | `7` | Max days for findings date filter |
|
|
| `DJANGO_TMP_OUTPUT_DIRECTORY` | `/tmp/prowler_api_output` | Temp output directory |
|
|
| `DJANGO_FINDINGS_BATCH_SIZE` | `1000` | Batch size for findings export |
|
|
| `DJANGO_DELETION_BATCH_SIZE` | `5000` | Batch size for deletions |
|
|
| `DJANGO_LOGGING_LEVEL` | `INFO` | Log level |
|
|
| `DJANGO_LOGGING_FORMATTER` | `ndjson` | Log format (`ndjson` or `human_readable`) |
|
|
|
|
---
|
|
|
|
## Social Login (OAuth/SAML)
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `SOCIAL_GOOGLE_OAUTH_CLIENT_ID` | Google OAuth client ID |
|
|
| `SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET` | Google OAuth secret |
|
|
| `SOCIAL_GITHUB_OAUTH_CLIENT_ID` | GitHub OAuth client ID |
|
|
| `SOCIAL_GITHUB_OAUTH_CLIENT_SECRET` | GitHub OAuth secret |
|
|
|
|
---
|
|
|
|
## Monitoring
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `DJANGO_SENTRY_DSN` | Sentry DSN for error tracking |
|
|
|
|
---
|
|
|
|
## Middleware Stack (Order Matters)
|
|
|
|
```python
|
|
MIDDLEWARE = [
|
|
"django_guid.middleware.guid_middleware", # 1. Transaction ID
|
|
"django.middleware.security.SecurityMiddleware", # 2. Security headers
|
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
|
"corsheaders.middleware.CorsMiddleware", # 4. CORS (before Common)
|
|
"django.middleware.common.CommonMiddleware",
|
|
"django.middleware.csrf.CsrfViewMiddleware",
|
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
|
"django.contrib.messages.middleware.MessageMiddleware",
|
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
|
"api.middleware.APILoggingMiddleware", # 10. Custom API logging
|
|
"allauth.account.middleware.AccountMiddleware",
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## Security Headers
|
|
|
|
| Setting | Value | Description |
|
|
|---------|-------|-------------|
|
|
| `SECURE_PROXY_SSL_HEADER` | `("HTTP_X_FORWARDED_PROTO", "https")` | Trust X-Forwarded-Proto |
|
|
| `SECURE_CONTENT_TYPE_NOSNIFF` | `True` | X-Content-Type-Options: nosniff |
|
|
| `X_FRAME_OPTIONS` | `"DENY"` | Prevent framing |
|
|
| `CSRF_COOKIE_SECURE` | `True` | HTTPS-only CSRF cookie |
|
|
| `SESSION_COOKIE_SECURE` | `True` | HTTPS-only session cookie |
|
|
|
|
---
|
|
|
|
## Password Validators
|
|
|
|
| Validator | Options |
|
|
|-----------|---------|
|
|
| `UserAttributeSimilarityValidator` | Default |
|
|
| `MinimumLengthValidator` | `min_length=12` |
|
|
| `MaximumLengthValidator` | `max_length=72` (bcrypt limit) |
|
|
| `CommonPasswordValidator` | Default |
|
|
| `NumericPasswordValidator` | Default |
|
|
| `SpecialCharactersValidator` | `min_special_characters=1` |
|
|
| `UppercaseValidator` | `min_uppercase=1` |
|
|
| `LowercaseValidator` | `min_lowercase=1` |
|
|
| `NumericValidator` | `min_numeric=1` |
|