Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
799a72dff7 |
@@ -6,20 +6,14 @@
|
||||
PROWLER_UI_VERSION="stable"
|
||||
AUTH_URL=http://localhost:3000
|
||||
API_BASE_URL=http://prowler-api:8080/api/v1
|
||||
# deprecated, use UI_API_BASE_URL
|
||||
NEXT_PUBLIC_API_BASE_URL=${API_BASE_URL}
|
||||
UI_API_BASE_URL=${API_BASE_URL}
|
||||
# deprecated, use UI_API_DOCS_URL
|
||||
NEXT_PUBLIC_API_DOCS_URL=http://prowler-api:8080/api/v1/docs
|
||||
UI_API_DOCS_URL=http://prowler-api:8080/api/v1/docs
|
||||
AUTH_TRUST_HOST=true
|
||||
UI_PORT=3000
|
||||
# openssl rand -base64 32
|
||||
AUTH_SECRET="N/c6mnaS5+SWq81+819OrzQZlmx1Vxtp/orjttJSmw8="
|
||||
# Google Tag Manager ID (empty/unset ⇒ GTM not loaded, zero egress)
|
||||
# deprecated, use UI_GOOGLE_TAG_MANAGER_ID
|
||||
# Google Tag Manager ID
|
||||
NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID=""
|
||||
UI_GOOGLE_TAG_MANAGER_ID=""
|
||||
|
||||
#### MCP Server ####
|
||||
PROWLER_MCP_VERSION=stable
|
||||
@@ -145,16 +139,10 @@ DJANGO_BROKER_VISIBILITY_TIMEOUT=86400
|
||||
DJANGO_SENTRY_DSN=
|
||||
DJANGO_THROTTLE_TOKEN_OBTAIN=50/minute
|
||||
|
||||
# Sentry for the web app (server + browser). Empty/unset UI_SENTRY_DSN ⇒
|
||||
# Sentry disabled, zero egress. SENTRY_RELEASE (unprefixed) feeds the web app's
|
||||
# server/edge SDKs.
|
||||
UI_SENTRY_DSN=
|
||||
UI_SENTRY_ENVIRONMENT=local
|
||||
# Sentry settings
|
||||
SENTRY_ENVIRONMENT=local
|
||||
SENTRY_RELEASE=local
|
||||
# Reserved runtime public config (registered now; no UI consumer yet)
|
||||
# POSTHOG_KEY=
|
||||
# POSTHOG_HOST=
|
||||
# REO_DEV_CLIENT_ID=
|
||||
NEXT_PUBLIC_SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT}
|
||||
|
||||
#### Prowler release version ####
|
||||
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.31.0
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# SDK
|
||||
/* @prowler-cloud/detection-remediation
|
||||
/prowler/ @prowler-cloud/detection-remediation
|
||||
/prowler/compliance/ @prowler-cloud/compliance
|
||||
/tests/ @prowler-cloud/detection-remediation
|
||||
/dashboard/ @prowler-cloud/detection-remediation
|
||||
/docs/ @prowler-cloud/detection-remediation
|
||||
|
||||
@@ -77,11 +77,6 @@ provider/okta:
|
||||
- any-glob-to-any-file: "prowler/providers/okta/**"
|
||||
- any-glob-to-any-file: "tests/providers/okta/**"
|
||||
|
||||
provider/linode:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "prowler/providers/linode/**"
|
||||
- any-glob-to-any-file: "tests/providers/linode/**"
|
||||
|
||||
github_actions:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ".github/workflows/*"
|
||||
|
||||
@@ -24,6 +24,7 @@ permissions: {}
|
||||
|
||||
jobs:
|
||||
mcp-security-scans:
|
||||
if: github.repository == 'prowler-cloud/prowler'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
|
||||
@@ -590,30 +590,6 @@ jobs:
|
||||
flags: prowler-py${{ matrix.python-version }}-stackit
|
||||
files: ./stackit_coverage.xml
|
||||
|
||||
# Linode Provider
|
||||
- name: Check if Linode files changed
|
||||
if: steps.check-changes.outputs.any_changed == 'true'
|
||||
id: changed-linode
|
||||
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
|
||||
with:
|
||||
files: |
|
||||
./prowler/**/linode/**
|
||||
./tests/**/linode/**
|
||||
./uv.lock
|
||||
|
||||
- name: Run Linode tests
|
||||
if: steps.changed-linode.outputs.any_changed == 'true'
|
||||
run: uv run pytest -n auto --cov=./prowler/providers/linode --cov-report=xml:linode_coverage.xml tests/providers/linode
|
||||
|
||||
- name: Upload Linode coverage to Codecov
|
||||
if: steps.changed-linode.outputs.any_changed == 'true'
|
||||
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
with:
|
||||
flags: prowler-py${{ matrix.python-version }}-linode
|
||||
files: ./linode_coverage.xml
|
||||
|
||||
# External Provider (dynamic loading)
|
||||
- name: Check if External Provider files changed
|
||||
if: steps.check-changes.outputs.any_changed == 'true'
|
||||
|
||||
@@ -32,6 +32,9 @@ env:
|
||||
PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud
|
||||
PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-ui
|
||||
|
||||
# Build args
|
||||
NEXT_PUBLIC_API_BASE_URL: http://prowler-api:8080/api/v1
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
@@ -143,6 +146,7 @@ jobs:
|
||||
context: ${{ env.WORKING_DIRECTORY }}
|
||||
build-args: |
|
||||
NEXT_PUBLIC_PROWLER_RELEASE_VERSION=${{ (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && format('v{0}', env.RELEASE_TAG) || needs.setup.outputs.short-sha }}
|
||||
NEXT_PUBLIC_API_BASE_URL=${{ env.NEXT_PUBLIC_API_BASE_URL }}
|
||||
push: true
|
||||
platforms: ${{ matrix.platform }}
|
||||
tags: |
|
||||
|
||||
@@ -40,8 +40,7 @@ jobs:
|
||||
AUTH_SECRET: 'fallback-ci-secret-for-testing'
|
||||
AUTH_TRUST_HOST: true
|
||||
NEXTAUTH_URL: 'http://localhost:3000'
|
||||
AUTH_URL: 'http://localhost:3000'
|
||||
UI_API_BASE_URL: 'http://localhost:8080/api/v1'
|
||||
NEXT_PUBLIC_API_BASE_URL: 'http://localhost:8080/api/v1'
|
||||
E2E_ADMIN_USER: ${{ secrets.E2E_ADMIN_USER }}
|
||||
E2E_ADMIN_PASSWORD: ${{ secrets.E2E_ADMIN_PASSWORD }}
|
||||
E2E_AWS_PROVIDER_ACCOUNT_ID: ${{ secrets.E2E_AWS_PROVIDER_ACCOUNT_ID }}
|
||||
@@ -78,14 +77,6 @@ jobs:
|
||||
E2E_ALIBABACLOUD_ACCESS_KEY_ID: ${{ secrets.E2E_ALIBABACLOUD_ACCESS_KEY_ID }}
|
||||
E2E_ALIBABACLOUD_ACCESS_KEY_SECRET: ${{ secrets.E2E_ALIBABACLOUD_ACCESS_KEY_SECRET }}
|
||||
E2E_ALIBABACLOUD_ROLE_ARN: ${{ secrets.E2E_ALIBABACLOUD_ROLE_ARN }}
|
||||
E2E_OKTA_DOMAIN: ${{ secrets.E2E_OKTA_DOMAIN }}
|
||||
E2E_OKTA_CLIENT_ID: ${{ secrets.E2E_OKTA_CLIENT_ID }}
|
||||
E2E_OKTA_BASE64_PRIVATE_KEY: ${{ secrets.E2E_OKTA_BASE64_PRIVATE_KEY }}
|
||||
E2E_GOOGLEWORKSPACE_CUSTOMER_ID: ${{ secrets.E2E_GOOGLEWORKSPACE_CUSTOMER_ID }}
|
||||
E2E_GOOGLEWORKSPACE_SERVICE_ACCOUNT_JSON: ${{ secrets.E2E_GOOGLEWORKSPACE_SERVICE_ACCOUNT_JSON }}
|
||||
E2E_GOOGLEWORKSPACE_DELEGATED_USER: ${{ secrets.E2E_GOOGLEWORKSPACE_DELEGATED_USER }}
|
||||
E2E_VERCEL_TEAM_ID: ${{ secrets.E2E_VERCEL_TEAM_ID }}
|
||||
E2E_VERCEL_API_TOKEN: ${{ secrets.E2E_VERCEL_API_TOKEN }}
|
||||
# Pass E2E paths from impact analysis
|
||||
E2E_TEST_PATHS: ${{ needs.impact-analysis.outputs.ui-e2e }}
|
||||
RUN_ALL_TESTS: ${{ needs.impact-analysis.outputs.run-all }}
|
||||
@@ -166,7 +157,7 @@ jobs:
|
||||
timeout=150
|
||||
elapsed=0
|
||||
while [ $elapsed -lt $timeout ]; do
|
||||
if curl -s ${UI_API_BASE_URL}/docs >/dev/null 2>&1; then
|
||||
if curl -s ${NEXT_PUBLIC_API_BASE_URL}/docs >/dev/null 2>&1; then
|
||||
echo "Prowler API is ready!"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -24,6 +24,7 @@ permissions: {}
|
||||
|
||||
jobs:
|
||||
ui-security-scans:
|
||||
if: github.repository == 'prowler-cloud/prowler'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
# P50 — dependency validation
|
||||
|
||||
default_install_hook_types: [pre-commit]
|
||||
# Hooks run on commit only by default;
|
||||
# NOTE: default_stages does NOT override a hook's manifest stages, so fixers shipping pre-push in their
|
||||
# manifest need an explicit stages: ["pre-commit"] below to stay off push.
|
||||
default_stages: [pre-commit]
|
||||
|
||||
repos:
|
||||
## GENERAL (prek built-in — no external repo needed)
|
||||
@@ -25,16 +21,13 @@ repos:
|
||||
- id: check-json
|
||||
priority: 10
|
||||
- id: end-of-file-fixer
|
||||
stages: ["pre-commit"]
|
||||
priority: 0
|
||||
- id: trailing-whitespace
|
||||
stages: ["pre-commit"]
|
||||
priority: 0
|
||||
- id: no-commit-to-branch
|
||||
priority: 10
|
||||
- id: pretty-format-json
|
||||
args: ["--autofix", --no-sort-keys, --no-ensure-ascii]
|
||||
stages: ["pre-commit"]
|
||||
priority: 10
|
||||
|
||||
## TOML
|
||||
@@ -89,7 +82,6 @@ repos:
|
||||
name: "SDK - isort"
|
||||
files: { glob: ["{prowler,tests,dashboard,util,scripts}/**/*.py"] }
|
||||
args: ["--profile", "black"]
|
||||
stages: ["pre-commit"]
|
||||
priority: 20
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
|
||||
@@ -1,34 +1,5 @@
|
||||
.DEFAULT_GOAL:=help
|
||||
|
||||
DEV_LOCAL := ./scripts/development/dev-local.sh
|
||||
|
||||
.PHONY: dev dev-setup dev-attach dev-launch dev-stop dev-clean dev-wipe dev-status
|
||||
|
||||
##@ Local Development
|
||||
dev: ## Start local API, worker, and database logs
|
||||
$(DEV_LOCAL) all
|
||||
|
||||
dev-setup: ## Bootstrap local dependencies, migrations, and fixtures
|
||||
$(DEV_LOCAL) setup
|
||||
|
||||
dev-attach: ## Attach to the local tmux development session
|
||||
$(DEV_LOCAL) attach
|
||||
|
||||
dev-launch: ## Start the local stack on fixed ports and attach
|
||||
$(DEV_LOCAL) launch
|
||||
|
||||
dev-stop: ## Stop the local tmux session and containers
|
||||
$(DEV_LOCAL) kill
|
||||
|
||||
dev-clean: ## Remove stopped local development containers
|
||||
$(DEV_LOCAL) clean
|
||||
|
||||
dev-wipe: ## Stop everything and delete local development data
|
||||
$(DEV_LOCAL) wipe
|
||||
|
||||
dev-status: ## Show local development container status
|
||||
$(DEV_LOCAL) status
|
||||
|
||||
##@ Testing
|
||||
test: ## Test with pytest
|
||||
rm -rf .coverage && \
|
||||
|
||||
@@ -121,7 +121,6 @@ Every AWS provider scan will enqueue an Attack Paths ingestion job automatically
|
||||
| OpenStack | 34 | 5 | 0 | 9 | Official | UI, API, CLI |
|
||||
| Vercel | 26 | 6 | 0 | 8 | Official | UI, API, CLI |
|
||||
| Okta | 1 | 1 | 0 | 1 | Official | CLI |
|
||||
| Linode [Contact us](https://prowler.com/contact) | 10 | 3 | 0 | 4 | Unofficial | CLI |
|
||||
| Scaleway [Contact us](https://prowler.com/contact) | 1 | 1 | 0 | 1 | Unofficial | CLI |
|
||||
| StackIT [Contact us](https://prowler.com/contact) | 7 | 2 | 0 | 3 | Unofficial | CLI |
|
||||
| NHN | 6 | 2 | 1 | 0 | Unofficial | CLI |
|
||||
|
||||
@@ -24,9 +24,6 @@ DJANGO_THROTTLE_TOKEN_OBTAIN=50/minute
|
||||
# Decide whether to allow Django manage database table partitions
|
||||
DJANGO_MANAGE_DB_PARTITIONS=[True|False]
|
||||
DJANGO_CELERY_DEADLOCK_ATTEMPTS=5
|
||||
# Optional: bound Celery's prefork pool size. Unset → Celery uses os.cpu_count().
|
||||
# Useful on Kubernetes nodes with many CPUs where unbounded prefork balloons memory.
|
||||
# DJANGO_CELERY_WORKER_CONCURRENCY=4
|
||||
DJANGO_BROKER_VISIBILITY_TIMEOUT=86400
|
||||
DJANGO_SENTRY_DSN=
|
||||
|
||||
|
||||
@@ -6,21 +6,7 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- Provider group filters for API endpoints that support cloud provider filtering, including exact and `__in` variants [(#11573)](https://github.com/prowler-cloud/prowler/pull/11573)
|
||||
- Provider filters for `GET /api/v1/compliance-overviews`, `/metadata`, and `/requirements`, using latest completed scans per matching provider [(#11587)](https://github.com/prowler-cloud/prowler/pull/11587)
|
||||
- Server-Sent Events (SSE) infrastructure for the API: a base viewset, a tenant-aware channel manager, and channel-name helpers backed by `django-eventstream` over Valkey Pub/Sub and served through the Gunicorn ASGI worker, so feature endpoints can stream events to clients over a single long-lived connection [(#11556)](https://github.com/prowler-cloud/prowler/pull/11556)
|
||||
- `DJANGO_CELERY_WORKER_CONCURRENCY` to configure Celery workers concurrency. Unset for default behaviour [(#11075)](https://github.com/prowler-cloud/prowler/pull/11075)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- Gunicorn worker timeout raised from the 30s default to 120s, so long-running requests are no longer killed prematurely [(#11631)](https://github.com/prowler-cloud/prowler/pull/11631)
|
||||
- Sentry now drops ASGI's `RequestAborted` errors from health-check probe disconnects on `/health/live` [(#11632)](https://github.com/prowler-cloud/prowler/pull/11632)
|
||||
- Gunicorn keep-alive timeout now exceeds the load balancer idle timeout, stopping 502s from reused connections [(#11647)](https://github.com/prowler-cloud/prowler/pull/11647)
|
||||
- API runs under the Uvicorn worker so keep-alive outlives the load balancer idle timeout, fixing Gunicorn's intermittent 502s [(#11663)](https://github.com/prowler-cloud/prowler/pull/11663)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- Database connections no longer leak under the ASGI worker, which previously exhausted the read replica's connection slots and caused 500s on read endpoints [(#11640)](https://github.com/prowler-cloud/prowler/pull/11640)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
@@ -30,19 +16,11 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
|
||||
---
|
||||
|
||||
## [1.31.3] (Prowler v5.30.3)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
- SAML logins now link to an existing account only when the asserted email domain matches the ACS endpoint and the user is already a member of that domain's tenant, fixing a cross-tenant account takeover [(GHSA-h8m9-jgf8-vwvp)](https://github.com/prowler-cloud/prowler/security/advisories/GHSA-h8m9-jgf8-vwvp)
|
||||
|
||||
---
|
||||
|
||||
## [1.31.2] (Prowler v5.30.2)
|
||||
## [1.31.2] (Prowler UNRELEASED)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- `scan-compliance-overviews` task now streams the findings aggregation and the requirement-row writes so it runs faster and its peak memory no longer grows with the number of regions and frameworks [(#11591)](https://github.com/prowler-cloud/prowler/pull/11591)
|
||||
- `scan-compliance-overviews` task now streams the findings aggregation and the requirement-row writes (reading the denormalized `resource_regions` instead of prefetching resources, and batching rows into COPY instead of building the full list first), so it runs faster and its peak memory no longer grows with the number of regions and frameworks — a previous worker OOM risk on large scans — with no change to the compliance overview output [(#11591)](https://github.com/prowler-cloud/prowler/pull/11591)
|
||||
|
||||
---
|
||||
|
||||
@@ -68,7 +46,6 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
### 🔄 Changed
|
||||
|
||||
- Allowlisted idempotent background tasks are no longer lost when a worker is stopped or crashes mid-task; tasks with external side effects are marked terminal instead of blindly re-running [(#11416)](https://github.com/prowler-cloud/prowler/pull/11416)
|
||||
- SAML logins no longer wipe a user's roles when the IdP does not send the `userType` attribute; existing roles are kept, and when `userType` names a role that does not exist it is now created with read-only access (visibility over all providers, no management permissions) instead of no permissions at all [(#11520)](https://github.com/prowler-cloud/prowler/pull/11520)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
|
||||
@@ -196,42 +196,6 @@ python -m celery -A config.celery worker -l info -E
|
||||
|
||||
The Celery worker does not detect and reload changes in the code, so you need to restart it manually when you make changes.
|
||||
|
||||
### Makefile-Assisted Local Deployment
|
||||
|
||||
This method is an additional local development workflow. It does not replace the manual local deployment or the Docker deployment described in this guide.
|
||||
|
||||
PostgreSQL, Valkey, and Neo4j run with Docker Compose, while Django and the Celery worker run natively through `uv`. Additionally, this workflow creates a `tmux` session with panes for the API, worker, and PostgreSQL logs.
|
||||
|
||||
Before using this method, ensure `docker compose`, `tmux`, and `uv` are installed.
|
||||
|
||||
This workflow is designed for macOS and should also work on Linux when Docker, `tmux`, and `uv` are available. Windows requires script changes before it can be supported.
|
||||
|
||||
From the repository root, run:
|
||||
|
||||
```console
|
||||
make dev
|
||||
```
|
||||
|
||||
The API will be available at:
|
||||
|
||||
```console
|
||||
http://localhost:8080/api/v1
|
||||
```
|
||||
|
||||
Use these commands to manage the local stack:
|
||||
|
||||
```console
|
||||
make dev-setup # Bootstrap dependencies, migrations, and fixtures
|
||||
make dev-attach # Attach to the tmux session
|
||||
make dev-launch # Start the stack on fixed ports and attach
|
||||
make dev-stop # Stop the tmux session and containers
|
||||
make dev-clean # Remove stopped development containers
|
||||
make dev-wipe # Stop everything and delete local development data
|
||||
make dev-status # Show development container status
|
||||
```
|
||||
|
||||
This workflow does not start the UI. Start it separately from the `ui/` directory when needed.
|
||||
|
||||
### Docker deployment
|
||||
|
||||
This method requires `docker` and `docker compose`.
|
||||
|
||||
@@ -65,7 +65,6 @@ All settings have safe defaults; override via environment variables.
|
||||
| Env var | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `DJANGO_CELERY_WORKER_PREFETCH_MULTIPLIER` | `1` | Tasks reserved per worker process. |
|
||||
| `DJANGO_CELERY_WORKER_CONCURRENCY` | unset | Optional Celery prefork pool size. When unset, Celery uses its CPU-based default. Set this on worker containers to bound idle memory on hosts with many CPUs. |
|
||||
| `DJANGO_CELERY_WORKER_SOFT_SHUTDOWN_TIMEOUT` | `60` | Seconds the worker drains/re-queues on `SIGTERM` before force-kill. |
|
||||
| `DJANGO_CELERY_TASK_TIME_LIMIT` | `21600` (6h) | Hard limit for most tasks; connection checks are capped at 120s. |
|
||||
| `DJANGO_CELERY_TASK_SOFT_TIME_LIMIT` | hard - 600 | Soft limit; raises `SoftTimeLimitExceeded` for cleanup. |
|
||||
|
||||
@@ -43,7 +43,6 @@ dependencies = [
|
||||
"defusedxml==0.7.1",
|
||||
"django-eventstream==5.3.3",
|
||||
"gunicorn==26.0.0",
|
||||
"uvloop==0.22.1",
|
||||
"lxml==6.1.0",
|
||||
"prowler @ git+https://github.com/prowler-cloud/prowler.git@master",
|
||||
"psycopg2-binary==2.9.9",
|
||||
@@ -62,8 +61,7 @@ dependencies = [
|
||||
"gevent (==25.9.1)",
|
||||
"werkzeug (==3.1.7)",
|
||||
"sqlparse (==0.5.5)",
|
||||
"fonttools (==4.62.1)",
|
||||
"uvicorn-worker (==0.4.0)",
|
||||
"fonttools (==4.62.1)"
|
||||
]
|
||||
description = "Prowler's API (Django/DRF)"
|
||||
license = "Apache-2.0"
|
||||
@@ -423,8 +421,6 @@ constraint-dependencies = [
|
||||
"uritemplate==4.2.0",
|
||||
"urllib3==2.7.0",
|
||||
"uuid6==2024.7.10",
|
||||
"uvicorn==0.49.0",
|
||||
"uvloop==0.22.1",
|
||||
"vine==5.1.0",
|
||||
"vulture==2.14",
|
||||
"wcwidth==0.5.3",
|
||||
|
||||
@@ -3,14 +3,7 @@ from django.db import transaction
|
||||
|
||||
from api.db_router import MainRouter
|
||||
from api.db_utils import rls_transaction
|
||||
from api.models import (
|
||||
Membership,
|
||||
Role,
|
||||
SAMLConfiguration,
|
||||
Tenant,
|
||||
User,
|
||||
UserRoleRelationship,
|
||||
)
|
||||
from api.models import Membership, Role, Tenant, User, UserRoleRelationship
|
||||
|
||||
|
||||
class ProwlerSocialAccountAdapter(DefaultSocialAccountAdapter):
|
||||
@@ -25,42 +18,7 @@ class ProwlerSocialAccountAdapter(DefaultSocialAccountAdapter):
|
||||
# Link existing accounts with the same email address
|
||||
email = sociallogin.account.extra_data.get("email")
|
||||
if sociallogin.provider.id == "saml":
|
||||
# For SAML, the asserted NameID email cannot be trusted on its own:
|
||||
# any tenant can claim any email domain in its SAML configuration. To
|
||||
# prevent cross-tenant account takeover (GHSA-h8m9-jgf8-vwvp), only link
|
||||
# the incoming SAML session to an existing account when (1) the email
|
||||
# domain matches the tenant whose ACS endpoint is being used and (2) the
|
||||
# existing user is already a member of that tenant.
|
||||
email = sociallogin.user.email
|
||||
if not email:
|
||||
return
|
||||
|
||||
domain = email.rsplit("@", 1)[-1].lower()
|
||||
resolver_match = getattr(request, "resolver_match", None)
|
||||
organization_slug = (
|
||||
(resolver_match.kwargs or {}).get("organization_slug", "")
|
||||
if resolver_match
|
||||
else ""
|
||||
).lower()
|
||||
# The ACS endpoint is scoped per email domain; reject mismatches so an
|
||||
# attacker cannot replay an assertion through another tenant's endpoint.
|
||||
if organization_slug != domain:
|
||||
return
|
||||
|
||||
try:
|
||||
saml_config = SAMLConfiguration.objects.using(MainRouter.admin_db).get(
|
||||
email_domain=domain
|
||||
)
|
||||
except SAMLConfiguration.DoesNotExist:
|
||||
return
|
||||
|
||||
existing_user = self.get_user_by_email(email)
|
||||
if existing_user and existing_user.is_member_of_tenant(
|
||||
str(saml_config.tenant_id)
|
||||
):
|
||||
sociallogin.connect(request, existing_user)
|
||||
return
|
||||
|
||||
if email:
|
||||
existing_user = self.get_user_by_email(email)
|
||||
if existing_user:
|
||||
|
||||
@@ -112,14 +112,14 @@ def get_compliance_frameworks(provider_type: Provider.ProviderChoices) -> list[s
|
||||
"""List compliance framework identifiers available for `provider_type`.
|
||||
|
||||
Includes both per-provider frameworks and universal top-level frameworks
|
||||
(e.g. ``dora_2022_2554``, ``csa_ccm_4.0``).
|
||||
(e.g. ``dora``, ``csa_ccm_4.0``).
|
||||
|
||||
Args:
|
||||
provider_type (Provider.ProviderChoices): The cloud provider type
|
||||
(e.g., "aws", "azure", "gcp", "m365").
|
||||
|
||||
Returns:
|
||||
list[str]: Framework identifiers (e.g., "cis_1.4_aws", "dora_2022_2554").
|
||||
list[str]: Framework identifiers (e.g., "cis_1.4_aws", "dora").
|
||||
"""
|
||||
global AVAILABLE_COMPLIANCE_FRAMEWORKS
|
||||
if provider_type not in AVAILABLE_COMPLIANCE_FRAMEWORKS:
|
||||
|
||||
@@ -102,7 +102,7 @@ class BaseProviderFilter(FilterSet):
|
||||
"""
|
||||
Abstract base filter for models with direct FK to Provider.
|
||||
|
||||
Provides standard provider_id, provider_type, and provider_groups filters.
|
||||
Provides standard provider_id and provider_type filters.
|
||||
Subclasses must define Meta.model.
|
||||
"""
|
||||
|
||||
@@ -116,16 +116,6 @@ class BaseProviderFilter(FilterSet):
|
||||
choices=Provider.ProviderChoices.choices,
|
||||
lookup_expr="in",
|
||||
)
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
@@ -136,7 +126,7 @@ class BaseScanProviderFilter(FilterSet):
|
||||
"""
|
||||
Abstract base filter for models with FK to Scan (and Scan has FK to Provider).
|
||||
|
||||
Provides standard provider_id, provider_type, and provider_groups filters via scan relationship.
|
||||
Provides standard provider_id and provider_type filters via scan relationship.
|
||||
Subclasses must define Meta.model.
|
||||
"""
|
||||
|
||||
@@ -150,16 +140,6 @@ class BaseScanProviderFilter(FilterSet):
|
||||
choices=Provider.ProviderChoices.choices,
|
||||
lookup_expr="in",
|
||||
)
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="scan__provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="scan__provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
@@ -180,16 +160,6 @@ class CommonFindingFilters(FilterSet):
|
||||
provider_type__in = ChoiceInFilter(
|
||||
choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider"
|
||||
)
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="scan__provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="scan__provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
provider_uid = CharFilter(field_name="scan__provider__uid", lookup_expr="exact")
|
||||
provider_uid__in = CharInFilter(field_name="scan__provider__uid", lookup_expr="in")
|
||||
provider_uid__icontains = CharFilter(
|
||||
@@ -400,12 +370,6 @@ class ProviderFilter(FilterSet):
|
||||
choices=Provider.ProviderChoices.choices,
|
||||
lookup_expr="in",
|
||||
)
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="provider_groups__id", lookup_expr="exact", distinct=True
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="provider_groups__id", lookup_expr="in", distinct=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Provider
|
||||
@@ -431,16 +395,6 @@ class ProviderRelationshipFilterSet(FilterSet):
|
||||
provider_type__in = ChoiceInFilter(
|
||||
choices=Provider.ProviderChoices.choices, field_name="provider__provider"
|
||||
)
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
provider_uid = CharFilter(field_name="provider__uid", lookup_expr="exact")
|
||||
provider_uid__in = CharInFilter(field_name="provider__uid", lookup_expr="in")
|
||||
provider_uid__icontains = CharFilter(
|
||||
@@ -1047,16 +1001,6 @@ class FindingGroupSummaryFilter(_CheckTitleToCheckIdMixin, FilterSet):
|
||||
field_name="provider__provider", choices=Provider.ProviderChoices.choices
|
||||
)
|
||||
provider_type__in = CharInFilter(field_name="provider__provider", lookup_expr="in")
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = FindingGroupDailySummary
|
||||
@@ -1157,16 +1101,6 @@ class LatestFindingGroupSummaryFilter(_CheckTitleToCheckIdMixin, FilterSet):
|
||||
field_name="provider__provider", choices=Provider.ProviderChoices.choices
|
||||
)
|
||||
provider_type__in = CharInFilter(field_name="provider__provider", lookup_expr="in")
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = FindingGroupDailySummary
|
||||
@@ -1346,19 +1280,12 @@ class RoleFilter(FilterSet):
|
||||
}
|
||||
|
||||
|
||||
class ComplianceOverviewFilter(BaseScanProviderFilter):
|
||||
"""
|
||||
Keep provider filters in the schema while runtime filtering resolves scans first.
|
||||
|
||||
Compliance overview provider filters are applied to the latest completed scans
|
||||
in the viewset, then this filterset handles the remaining compliance fields.
|
||||
"""
|
||||
|
||||
class ComplianceOverviewFilter(FilterSet):
|
||||
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
|
||||
scan_id = UUIDFilter(field_name="scan_id")
|
||||
scan_id = UUIDFilter(field_name="scan_id", required=True)
|
||||
region = CharFilter(field_name="region")
|
||||
|
||||
class Meta(BaseScanProviderFilter.Meta):
|
||||
class Meta:
|
||||
model = ComplianceRequirementOverview
|
||||
fields = {
|
||||
"inserted_at": ["date", "gte", "lte"],
|
||||
@@ -1379,16 +1306,6 @@ class ScanSummaryFilter(FilterSet):
|
||||
provider_type__in = ChoiceInFilter(
|
||||
field_name="scan__provider__provider", choices=Provider.ProviderChoices.choices
|
||||
)
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="scan__provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="scan__provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
region = CharFilter(field_name="region")
|
||||
|
||||
class Meta:
|
||||
@@ -1412,16 +1329,6 @@ class DailySeveritySummaryFilter(FilterSet):
|
||||
provider_type__in = ChoiceInFilter(
|
||||
field_name="provider__provider", choices=Provider.ProviderChoices.choices
|
||||
)
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
date_from = DateFilter(method="filter_noop")
|
||||
date_to = DateFilter(method="filter_noop")
|
||||
|
||||
@@ -1678,16 +1585,6 @@ class ThreatScoreSnapshotFilter(FilterSet):
|
||||
choices=Provider.ProviderChoices.choices,
|
||||
lookup_expr="in",
|
||||
)
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
compliance_id = CharFilter(field_name="compliance_id", lookup_expr="exact")
|
||||
compliance_id__in = CharInFilter(field_name="compliance_id", lookup_expr="in")
|
||||
|
||||
@@ -1731,16 +1628,6 @@ class ResourceGroupOverviewFilter(FilterSet):
|
||||
choices=Provider.ProviderChoices.choices,
|
||||
lookup_expr="in",
|
||||
)
|
||||
provider_groups = UUIDFilter(
|
||||
field_name="scan__provider__provider_groups__id",
|
||||
lookup_expr="exact",
|
||||
distinct=True,
|
||||
)
|
||||
provider_groups__in = UUIDInFilter(
|
||||
field_name="scan__provider__provider_groups__id",
|
||||
lookup_expr="in",
|
||||
distinct=True,
|
||||
)
|
||||
resource_group = CharFilter(field_name="resource_group", lookup_expr="exact")
|
||||
resource_group__in = CharInFilter(field_name="resource_group", lookup_expr="in")
|
||||
|
||||
|
||||
@@ -1,35 +1,9 @@
|
||||
import logging
|
||||
import time
|
||||
|
||||
from django.core.handlers.asgi import ASGIRequest
|
||||
from django.db import connections
|
||||
|
||||
from config.custom_logging import BackendLogger
|
||||
|
||||
|
||||
class CloseDBConnectionsMiddleware:
|
||||
"""
|
||||
Close request-scoped DB connections at the end of each ASGI request.
|
||||
|
||||
Under the ASGI worker, connections opened by sync views are not released
|
||||
by Django's normal request-boundary cleanup, so they accumulate idle until
|
||||
Postgres runs out of slots. Only ASGI requests are handled; the sync WSGI
|
||||
test client manages its own connections and must be left alone.
|
||||
"""
|
||||
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
try:
|
||||
return self.get_response(request)
|
||||
finally:
|
||||
if isinstance(request, ASGIRequest):
|
||||
for conn in connections.all(initialized_only=True):
|
||||
if not conn.in_atomic_block:
|
||||
conn.close_if_unusable_or_obsolete()
|
||||
|
||||
|
||||
def extract_auth_info(request) -> dict:
|
||||
if getattr(request, "auth", None) is not None:
|
||||
tenant_id = request.auth.get("tenant_id", "N/A")
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
@@ -6,48 +5,9 @@ from allauth.socialaccount.models import SocialLogin
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from api.adapters import ProwlerSocialAccountAdapter
|
||||
from api.db_router import MainRouter
|
||||
from api.models import SAMLConfiguration
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
# Minimal, well-formed IdP metadata accepted by SAMLConfiguration._parse_metadata.
|
||||
VALID_METADATA = """<?xml version='1.0' encoding='UTF-8'?>
|
||||
<md:EntityDescriptor entityID='TEST' xmlns:md='urn:oasis:names:tc:SAML:2.0:metadata'>
|
||||
<md:IDPSSODescriptor WantAuthnRequestsSigned='false' protocolSupportEnumeration='urn:oasis:names:tc:SAML:2.0:protocol'>
|
||||
<md:KeyDescriptor use='signing'>
|
||||
<ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>FAKECERTDATA</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:SingleSignOnService Binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST' Location='https://idp.test/sso'/>
|
||||
</md:IDPSSODescriptor>
|
||||
</md:EntityDescriptor>
|
||||
"""
|
||||
|
||||
|
||||
def _saml_request(rf, organization_slug):
|
||||
"""Build an ACS request whose resolver_match carries the organization slug,
|
||||
mirroring how Django populates it after routing the SAML ACS URL."""
|
||||
request = rf.post(f"/api/v1/accounts/saml/{organization_slug}/acs/finish/")
|
||||
request.resolver_match = SimpleNamespace(
|
||||
kwargs={"organization_slug": organization_slug}
|
||||
)
|
||||
return request
|
||||
|
||||
|
||||
def _saml_sociallogin(user):
|
||||
sociallogin = MagicMock(spec=SocialLogin)
|
||||
sociallogin.account = MagicMock()
|
||||
sociallogin.provider = MagicMock()
|
||||
sociallogin.provider.id = "saml"
|
||||
sociallogin.account.extra_data = {}
|
||||
sociallogin.user = user
|
||||
sociallogin.connect = MagicMock()
|
||||
return sociallogin
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestProwlerSocialAccountAdapter:
|
||||
@@ -60,99 +20,26 @@ class TestProwlerSocialAccountAdapter:
|
||||
adapter = ProwlerSocialAccountAdapter()
|
||||
assert adapter.get_user_by_email("notfound@example.com") is None
|
||||
|
||||
def test_pre_social_login_links_member_of_saml_tenant(
|
||||
self, create_test_user, tenants_fixture, rf
|
||||
):
|
||||
"""A SAML login links to an existing account only when that user is
|
||||
already a member of the tenant that owns the asserted email domain."""
|
||||
def test_pre_social_login_links_existing_user(self, create_test_user, rf):
|
||||
adapter = ProwlerSocialAccountAdapter()
|
||||
# create_test_user (dev@prowler.com) is a member of tenant1.
|
||||
domain = create_test_user.email.rsplit("@", 1)[-1]
|
||||
SAMLConfiguration.objects.using(MainRouter.admin_db).create(
|
||||
email_domain=domain,
|
||||
metadata_xml=VALID_METADATA,
|
||||
tenant=tenants_fixture[0],
|
||||
)
|
||||
|
||||
sociallogin = _saml_sociallogin(create_test_user)
|
||||
adapter.pre_social_login(_saml_request(rf, domain), sociallogin)
|
||||
sociallogin = MagicMock(spec=SocialLogin)
|
||||
sociallogin.account = MagicMock()
|
||||
sociallogin.provider = MagicMock()
|
||||
sociallogin.provider.id = "saml"
|
||||
sociallogin.account.extra_data = {}
|
||||
sociallogin.user = create_test_user
|
||||
sociallogin.connect = MagicMock()
|
||||
|
||||
adapter.pre_social_login(rf.get("/"), sociallogin)
|
||||
|
||||
call_args = sociallogin.connect.call_args
|
||||
assert call_args is not None
|
||||
_, called_user = call_args[0]
|
||||
|
||||
called_request, called_user = call_args[0]
|
||||
assert called_request.path == "/"
|
||||
assert called_user.email == create_test_user.email
|
||||
|
||||
def test_pre_social_login_blocks_cross_tenant_takeover(
|
||||
self, create_test_user, tenants_fixture, rf
|
||||
):
|
||||
"""GHSA-h8m9-jgf8-vwvp: an attacker tenant that claims the victim's
|
||||
email domain must NOT be able to link to the victim's account, because
|
||||
the victim is not a member of the attacker's tenant."""
|
||||
adapter = ProwlerSocialAccountAdapter()
|
||||
domain = create_test_user.email.rsplit("@", 1)[-1]
|
||||
# tenant3 is the attacker tenant; create_test_user is NOT a member of it.
|
||||
attacker_tenant = tenants_fixture[2]
|
||||
assert not create_test_user.is_member_of_tenant(str(attacker_tenant.id))
|
||||
SAMLConfiguration.objects.using(MainRouter.admin_db).create(
|
||||
email_domain=domain,
|
||||
metadata_xml=VALID_METADATA,
|
||||
tenant=attacker_tenant,
|
||||
)
|
||||
|
||||
sociallogin = _saml_sociallogin(create_test_user)
|
||||
adapter.pre_social_login(_saml_request(rf, domain), sociallogin)
|
||||
|
||||
sociallogin.connect.assert_not_called()
|
||||
|
||||
def test_pre_social_login_blocks_domain_slug_mismatch(
|
||||
self, create_test_user, tenants_fixture, rf
|
||||
):
|
||||
"""The asserted email domain must match the ACS endpoint's slug, so an
|
||||
assertion cannot be replayed through a different tenant's endpoint."""
|
||||
adapter = ProwlerSocialAccountAdapter()
|
||||
domain = create_test_user.email.rsplit("@", 1)[-1]
|
||||
SAMLConfiguration.objects.using(MainRouter.admin_db).create(
|
||||
email_domain=domain,
|
||||
metadata_xml=VALID_METADATA,
|
||||
tenant=tenants_fixture[0],
|
||||
)
|
||||
|
||||
sociallogin = _saml_sociallogin(create_test_user)
|
||||
# Slug points at a different domain than the asserted email.
|
||||
adapter.pre_social_login(_saml_request(rf, "attacker.com"), sociallogin)
|
||||
|
||||
sociallogin.connect.assert_not_called()
|
||||
|
||||
def test_pre_social_login_blocks_when_no_saml_config(
|
||||
self, create_test_user, tenants_fixture, rf
|
||||
):
|
||||
"""No SAML configuration for the domain means nothing to link against."""
|
||||
adapter = ProwlerSocialAccountAdapter()
|
||||
domain = create_test_user.email.rsplit("@", 1)[-1]
|
||||
|
||||
sociallogin = _saml_sociallogin(create_test_user)
|
||||
adapter.pre_social_login(_saml_request(rf, domain), sociallogin)
|
||||
|
||||
sociallogin.connect.assert_not_called()
|
||||
|
||||
def test_pre_social_login_blocks_without_resolver_match(
|
||||
self, create_test_user, tenants_fixture, rf
|
||||
):
|
||||
"""Fail closed: if the request has no resolver_match we cannot bind the
|
||||
assertion to a tenant, so no linking happens."""
|
||||
adapter = ProwlerSocialAccountAdapter()
|
||||
domain = create_test_user.email.rsplit("@", 1)[-1]
|
||||
SAMLConfiguration.objects.using(MainRouter.admin_db).create(
|
||||
email_domain=domain,
|
||||
metadata_xml=VALID_METADATA,
|
||||
tenant=tenants_fixture[0],
|
||||
)
|
||||
|
||||
sociallogin = _saml_sociallogin(create_test_user)
|
||||
adapter.pre_social_login(rf.post("/"), sociallogin)
|
||||
|
||||
sociallogin.connect.assert_not_called()
|
||||
|
||||
def test_pre_social_login_no_link_if_email_missing(self, rf):
|
||||
adapter = ProwlerSocialAccountAdapter()
|
||||
|
||||
@@ -160,34 +47,13 @@ class TestProwlerSocialAccountAdapter:
|
||||
sociallogin.account = MagicMock()
|
||||
sociallogin.provider = MagicMock()
|
||||
sociallogin.user = MagicMock()
|
||||
sociallogin.user.email = ""
|
||||
sociallogin.provider.id = "saml"
|
||||
sociallogin.account.extra_data = {}
|
||||
sociallogin.connect = MagicMock()
|
||||
|
||||
adapter.pre_social_login(_saml_request(rf, "prowler.com"), sociallogin)
|
||||
|
||||
sociallogin.connect.assert_not_called()
|
||||
|
||||
def test_pre_social_login_non_saml_links_by_email(self, create_test_user, rf):
|
||||
"""Non-SAML providers (e.g. Google/GitHub) still link to an existing
|
||||
local account by email; the tenant binding only applies to SAML."""
|
||||
adapter = ProwlerSocialAccountAdapter()
|
||||
|
||||
sociallogin = MagicMock(spec=SocialLogin)
|
||||
sociallogin.account = MagicMock()
|
||||
sociallogin.provider = MagicMock()
|
||||
sociallogin.provider.id = "google"
|
||||
sociallogin.account.extra_data = {"email": create_test_user.email}
|
||||
sociallogin.user = create_test_user
|
||||
sociallogin.connect = MagicMock()
|
||||
|
||||
adapter.pre_social_login(rf.get("/"), sociallogin)
|
||||
|
||||
call_args = sociallogin.connect.call_args
|
||||
assert call_args is not None
|
||||
_, called_user = call_args[0]
|
||||
assert called_user.email == create_test_user.email
|
||||
sociallogin.connect.assert_not_called()
|
||||
|
||||
def test_save_user_saml_sets_session_flag(self, rf):
|
||||
adapter = ProwlerSocialAccountAdapter()
|
||||
|
||||
@@ -41,30 +41,3 @@ class TestBuildCeleryBrokerUrl:
|
||||
def test_invalid_scheme_raises_error(self):
|
||||
with pytest.raises(ValueError, match="Invalid VALKEY_SCHEME 'http'"):
|
||||
_build_celery_broker_url("http", "", "", "valkey", "6379", "0")
|
||||
|
||||
|
||||
class TestCeleryWorkerConcurrency:
|
||||
def _reimport_settings(self):
|
||||
"""Fresh import — importlib.reload() doesn't clear the module namespace,
|
||||
so an attribute set by a prior test would leak into the unset case."""
|
||||
import sys
|
||||
|
||||
sys.modules.pop("config.settings.celery", None)
|
||||
import config.settings.celery as celery_settings
|
||||
|
||||
return celery_settings
|
||||
|
||||
def test_unset_leaves_setting_absent(self, monkeypatch):
|
||||
monkeypatch.delenv("DJANGO_CELERY_WORKER_CONCURRENCY", raising=False)
|
||||
mod = self._reimport_settings()
|
||||
assert not hasattr(mod, "CELERY_WORKER_CONCURRENCY")
|
||||
|
||||
def test_explicit_value_applied(self, monkeypatch):
|
||||
monkeypatch.setenv("DJANGO_CELERY_WORKER_CONCURRENCY", "8")
|
||||
mod = self._reimport_settings()
|
||||
assert mod.CELERY_WORKER_CONCURRENCY == 8
|
||||
|
||||
def test_invalid_value_raises(self, monkeypatch):
|
||||
monkeypatch.setenv("DJANGO_CELERY_WORKER_CONCURRENCY", "not-a-number")
|
||||
with pytest.raises(ValueError):
|
||||
self._reimport_settings()
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from django.http import QueryDict
|
||||
from django.urls import reverse
|
||||
from django_celery_results.models import TaskResult
|
||||
from rest_framework import status
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.response import Response
|
||||
|
||||
from api.exceptions import (
|
||||
@@ -12,7 +8,7 @@ from api.exceptions import (
|
||||
TaskInProgressException,
|
||||
TaskNotFoundException,
|
||||
)
|
||||
from api.models import Provider, StateChoices, Task
|
||||
from api.models import StateChoices, Task
|
||||
from api.v1.serializers import TaskSerializer
|
||||
|
||||
|
||||
@@ -78,162 +74,6 @@ class PaginateByPkMixin:
|
||||
return self.get_paginated_response(serialized)
|
||||
|
||||
|
||||
class JsonApiFilterMixin:
|
||||
"""Shared helpers for manually applying django-filter to JSON:API params."""
|
||||
|
||||
jsonapi_filter_replace_dots = False
|
||||
|
||||
def _normalize_jsonapi_params(
|
||||
self,
|
||||
query_params,
|
||||
exclude_keys=None,
|
||||
replace_dots=None,
|
||||
):
|
||||
exclude_keys = exclude_keys or set()
|
||||
if replace_dots is None:
|
||||
replace_dots = self.jsonapi_filter_replace_dots
|
||||
|
||||
normalized = QueryDict(mutable=True)
|
||||
for key, values in query_params.lists():
|
||||
normalized_key = (
|
||||
key[7:-1] if key.startswith("filter[") and key.endswith("]") else key
|
||||
)
|
||||
if replace_dots:
|
||||
normalized_key = normalized_key.replace(".", "__")
|
||||
if normalized_key not in exclude_keys:
|
||||
normalized.setlist(normalized_key, values)
|
||||
return normalized
|
||||
|
||||
def _apply_filterset(
|
||||
self,
|
||||
queryset,
|
||||
filterset_class,
|
||||
exclude_keys=None,
|
||||
replace_dots=None,
|
||||
):
|
||||
normalized_params = self._normalize_jsonapi_params(
|
||||
self.request.query_params,
|
||||
exclude_keys=set(exclude_keys or []),
|
||||
replace_dots=replace_dots,
|
||||
)
|
||||
filterset = filterset_class(normalized_params, queryset=queryset)
|
||||
if not filterset.is_valid():
|
||||
raise ValidationError(filterset.errors)
|
||||
return filterset.qs
|
||||
|
||||
|
||||
class ProviderFilterParamsMixin(JsonApiFilterMixin):
|
||||
"""Shared extraction of provider filters from JSON:API query params."""
|
||||
|
||||
PROVIDER_FILTER_KEYS = frozenset(
|
||||
{
|
||||
"provider_id",
|
||||
"provider_id__in",
|
||||
"provider_type",
|
||||
"provider_type__in",
|
||||
"provider_groups",
|
||||
"provider_groups__in",
|
||||
}
|
||||
)
|
||||
PROVIDER_FILTER_DOT_ALIAS_KEYS = frozenset(
|
||||
{
|
||||
"provider_id.in",
|
||||
"provider_type.in",
|
||||
"provider_groups.in",
|
||||
}
|
||||
)
|
||||
PROVIDER_FILTER_QUERY_KEYS = PROVIDER_FILTER_KEYS | PROVIDER_FILTER_DOT_ALIAS_KEYS
|
||||
|
||||
def _csv_filter_values(self, value):
|
||||
return [item.strip() for item in value.split(",") if item.strip()]
|
||||
|
||||
def _validate_uuid_filter_values(self, field_name, values):
|
||||
try:
|
||||
for value in values:
|
||||
uuid.UUID(str(value))
|
||||
except (TypeError, ValueError, AttributeError):
|
||||
raise ValidationError({field_name: ["Enter a valid UUID."]})
|
||||
|
||||
def _has_provider_filters(self, include_dot_aliases=False):
|
||||
provider_filter_keys = (
|
||||
self.PROVIDER_FILTER_QUERY_KEYS
|
||||
if include_dot_aliases
|
||||
else self.PROVIDER_FILTER_KEYS
|
||||
)
|
||||
return any(
|
||||
self.request.query_params.get(f"filter[{key}]")
|
||||
for key in provider_filter_keys
|
||||
)
|
||||
|
||||
def _extract_provider_filters_from_params(
|
||||
self,
|
||||
*,
|
||||
validate_uuids=False,
|
||||
include_dot_aliases=False,
|
||||
):
|
||||
params = self.request.query_params
|
||||
filters = {}
|
||||
valid_provider_types = {
|
||||
choice[0] for choice in Provider.ProviderChoices.choices
|
||||
}
|
||||
|
||||
provider_id = params.get("filter[provider_id]")
|
||||
if provider_id:
|
||||
if validate_uuids:
|
||||
self._validate_uuid_filter_values("provider_id", [provider_id])
|
||||
filters["provider_id"] = provider_id
|
||||
|
||||
provider_id_in = params.get("filter[provider_id__in]")
|
||||
if include_dot_aliases:
|
||||
provider_id_in = provider_id_in or params.get("filter[provider_id.in]")
|
||||
if provider_id_in:
|
||||
values = self._csv_filter_values(provider_id_in)
|
||||
if validate_uuids:
|
||||
self._validate_uuid_filter_values("provider_id__in", values)
|
||||
filters["provider_id__in"] = values
|
||||
|
||||
provider_type = params.get("filter[provider_type]")
|
||||
if provider_type:
|
||||
if provider_type not in valid_provider_types:
|
||||
raise ValidationError(
|
||||
{"provider_type": f"Invalid choice: {provider_type}"}
|
||||
)
|
||||
filters["provider__provider"] = provider_type
|
||||
|
||||
provider_type_in = params.get("filter[provider_type__in]")
|
||||
if include_dot_aliases:
|
||||
provider_type_in = provider_type_in or params.get(
|
||||
"filter[provider_type.in]"
|
||||
)
|
||||
if provider_type_in:
|
||||
values = self._csv_filter_values(provider_type_in)
|
||||
invalid = [value for value in values if value not in valid_provider_types]
|
||||
if invalid:
|
||||
raise ValidationError(
|
||||
{"provider_type__in": f"Invalid choices: {', '.join(invalid)}"}
|
||||
)
|
||||
filters["provider__provider__in"] = values
|
||||
|
||||
provider_groups = params.get("filter[provider_groups]")
|
||||
if provider_groups:
|
||||
if validate_uuids:
|
||||
self._validate_uuid_filter_values("provider_groups", [provider_groups])
|
||||
filters["provider__provider_groups__id"] = provider_groups
|
||||
|
||||
provider_groups_in = params.get("filter[provider_groups__in]")
|
||||
if include_dot_aliases:
|
||||
provider_groups_in = provider_groups_in or params.get(
|
||||
"filter[provider_groups.in]"
|
||||
)
|
||||
if provider_groups_in:
|
||||
values = self._csv_filter_values(provider_groups_in)
|
||||
if validate_uuids:
|
||||
self._validate_uuid_filter_values("provider_groups__in", values)
|
||||
filters["provider__provider_groups__id__in"] = values
|
||||
|
||||
return filters
|
||||
|
||||
|
||||
class TaskManagementMixin:
|
||||
"""
|
||||
Mixin to manage task status checking.
|
||||
|
||||
@@ -228,13 +228,7 @@ from api.utils import (
|
||||
validate_invitation,
|
||||
)
|
||||
from api.uuid_utils import datetime_to_uuid7, uuid7_start
|
||||
from api.v1.mixins import (
|
||||
DisablePaginationMixin,
|
||||
JsonApiFilterMixin,
|
||||
PaginateByPkMixin,
|
||||
ProviderFilterParamsMixin,
|
||||
TaskManagementMixin,
|
||||
)
|
||||
from api.v1.mixins import DisablePaginationMixin, PaginateByPkMixin, TaskManagementMixin
|
||||
from api.v1.serializers import (
|
||||
AttackPathsCartographySchemaSerializer,
|
||||
AttackPathsCustomQueryRunRequestSerializer,
|
||||
@@ -767,10 +761,7 @@ class TenantFinishACSView(FinishACSView):
|
||||
try:
|
||||
check = SAMLDomainIndex.objects.get(email_domain=organization_slug)
|
||||
with rls_transaction(str(check.tenant_id)):
|
||||
saml_config = SAMLConfiguration.objects.select_related("tenant").get(
|
||||
tenant_id=str(check.tenant_id)
|
||||
)
|
||||
tenant = saml_config.tenant
|
||||
SAMLConfiguration.objects.get(tenant_id=str(check.tenant_id))
|
||||
social_app = SocialApp.objects.get(
|
||||
provider="saml", client_id=organization_slug
|
||||
)
|
||||
@@ -790,15 +781,6 @@ class TenantFinishACSView(FinishACSView):
|
||||
callback_url = env.str("AUTH_URL")
|
||||
return redirect(f"{callback_url}?sso_saml_failed=true")
|
||||
|
||||
requested_domain = organization_slug.lower()
|
||||
configured_domain = saml_config.email_domain.lower()
|
||||
email_domain = user.email.rsplit("@", 1)[-1].lower()
|
||||
if configured_domain != requested_domain or email_domain != configured_domain:
|
||||
logger.error("SAML email domain does not match requested organization")
|
||||
self._rollback_saml_user(request)
|
||||
callback_url = env.str("AUTH_URL")
|
||||
return redirect(f"{callback_url}?sso_saml_failed=true")
|
||||
|
||||
extra = social_account.extra_data
|
||||
user.first_name = (
|
||||
extra.get("firstName", [""])[0] if extra.get("firstName") else ""
|
||||
@@ -812,70 +794,67 @@ class TenantFinishACSView(FinishACSView):
|
||||
user.name = "N/A"
|
||||
user.save()
|
||||
|
||||
# Only remap roles when the IdP provides a userType attribute.
|
||||
# Without it, the user's current roles are left untouched.
|
||||
role_name = (
|
||||
extra.get("userType", [""])[0].strip() if extra.get("userType") else ""
|
||||
email_domain = user.email.split("@")[-1]
|
||||
tenant = (
|
||||
SAMLConfiguration.objects.using(MainRouter.admin_db)
|
||||
.get(email_domain=email_domain)
|
||||
.tenant
|
||||
)
|
||||
if role_name:
|
||||
with transaction.atomic(using=MainRouter.admin_db):
|
||||
role = (
|
||||
Role.objects.using(MainRouter.admin_db)
|
||||
.filter(name=role_name, tenant=tenant)
|
||||
.first()
|
||||
)
|
||||
|
||||
# Only skip mapping if it would remove the last MANAGE_ACCOUNT user
|
||||
remaining_manage_account_users = (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(role__manage_account=True, tenant_id=tenant.id)
|
||||
.exclude(user_id=user_id)
|
||||
.values("user")
|
||||
.distinct()
|
||||
.count()
|
||||
)
|
||||
user_has_manage_account = (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(
|
||||
role__manage_account=True,
|
||||
tenant_id=tenant.id,
|
||||
user_id=user_id,
|
||||
)
|
||||
.exists()
|
||||
)
|
||||
role_manage_account = role.manage_account if role else False
|
||||
would_remove_last_manage_account = (
|
||||
user_has_manage_account
|
||||
and remaining_manage_account_users == 0
|
||||
and not role_manage_account
|
||||
)
|
||||
role_name = (
|
||||
extra.get("userType", ["no_permissions"])[0].strip()
|
||||
if extra.get("userType")
|
||||
else "no_permissions"
|
||||
)
|
||||
role = (
|
||||
Role.objects.using(MainRouter.admin_db)
|
||||
.filter(name=role_name, tenant=tenant)
|
||||
.first()
|
||||
)
|
||||
|
||||
if not would_remove_last_manage_account:
|
||||
if role is None:
|
||||
# Roles auto-created from userType get read-only access:
|
||||
# visibility over all providers, no management permissions
|
||||
role, _ = Role.objects.using(MainRouter.admin_db).get_or_create(
|
||||
name=role_name,
|
||||
tenant=tenant,
|
||||
defaults={
|
||||
"manage_users": False,
|
||||
"manage_account": False,
|
||||
"manage_billing": False,
|
||||
"manage_providers": False,
|
||||
"manage_integrations": False,
|
||||
"manage_scans": False,
|
||||
"unlimited_visibility": True,
|
||||
},
|
||||
)
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).filter(
|
||||
user=user,
|
||||
tenant_id=tenant.id,
|
||||
).delete()
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
|
||||
user=user,
|
||||
role=role,
|
||||
tenant_id=tenant.id,
|
||||
)
|
||||
# Only skip mapping if it would remove the last MANAGE_ACCOUNT user
|
||||
remaining_manage_account_users = (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(role__manage_account=True, tenant_id=tenant.id)
|
||||
.exclude(user_id=user_id)
|
||||
.values("user")
|
||||
.distinct()
|
||||
.count()
|
||||
)
|
||||
user_has_manage_account = (
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db)
|
||||
.filter(role__manage_account=True, tenant_id=tenant.id, user_id=user_id)
|
||||
.exists()
|
||||
)
|
||||
role_manage_account = role.manage_account if role else False
|
||||
would_remove_last_manage_account = (
|
||||
user_has_manage_account
|
||||
and remaining_manage_account_users == 0
|
||||
and not role_manage_account
|
||||
)
|
||||
|
||||
if not would_remove_last_manage_account:
|
||||
if role is None:
|
||||
role = Role.objects.using(MainRouter.admin_db).create(
|
||||
name=role_name,
|
||||
tenant=tenant,
|
||||
manage_users=False,
|
||||
manage_account=False,
|
||||
manage_billing=False,
|
||||
manage_providers=False,
|
||||
manage_integrations=False,
|
||||
manage_scans=False,
|
||||
unlimited_visibility=False,
|
||||
)
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).filter(
|
||||
user=user,
|
||||
tenant_id=tenant.id,
|
||||
).delete()
|
||||
UserRoleRelationship.objects.using(MainRouter.admin_db).create(
|
||||
user=user,
|
||||
role=role,
|
||||
tenant_id=tenant.id,
|
||||
)
|
||||
membership, _ = Membership.objects.using(MainRouter.admin_db).get_or_create(
|
||||
user=user,
|
||||
tenant=tenant,
|
||||
@@ -1889,7 +1868,7 @@ class ProviderViewSet(DisablePaginationMixin, BaseRLSViewSet):
|
||||
description=(
|
||||
"Download a specific compliance report as an OCSF JSON file. "
|
||||
"Only universal frameworks that declare an output configuration "
|
||||
"produce this artifact (currently 'dora_2022_2554' and 'csa_ccm_4.0'); any "
|
||||
"produce this artifact (currently 'dora' and 'csa_ccm_4.0'); any "
|
||||
"other framework returns 404."
|
||||
),
|
||||
parameters=[
|
||||
@@ -1898,7 +1877,7 @@ class ProviderViewSet(DisablePaginationMixin, BaseRLSViewSet):
|
||||
type=str,
|
||||
location=OpenApiParameter.PATH,
|
||||
required=True,
|
||||
description="The compliance report name, like 'dora_2022_2554'",
|
||||
description="The compliance report name, like 'dora'",
|
||||
),
|
||||
],
|
||||
responses={
|
||||
@@ -4567,19 +4546,15 @@ class RoleProviderGroupRelationshipView(RelationshipView, BaseRLSViewSet):
|
||||
@extend_schema_view(
|
||||
list=extend_schema(
|
||||
tags=["Compliance Overview"],
|
||||
summary="List compliance overviews",
|
||||
description=(
|
||||
"Retrieve compliance overview data for a scan. When provider filters "
|
||||
"are provided, the endpoint uses the latest completed scan for each "
|
||||
"matching provider."
|
||||
),
|
||||
summary="List compliance overviews for a scan",
|
||||
description="Retrieve an overview of all the compliance in a given scan.",
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="filter[scan_id]",
|
||||
required=False,
|
||||
required=True,
|
||||
type=OpenApiTypes.UUID,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Related scan ID. Required unless a provider filter is provided.",
|
||||
description="Related scan ID.",
|
||||
),
|
||||
],
|
||||
responses={
|
||||
@@ -4594,23 +4569,19 @@ class RoleProviderGroupRelationshipView(RelationshipView, BaseRLSViewSet):
|
||||
description="Compliance overviews generation task failed"
|
||||
),
|
||||
},
|
||||
filters=True,
|
||||
),
|
||||
metadata=extend_schema(
|
||||
tags=["Compliance Overview"],
|
||||
summary="Retrieve metadata values from compliance overviews",
|
||||
description=(
|
||||
"Fetch unique metadata values from compliance overviews. This is useful "
|
||||
"for dynamic filtering. When provider filters are provided, metadata is "
|
||||
"computed from the latest completed scan for each matching provider."
|
||||
),
|
||||
description="Fetch unique metadata values from a set of compliance overviews. This is useful for dynamic "
|
||||
"filtering.",
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="filter[scan_id]",
|
||||
required=False,
|
||||
required=True,
|
||||
type=OpenApiTypes.UUID,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Related scan ID. Required unless a provider filter is provided.",
|
||||
description="Related scan ID.",
|
||||
),
|
||||
],
|
||||
responses={
|
||||
@@ -4625,24 +4596,19 @@ class RoleProviderGroupRelationshipView(RelationshipView, BaseRLSViewSet):
|
||||
description="Compliance overviews generation task failed"
|
||||
),
|
||||
},
|
||||
filters=True,
|
||||
),
|
||||
requirements=extend_schema(
|
||||
tags=["Compliance Overview"],
|
||||
summary="List compliance requirements overview",
|
||||
description=(
|
||||
"Retrieve a detailed overview of compliance requirements, grouped by "
|
||||
"compliance framework. This endpoint provides requirement-level details "
|
||||
"and aggregates status across regions. When provider filters are provided, "
|
||||
"the endpoint uses the latest completed scan for each matching provider."
|
||||
),
|
||||
summary="List compliance requirements overview for a scan",
|
||||
description="Retrieve a detailed overview of compliance requirements in a given scan, grouped by compliance "
|
||||
"framework. This endpoint provides requirement-level details and aggregates status across regions.",
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="filter[scan_id]",
|
||||
required=False,
|
||||
required=True,
|
||||
type=OpenApiTypes.UUID,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Related scan ID. Required unless a provider filter is provided.",
|
||||
description="Related scan ID.",
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="filter[compliance_id]",
|
||||
@@ -4701,10 +4667,7 @@ class RoleProviderGroupRelationshipView(RelationshipView, BaseRLSViewSet):
|
||||
@method_decorator(CACHE_DECORATOR, name="list")
|
||||
@method_decorator(CACHE_DECORATOR, name="requirements")
|
||||
@method_decorator(CACHE_DECORATOR, name="attributes")
|
||||
class ComplianceOverviewViewSet(
|
||||
ProviderFilterParamsMixin, BaseRLSViewSet, TaskManagementMixin
|
||||
):
|
||||
jsonapi_filter_replace_dots = True
|
||||
class ComplianceOverviewViewSet(BaseRLSViewSet, TaskManagementMixin):
|
||||
pagination_class = ComplianceOverviewPagination
|
||||
queryset = ComplianceRequirementOverview.objects.all()
|
||||
serializer_class = ComplianceOverviewSerializer
|
||||
@@ -4718,22 +4681,28 @@ class ComplianceOverviewViewSet(
|
||||
required_permissions = []
|
||||
|
||||
def get_queryset(self):
|
||||
if getattr(self, "swagger_fake_view", False):
|
||||
return ComplianceRequirementOverview.objects.none()
|
||||
|
||||
role = get_role(self.request.user, self.request.tenant_id)
|
||||
unlimited_visibility = getattr(
|
||||
role, Permissions.UNLIMITED_VISIBILITY.value, False
|
||||
)
|
||||
|
||||
base_queryset = ComplianceRequirementOverview.objects.filter(
|
||||
tenant_id=self.request.tenant_id
|
||||
)
|
||||
|
||||
if unlimited_visibility:
|
||||
return base_queryset
|
||||
base_queryset = self.filter_queryset(
|
||||
ComplianceRequirementOverview.objects.filter(
|
||||
tenant_id=self.request.tenant_id
|
||||
)
|
||||
)
|
||||
else:
|
||||
providers = Provider.objects.filter(
|
||||
provider_groups__in=role.provider_groups.all()
|
||||
).distinct()
|
||||
base_queryset = self.filter_queryset(
|
||||
ComplianceRequirementOverview.objects.filter(
|
||||
tenant_id=self.request.tenant_id, scan__provider__in=providers
|
||||
)
|
||||
)
|
||||
|
||||
return base_queryset.filter(scan__provider__in=get_providers(role))
|
||||
return base_queryset
|
||||
|
||||
def get_serializer_class(self):
|
||||
if hasattr(self, "response_serializer_class"):
|
||||
@@ -4771,72 +4740,6 @@ class ComplianceOverviewViewSet(
|
||||
|
||||
return summaries
|
||||
|
||||
def _validate_scan_selection(self, scan_id, has_provider_filters):
|
||||
if scan_id and has_provider_filters:
|
||||
raise ValidationError(
|
||||
[
|
||||
{
|
||||
"detail": "Use either filter[scan_id] or provider filters.",
|
||||
"status": 400,
|
||||
"source": {"pointer": "filter[scan_id]"},
|
||||
"code": "invalid",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
if scan_id:
|
||||
self._validate_uuid_filter_values("scan_id", [scan_id])
|
||||
return
|
||||
|
||||
if has_provider_filters:
|
||||
return
|
||||
|
||||
raise ValidationError(
|
||||
[
|
||||
{
|
||||
"detail": "This query parameter is required unless a provider filter is provided.",
|
||||
"status": 400,
|
||||
"source": {"pointer": "filter[scan_id]"},
|
||||
"code": "required",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
def _latest_scan_ids_for_provider_filters(self):
|
||||
role = get_role(self.request.user, self.request.tenant_id)
|
||||
scans = Scan.all_objects.filter(
|
||||
tenant_id=self.request.tenant_id,
|
||||
state=StateChoices.COMPLETED,
|
||||
)
|
||||
|
||||
if not getattr(role, Permissions.UNLIMITED_VISIBILITY.value, False):
|
||||
scans = scans.filter(provider__in=get_providers(role))
|
||||
|
||||
provider_filters = self._extract_provider_filters_from_params(
|
||||
validate_uuids=True,
|
||||
include_dot_aliases=True,
|
||||
)
|
||||
if provider_filters:
|
||||
scans = scans.filter(**provider_filters)
|
||||
|
||||
return list(
|
||||
scans.order_by("provider_id", "-inserted_at")
|
||||
.distinct("provider_id")
|
||||
.values_list("id", flat=True)
|
||||
)
|
||||
|
||||
def _filtered_queryset_for_latest_provider_scans(self, latest_scan_ids=None):
|
||||
if latest_scan_ids is None:
|
||||
latest_scan_ids = self._latest_scan_ids_for_provider_filters()
|
||||
queryset = self.get_queryset().filter(scan_id__in=latest_scan_ids)
|
||||
# Provider filters stay on the filterset for OpenAPI docs, but runtime
|
||||
# filtering happens on Scan first so compliance queries use scan IDs.
|
||||
return self._apply_filterset(
|
||||
queryset,
|
||||
self.filterset_class,
|
||||
exclude_keys=self.PROVIDER_FILTER_KEYS | {"scan_id"},
|
||||
)
|
||||
|
||||
def _get_compliance_template(self, *, provider=None, scan_id=None):
|
||||
"""Return the compliance template for the given provider or scan."""
|
||||
if provider is None and scan_id is not None:
|
||||
@@ -4952,36 +4855,6 @@ class ComplianceOverviewViewSet(
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
|
||||
def _task_response_for_latest_provider_scans(self, latest_scan_ids):
|
||||
for scan_id in latest_scan_ids:
|
||||
task_response = self._task_response_if_running(str(scan_id))
|
||||
if task_response:
|
||||
return task_response
|
||||
return None
|
||||
|
||||
def _latest_provider_scan_ids_without_data(self, latest_scan_ids):
|
||||
data_presence_queryset = self.get_queryset().filter(scan_id__in=latest_scan_ids)
|
||||
scan_ids_with_data = {
|
||||
str(scan_id)
|
||||
for scan_id in data_presence_queryset.values_list(
|
||||
"scan_id", flat=True
|
||||
).distinct()
|
||||
}
|
||||
return [
|
||||
scan_id
|
||||
for scan_id in latest_scan_ids
|
||||
if str(scan_id) not in scan_ids_with_data
|
||||
]
|
||||
|
||||
def _task_response_for_latest_provider_scans_without_data(
|
||||
self,
|
||||
latest_scan_ids,
|
||||
):
|
||||
scan_ids_to_check = self._latest_provider_scan_ids_without_data(
|
||||
latest_scan_ids,
|
||||
)
|
||||
return self._task_response_for_latest_provider_scans(scan_ids_to_check)
|
||||
|
||||
def _list_with_region_filter(self, scan_id, region_filter):
|
||||
"""
|
||||
Fall back to detailed ComplianceRequirementOverview query when region filter is applied.
|
||||
@@ -5022,25 +4895,8 @@ class ComplianceOverviewViewSet(
|
||||
|
||||
return Response(data)
|
||||
|
||||
def _list_with_latest_provider_filters(self):
|
||||
latest_scan_ids = self._latest_scan_ids_for_provider_filters()
|
||||
queryset = self._filtered_queryset_for_latest_provider_scans(latest_scan_ids)
|
||||
data = self._aggregate_compliance_overview(queryset)
|
||||
task_response = self._task_response_for_latest_provider_scans_without_data(
|
||||
latest_scan_ids,
|
||||
)
|
||||
if task_response:
|
||||
return task_response
|
||||
|
||||
return Response(data)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
scan_id = request.query_params.get("filter[scan_id]")
|
||||
has_provider_filters = self._has_provider_filters(include_dot_aliases=True)
|
||||
self._validate_scan_selection(scan_id, has_provider_filters)
|
||||
|
||||
if has_provider_filters:
|
||||
return self._list_with_latest_provider_filters()
|
||||
|
||||
# Specific scan requested - use optimized summaries with region support
|
||||
region_filter = request.query_params.get(
|
||||
@@ -5086,34 +4942,33 @@ class ComplianceOverviewViewSet(
|
||||
@action(detail=False, methods=["get"], url_name="metadata")
|
||||
def metadata(self, request):
|
||||
scan_id = request.query_params.get("filter[scan_id]")
|
||||
has_provider_filters = self._has_provider_filters(include_dot_aliases=True)
|
||||
self._validate_scan_selection(scan_id, has_provider_filters)
|
||||
|
||||
latest_scan_ids = None
|
||||
if has_provider_filters:
|
||||
latest_scan_ids = self._latest_scan_ids_for_provider_filters()
|
||||
queryset = self._filtered_queryset_for_latest_provider_scans(
|
||||
latest_scan_ids
|
||||
if not scan_id:
|
||||
raise ValidationError(
|
||||
[
|
||||
{
|
||||
"detail": "This query parameter is required.",
|
||||
"status": 400,
|
||||
"source": {"pointer": "filter[scan_id]"},
|
||||
"code": "required",
|
||||
}
|
||||
]
|
||||
)
|
||||
else:
|
||||
queryset = self._apply_filterset(self.get_queryset(), self.filterset_class)
|
||||
|
||||
regions = list(
|
||||
queryset.values_list("region", flat=True).order_by("region").distinct()
|
||||
self.get_queryset()
|
||||
.filter(scan_id=scan_id)
|
||||
.values_list("region", flat=True)
|
||||
.order_by("region")
|
||||
.distinct()
|
||||
)
|
||||
result = {"regions": regions}
|
||||
|
||||
task_response = None
|
||||
if has_provider_filters:
|
||||
task_response = self._task_response_for_latest_provider_scans_without_data(
|
||||
latest_scan_ids,
|
||||
)
|
||||
elif not regions:
|
||||
task_response = self._task_response_if_running(scan_id)
|
||||
if task_response:
|
||||
return task_response
|
||||
if regions:
|
||||
serializer = self.get_serializer(data=result)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
if has_provider_filters and task_response:
|
||||
task_response = self._task_response_if_running(scan_id)
|
||||
if task_response:
|
||||
return task_response
|
||||
|
||||
serializer = self.get_serializer(data=result)
|
||||
@@ -5123,10 +4978,19 @@ class ComplianceOverviewViewSet(
|
||||
@action(detail=False, methods=["get"], url_name="requirements")
|
||||
def requirements(self, request):
|
||||
scan_id = request.query_params.get("filter[scan_id]")
|
||||
has_provider_filters = self._has_provider_filters(include_dot_aliases=True)
|
||||
compliance_id = request.query_params.get("filter[compliance_id]")
|
||||
|
||||
self._validate_scan_selection(scan_id, has_provider_filters)
|
||||
if not scan_id:
|
||||
raise ValidationError(
|
||||
[
|
||||
{
|
||||
"detail": "This query parameter is required.",
|
||||
"status": 400,
|
||||
"source": {"pointer": "filter[scan_id]"},
|
||||
"code": "required",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
if not compliance_id:
|
||||
raise ValidationError(
|
||||
@@ -5139,16 +5003,7 @@ class ComplianceOverviewViewSet(
|
||||
}
|
||||
]
|
||||
)
|
||||
latest_scan_ids = None
|
||||
if has_provider_filters:
|
||||
latest_scan_ids = self._latest_scan_ids_for_provider_filters()
|
||||
filtered_queryset = self._filtered_queryset_for_latest_provider_scans(
|
||||
latest_scan_ids
|
||||
)
|
||||
else:
|
||||
filtered_queryset = self._apply_filterset(
|
||||
self.get_queryset(), self.filterset_class
|
||||
)
|
||||
filtered_queryset = self.filter_queryset(self.get_queryset())
|
||||
|
||||
all_requirements = filtered_queryset.values(
|
||||
"requirement_id",
|
||||
@@ -5207,22 +5062,13 @@ class ComplianceOverviewViewSet(
|
||||
requirements_summary, many=True
|
||||
)
|
||||
|
||||
task_response = None
|
||||
if has_provider_filters:
|
||||
task_response = self._task_response_for_latest_provider_scans_without_data(
|
||||
latest_scan_ids,
|
||||
)
|
||||
elif not requirements_summary:
|
||||
task_response = self._task_response_if_running(scan_id)
|
||||
if task_response:
|
||||
return task_response
|
||||
|
||||
if has_provider_filters and task_response:
|
||||
return task_response
|
||||
|
||||
if requirements_summary:
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
task_response = self._task_response_if_running(scan_id)
|
||||
if task_response:
|
||||
return task_response
|
||||
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
@action(detail=False, methods=["get"], url_name="attributes")
|
||||
@@ -5461,7 +5307,7 @@ class ComplianceOverviewViewSet(
|
||||
),
|
||||
)
|
||||
@method_decorator(CACHE_DECORATOR, name="list")
|
||||
class OverviewViewSet(ProviderFilterParamsMixin, BaseRLSViewSet):
|
||||
class OverviewViewSet(BaseRLSViewSet):
|
||||
queryset = ScanSummary.objects.all()
|
||||
http_method_names = ["get"]
|
||||
ordering = ["-inserted_at"]
|
||||
@@ -5578,6 +5424,18 @@ class OverviewViewSet(ProviderFilterParamsMixin, BaseRLSViewSet):
|
||||
tenant_id=tenant_id, scan_id__in=latest_scan_ids
|
||||
)
|
||||
|
||||
def _normalize_jsonapi_params(self, query_params, exclude_keys=None):
|
||||
"""Convert JSON:API filter params (filter[X]) to flat params (X)."""
|
||||
exclude_keys = exclude_keys or set()
|
||||
normalized = QueryDict(mutable=True)
|
||||
for key, values in query_params.lists():
|
||||
normalized_key = (
|
||||
key[7:-1] if key.startswith("filter[") and key.endswith("]") else key
|
||||
)
|
||||
if normalized_key not in exclude_keys:
|
||||
normalized.setlist(normalized_key, values)
|
||||
return normalized
|
||||
|
||||
def _ensure_allowed_providers(self):
|
||||
"""Populate allowed providers for RBAC-aware queries once per request."""
|
||||
if getattr(self, "_providers_initialized", False):
|
||||
@@ -5597,6 +5455,15 @@ class OverviewViewSet(ProviderFilterParamsMixin, BaseRLSViewSet):
|
||||
return queryset.filter(**provider_filter)
|
||||
return queryset
|
||||
|
||||
def _apply_filterset(self, queryset, filterset_class, exclude_keys=None):
|
||||
normalized_params = self._normalize_jsonapi_params(
|
||||
self.request.query_params, exclude_keys=set(exclude_keys or [])
|
||||
)
|
||||
filterset = filterset_class(normalized_params, queryset=queryset)
|
||||
if not filterset.is_valid():
|
||||
raise ValidationError(filterset.errors)
|
||||
return filterset.qs
|
||||
|
||||
def _latest_scan_ids_for_allowed_providers(self, tenant_id, provider_filters=None):
|
||||
provider_filter = self._get_provider_filter()
|
||||
queryset = Scan.all_objects.filter(
|
||||
@@ -5610,6 +5477,40 @@ class OverviewViewSet(ProviderFilterParamsMixin, BaseRLSViewSet):
|
||||
.values_list("id", flat=True)
|
||||
)
|
||||
|
||||
def _extract_provider_filters_from_params(self):
|
||||
"""Extract and validate provider filters from query params."""
|
||||
params = self.request.query_params
|
||||
filters = {}
|
||||
valid_provider_types = {c[0] for c in Provider.ProviderChoices.choices}
|
||||
|
||||
provider_id = params.get("filter[provider_id]")
|
||||
if provider_id:
|
||||
filters["provider_id"] = provider_id
|
||||
|
||||
provider_id_in = params.get("filter[provider_id__in]")
|
||||
if provider_id_in:
|
||||
filters["provider_id__in"] = provider_id_in.split(",")
|
||||
|
||||
provider_type = params.get("filter[provider_type]")
|
||||
if provider_type:
|
||||
if provider_type not in valid_provider_types:
|
||||
raise ValidationError(
|
||||
{"provider_type": f"Invalid choice: {provider_type}"}
|
||||
)
|
||||
filters["provider__provider"] = provider_type
|
||||
|
||||
provider_type_in = params.get("filter[provider_type__in]")
|
||||
if provider_type_in:
|
||||
types = provider_type_in.split(",")
|
||||
invalid = [t for t in types if t not in valid_provider_types]
|
||||
if invalid:
|
||||
raise ValidationError(
|
||||
{"provider_type__in": f"Invalid choices: {', '.join(invalid)}"}
|
||||
)
|
||||
filters["provider__provider__in"] = types
|
||||
|
||||
return filters
|
||||
|
||||
@action(detail=False, methods=["get"], url_name="providers")
|
||||
def providers(self, request):
|
||||
tenant_id = self.request.tenant_id
|
||||
@@ -5680,11 +5581,15 @@ class OverviewViewSet(ProviderFilterParamsMixin, BaseRLSViewSet):
|
||||
tenant_id = self.request.tenant_id
|
||||
providers_qs = Provider.objects.filter(tenant_id=tenant_id)
|
||||
|
||||
self._ensure_allowed_providers()
|
||||
if hasattr(self, "allowed_providers"):
|
||||
providers_qs = providers_qs.filter(
|
||||
id__in=self.allowed_providers.values("id")
|
||||
)
|
||||
allowed_ids = list(self.allowed_providers.values_list("id", flat=True))
|
||||
if not allowed_ids:
|
||||
overview = []
|
||||
return Response(
|
||||
self.get_serializer(overview, many=True).data,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
providers_qs = providers_qs.filter(id__in=allowed_ids)
|
||||
|
||||
overview = (
|
||||
providers_qs.values("provider")
|
||||
@@ -5900,41 +5805,29 @@ class OverviewViewSet(ProviderFilterParamsMixin, BaseRLSViewSet):
|
||||
description="Retrieve a specific snapshot by ID. If not provided, returns latest snapshots.",
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="filter[provider_id]",
|
||||
name="provider_id",
|
||||
type=OpenApiTypes.UUID,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Filter by specific provider ID",
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="filter[provider_id__in]",
|
||||
name="provider_id__in",
|
||||
type=OpenApiTypes.STR,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Filter by multiple provider IDs (comma-separated UUIDs)",
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="filter[provider_type]",
|
||||
name="provider_type",
|
||||
type=OpenApiTypes.STR,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Filter by provider type (aws, azure, gcp, etc.)",
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="filter[provider_type__in]",
|
||||
name="provider_type__in",
|
||||
type=OpenApiTypes.STR,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Filter by multiple provider types (comma-separated)",
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="filter[provider_groups]",
|
||||
type=OpenApiTypes.UUID,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Filter by provider group ID",
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="filter[provider_groups__in]",
|
||||
type=OpenApiTypes.STR,
|
||||
location=OpenApiParameter.QUERY,
|
||||
description="Filter by multiple provider group IDs (comma-separated UUIDs)",
|
||||
),
|
||||
],
|
||||
)
|
||||
@action(detail=False, methods=["get"], url_name="threatscore")
|
||||
@@ -6276,8 +6169,6 @@ class OverviewViewSet(ProviderFilterParamsMixin, BaseRLSViewSet):
|
||||
"provider_id__in",
|
||||
"provider_type",
|
||||
"provider_type__in",
|
||||
"provider_groups",
|
||||
"provider_groups__in",
|
||||
}
|
||||
filtered_queryset = self._apply_filterset(
|
||||
base_queryset, CategoryOverviewFilter, exclude_keys=provider_filter_keys
|
||||
@@ -6347,8 +6238,6 @@ class OverviewViewSet(ProviderFilterParamsMixin, BaseRLSViewSet):
|
||||
"provider_id__in",
|
||||
"provider_type",
|
||||
"provider_type__in",
|
||||
"provider_groups",
|
||||
"provider_groups__in",
|
||||
}
|
||||
filtered_queryset = self._apply_filterset(
|
||||
base_queryset,
|
||||
@@ -7399,7 +7288,7 @@ SEVERITY_ORDER_REVERSE = {v: k for k, v in SEVERITY_ORDER.items()}
|
||||
),
|
||||
retrieve=extend_schema(exclude=True),
|
||||
)
|
||||
class FindingGroupViewSet(JsonApiFilterMixin, BaseRLSViewSet):
|
||||
class FindingGroupViewSet(BaseRLSViewSet):
|
||||
"""
|
||||
ViewSet for Finding Groups - aggregates findings by check_id.
|
||||
|
||||
@@ -7415,7 +7304,6 @@ class FindingGroupViewSet(JsonApiFilterMixin, BaseRLSViewSet):
|
||||
queryset = FindingGroupDailySummary.objects.all()
|
||||
serializer_class = FindingGroupSerializer
|
||||
filterset_class = FindingGroupFilter
|
||||
jsonapi_filter_replace_dots = True
|
||||
filter_backends = [
|
||||
jsonapi_filters.QueryParameterValidationFilter,
|
||||
jsonapi_filters.OrderingFilter,
|
||||
@@ -7466,6 +7354,18 @@ class FindingGroupViewSet(JsonApiFilterMixin, BaseRLSViewSet):
|
||||
|
||||
return queryset
|
||||
|
||||
def _normalize_jsonapi_params(self, query_params):
|
||||
"""Convert JSON:API filter params (filter[X]) to flat params (X)."""
|
||||
normalized = QueryDict(mutable=True)
|
||||
for key, values in query_params.lists():
|
||||
normalized_key = (
|
||||
key[7:-1] if key.startswith("filter[") and key.endswith("]") else key
|
||||
)
|
||||
# Convert JSON:API dot notation to Django double underscore
|
||||
normalized_key = normalized_key.replace(".", "__")
|
||||
normalized.setlist(normalized_key, values)
|
||||
return normalized
|
||||
|
||||
@extend_schema(exclude=True)
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
raise MethodNotAllowed(method="GET")
|
||||
@@ -8584,10 +8484,9 @@ class FindingGroupViewSet(JsonApiFilterMixin, BaseRLSViewSet):
|
||||
|
||||
This endpoint returns finding groups without requiring date filters,
|
||||
automatically using the latest available data per check_id.
|
||||
Provider, provider group, check, and computed filters are still supported.
|
||||
All other filters (provider_id, provider_type, check_id) are still supported.
|
||||
""",
|
||||
tags=["Finding Groups"],
|
||||
filters=True,
|
||||
)
|
||||
@action(detail=False, methods=["get"], url_name="latest")
|
||||
def latest(self, request):
|
||||
|
||||
@@ -49,7 +49,6 @@ INSTALLED_APPS = [
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"api.middleware.CloseDBConnectionsMiddleware",
|
||||
"django_guid.middleware.guid_middleware",
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
|
||||
@@ -3,8 +3,6 @@ import multiprocessing
|
||||
import os
|
||||
import threading
|
||||
|
||||
from uvicorn_worker import UvicornWorker
|
||||
|
||||
from config.env import env
|
||||
|
||||
# Ensure the environment variable for Django settings is set
|
||||
@@ -14,7 +12,6 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.django.production")
|
||||
import django # noqa: E402
|
||||
|
||||
django.setup()
|
||||
|
||||
from api.compliance import warm_compliance_caches # noqa: E402
|
||||
from config.django.production import LOGGING as DJANGO_LOGGERS, DEBUG # noqa: E402
|
||||
from config.custom_logging import BackendLogger # noqa: E402
|
||||
@@ -22,37 +19,21 @@ from config.custom_logging import BackendLogger # noqa: E402
|
||||
BIND_ADDRESS = env("DJANGO_BIND_ADDRESS", default="127.0.0.1")
|
||||
PORT = env("DJANGO_PORT", default=8080)
|
||||
|
||||
|
||||
class ProwlerUvicornWorker(UvicornWorker):
|
||||
CONFIG_KWARGS = {
|
||||
# Keep-alive idle timeout. Must exceed the load balancer idle timeout.
|
||||
"timeout_keep_alive": env.int("GUNICORN_KEEPALIVE", default=75),
|
||||
"loop": "uvloop",
|
||||
"lifespan": "off", # Django ASGIHandler doesn't handle lifespan scopes
|
||||
}
|
||||
|
||||
|
||||
# Required so SSE endpoints can keep the event loop alive while waiting for events
|
||||
worker_class = env(
|
||||
"DJANGO_WORKER_CLASS",
|
||||
default="config.guniconf.ProwlerUvicornWorker",
|
||||
)
|
||||
|
||||
# Server settings
|
||||
bind = f"{BIND_ADDRESS}:{PORT}"
|
||||
|
||||
workers = env.int("DJANGO_WORKERS", default=multiprocessing.cpu_count() * 2 + 1)
|
||||
reload = DEBUG
|
||||
|
||||
# Native ASGI worker (gunicorn 24+). Required so SSE endpoints can keep the
|
||||
# event loop alive while waiting for events.
|
||||
worker_class = env("DJANGO_WORKER_CLASS", default="asgi")
|
||||
|
||||
# Preload the application before forking workers in production: the app is
|
||||
# imported once in the master and workers fork from it. In development, disable
|
||||
# preload so the server restarts on code changes.
|
||||
preload_app = not DEBUG
|
||||
|
||||
# Worker timeout in seconds. Increased from the default 30s to handle requests
|
||||
# that may take longer, such as complex API operations.
|
||||
timeout = env.int("GUNICORN_TIMEOUT", default=120)
|
||||
|
||||
# Logging
|
||||
logconfig_dict = DJANGO_LOGGERS
|
||||
gunicorn_logger = logging.getLogger(BackendLogger.GUNICORN)
|
||||
|
||||
@@ -53,8 +53,3 @@ CELERY_TASK_TRACK_STARTED = True
|
||||
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True
|
||||
|
||||
CELERY_DEADLOCK_ATTEMPTS = env.int("DJANGO_CELERY_DEADLOCK_ATTEMPTS", default=5)
|
||||
|
||||
# Opt-in override for Celery's prefork pool size. When unset, Celery falls back
|
||||
# to its default (os.cpu_count()).
|
||||
if "DJANGO_CELERY_WORKER_CONCURRENCY" in env.ENVIRON:
|
||||
CELERY_WORKER_CONCURRENCY = env.int("DJANGO_CELERY_WORKER_CONCURRENCY")
|
||||
|
||||
@@ -76,8 +76,6 @@ IGNORED_EXCEPTIONS = [
|
||||
# PowerShell Errors in User Authentication
|
||||
"Microsoft Teams User Auth connection failed: Please check your permissions and try again.",
|
||||
"Exchange Online User Auth connection failed: Please check your permissions and try again.",
|
||||
# ASGI: Client disconnected before the response finished (health-check probes on /health/live)
|
||||
"RequestAborted",
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ def generate_outputs_task(scan_id: str, provider_id: str, tenant_id: str):
|
||||
|
||||
# Per-framework exporters in `COMPLIANCE_CLASS_MAP` consume the legacy bulk.
|
||||
frameworks_bulk = Compliance.get_bulk(provider_type)
|
||||
# Universal-only frameworks (top-level JSONs like `dora_2022_2554.json`) are emitted
|
||||
# Universal-only frameworks (top-level JSONs like `dora.json`) are emitted
|
||||
# via `process_universal_compliance_frameworks` below.
|
||||
universal_bulk = get_prowler_provider_compliance(provider_type)
|
||||
universal_only_names = {
|
||||
@@ -650,7 +650,7 @@ def generate_outputs_task(scan_id: str, provider_id: str, tenant_id: str):
|
||||
writer.batch_write_data_to_file(**extra)
|
||||
writer._data.clear()
|
||||
|
||||
# Universal-only frameworks (e.g. `dora_2022_2554.json`).
|
||||
# Universal-only frameworks (e.g. `dora.json`).
|
||||
if universal_only_names:
|
||||
process_universal_compliance_frameworks(
|
||||
input_compliance_frameworks=universal_only_names,
|
||||
|
||||
@@ -357,8 +357,6 @@ constraints = [
|
||||
{ name = "uritemplate", specifier = "==4.2.0" },
|
||||
{ name = "urllib3", specifier = "==2.7.0" },
|
||||
{ name = "uuid6", specifier = "==2024.7.10" },
|
||||
{ name = "uvicorn", specifier = "==0.49.0" },
|
||||
{ name = "uvloop", specifier = "==0.22.1" },
|
||||
{ name = "vine", specifier = "==5.1.0" },
|
||||
{ name = "vulture", specifier = "==2.14" },
|
||||
{ name = "wcwidth", specifier = "==0.5.3" },
|
||||
@@ -4576,8 +4574,6 @@ dependencies = [
|
||||
{ name = "sentry-sdk", extra = ["django"] },
|
||||
{ name = "sqlparse" },
|
||||
{ name = "uuid6" },
|
||||
{ name = "uvicorn-worker" },
|
||||
{ name = "uvloop" },
|
||||
{ name = "werkzeug" },
|
||||
{ name = "xmlsec" },
|
||||
]
|
||||
@@ -4643,8 +4639,6 @@ requires-dist = [
|
||||
{ name = "sentry-sdk", extras = ["django"], specifier = "==2.56.0" },
|
||||
{ name = "sqlparse", specifier = "==0.5.5" },
|
||||
{ name = "uuid6", specifier = "==2024.7.10" },
|
||||
{ name = "uvicorn-worker", specifier = "==0.4.0" },
|
||||
{ name = "uvloop", specifier = "==0.22.1" },
|
||||
{ name = "werkzeug", specifier = "==3.1.7" },
|
||||
{ name = "xmlsec", specifier = "==1.3.17" },
|
||||
]
|
||||
@@ -5849,52 +5843,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/3e/4ae6af487ce5781ed71d5fe10aca72e7cbc4d4f45afc31b120287082a8dd/uuid6-2024.7.10-py3-none-any.whl", hash = "sha256:93432c00ba403751f722829ad21759ff9db051dea140bf81493271e8e4dd18b7", size = 6376, upload-time = "2024-07-10T16:39:36.148Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.49.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c4/1f/fa18009dea8469069cca78a4e877a008ab78f08b064bfc9ab891579077ff/uvicorn-0.49.0.tar.gz", hash = "sha256:ebf4271aa580d9de97f93192d4595176df6e91f9aae919ca73e4fc07df1e66a3", size = 91284, upload-time = "2026-06-03T22:01:30.448Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/88/fa/e1388bbcf24ef3274f45c0c1c7b501fd14971037c1b6ee23610553307497/uvicorn-0.49.0-py3-none-any.whl", hash = "sha256:ba3d14c3ee7e41c6c654c46c9eb489d33213cdd30aa1696eab1374337c13f68f", size = 71376, upload-time = "2026-06-03T22:01:29.037Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn-worker"
|
||||
version = "0.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "gunicorn" },
|
||||
{ name = "uvicorn" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/80/59/9101b9c0680fd80e9d26c07deb822a5d18a324339fcf9cd017885ee808ad/uvicorn_worker-0.4.0.tar.gz", hash = "sha256:8ee5306070d8f38dce124adce488c3c0b50f20cf0c0222b12c66188da7214493", size = 9361, upload-time = "2025-09-20T10:47:01.218Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/90/25/09cd7a90c8bb7fb693be0d6704fccd5f9778d5513214b7a01cc4a94ff314/uvicorn_worker-0.4.0-py3-none-any.whl", hash = "sha256:e2ed952cef976f5e9e429d7269640bbcafbd36c80aa80f1003c8c77a6797abde", size = 5364, upload-time = "2025-09-20T10:46:59.776Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvloop"
|
||||
version = "0.22.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9", size = 1352420, upload-time = "2025-10-16T22:16:21.187Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/73/c4e271b3bce59724e291465cc936c37758886a4868787da0278b3b56b905/uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77", size = 748677, upload-time = "2025-10-16T22:16:22.558Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/94/9fb7fad2f824d25f8ecac0d70b94d0d48107ad5ece03769a9c543444f78a/uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21", size = 3753819, upload-time = "2025-10-16T22:16:23.903Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/4f/256aca690709e9b008b7108bc85fba619a2bc37c6d80743d18abad16ee09/uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702", size = 3804529, upload-time = "2025-10-16T22:16:25.246Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/74/03c05ae4737e871923d21a76fe28b6aad57f5c03b6e6bfcfa5ad616013e4/uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733", size = 3621267, upload-time = "2025-10-16T22:16:26.819Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/be/f8e590fe61d18b4a92070905497aec4c0e64ae1761498cad09023f3f4b3e/uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473", size = 3723105, upload-time = "2025-10-16T22:16:28.252Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vine"
|
||||
version = "5.1.0"
|
||||
|
||||
@@ -16,6 +16,7 @@ from typing import Optional
|
||||
from prowler.lib.logger import logger
|
||||
from lib.models import ConnectivityGraph
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# JSON output
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -438,34 +438,6 @@ mainConfig:
|
||||
# Minimum number of Availability Zones that an ELBv2 must be in
|
||||
elbv2_min_azs: 2
|
||||
|
||||
# AWS Post-Quantum TLS Configuration
|
||||
# aws.acmpca_certificate_authority_pqc_key_algorithm
|
||||
acmpca_pqc_key_algorithms:
|
||||
- "ML_DSA_44"
|
||||
- "ML_DSA_65"
|
||||
- "ML_DSA_87"
|
||||
# aws.cloudfront_distributions_pqc_tls_enabled
|
||||
cloudfront_pqc_min_protocol_versions:
|
||||
- "TLSv1.3_2025"
|
||||
# aws.apigateway_domain_name_pqc_tls_enabled
|
||||
apigateway_pqc_tls_allowed_policies:
|
||||
- "SecurityPolicy_TLS13_1_2_FIPS_PFS_PQ_2025_09"
|
||||
- "SecurityPolicy_TLS13_1_2_PFS_PQ_2025_09"
|
||||
- "SecurityPolicy_TLS13_1_2_PQ_2025_09"
|
||||
|
||||
# AWS Post-Quantum SSH Key Exchange Configuration
|
||||
# aws.transfer_server_pqc_ssh_kex_enabled
|
||||
transfer_pqc_ssh_allowed_policies:
|
||||
- "TransferSecurityPolicy-2025-03"
|
||||
- "TransferSecurityPolicy-FIPS-2025-03"
|
||||
- "TransferSecurityPolicy-AS2Restricted-2025-07"
|
||||
|
||||
|
||||
# aws.rolesanywhere_trust_anchor_pqc_pki
|
||||
rolesanywhere_pqc_pca_key_algorithms:
|
||||
- "ML_DSA_44"
|
||||
- "ML_DSA_65"
|
||||
- "ML_DSA_87"
|
||||
|
||||
# AWS Secrets Configuration
|
||||
# Patterns to ignore in the secrets checks
|
||||
|
||||
@@ -11,7 +11,8 @@ data:
|
||||
{{- else }}
|
||||
AUTH_URL: {{ .Values.ui.authUrl | quote }}
|
||||
{{- end }}
|
||||
UI_API_BASE_URL: "http://{{ include "prowler.fullname" . }}-api:{{ .Values.api.service.port }}/api/v1"
|
||||
UI_API_DOCS_URL: "http://{{ include "prowler.fullname" . }}-api:{{ .Values.api.service.port }}/api/v1/docs"
|
||||
API_BASE_URL: "http://{{ include "prowler.fullname" . }}-api:{{ .Values.api.service.port }}/api/v1"
|
||||
NEXT_PUBLIC_API_BASE_URL: "http://{{ include "prowler.fullname" . }}-api:{{ .Values.api.service.port }}/api/v1"
|
||||
NEXT_PUBLIC_API_DOCS_URL: "http://{{ include "prowler.fullname" . }}-api:{{ .Values.api.service.port }}/api/v1/docs"
|
||||
AUTH_TRUST_HOST: "true"
|
||||
UI_PORT: {{ .Values.ui.service.port | quote }}
|
||||
|
||||
@@ -21,8 +21,8 @@ fullnameOverride: ""
|
||||
|
||||
secrets:
|
||||
SITE_URL: http://localhost:3000
|
||||
UI_API_BASE_URL: http://prowler-api:8080/api/v1
|
||||
UI_API_DOCS_URL: http://prowler-api:8080/api/v1/docs
|
||||
API_BASE_URL: http://prowler-api:8080/api/v1
|
||||
NEXT_PUBLIC_API_DOCS_URL: http://prowler-api:8080/api/v1/docs
|
||||
AUTH_TRUST_HOST: True
|
||||
UI_PORT: 3000
|
||||
# openssl rand -base64 32
|
||||
|
||||
@@ -10,6 +10,11 @@ from dash import dcc, html
|
||||
from dash.dependencies import Input, Output
|
||||
|
||||
from dashboard.config import folder_path_overview
|
||||
from dashboard.lib.cloud_promo import (
|
||||
cloud_promo_card,
|
||||
cloud_tour_modal,
|
||||
register_cloud_promo_callbacks,
|
||||
)
|
||||
from prowler.config.config import orange_color
|
||||
from prowler.lib.banner import print_banner
|
||||
|
||||
@@ -20,7 +25,7 @@ print_banner()
|
||||
print(
|
||||
f"{Fore.GREEN}Loading all CSV files from the folder {folder_path_overview} ...\n{Style.RESET_ALL}"
|
||||
)
|
||||
cli.show_server_banner = lambda *x: click.echo(
|
||||
cli.show_server_banner = lambda *_: click.echo(
|
||||
f"{Fore.YELLOW}NOTE:{Style.RESET_ALL} If you are using {Fore.GREEN}{Style.BRIGHT}Prowler Cloud{Style.RESET_ALL} with the S3 integration or that integration \nfrom {Fore.CYAN}{Style.BRIGHT}Prowler CLI{Style.RESET_ALL} and you want to use your data from your S3 bucket,\nrun: `{orange_color}aws s3 cp s3://<your-bucket>/output/csv ./output --recursive{Style.RESET_ALL}`\nand then run `prowler dashboard` again to load the new files."
|
||||
)
|
||||
|
||||
@@ -136,6 +141,8 @@ dashboard.layout = html.Div(
|
||||
],
|
||||
className="grid custom-grid 2xl:custom-grid-large h-screen",
|
||||
),
|
||||
# Prowler Cloud product tour (image-only experience).
|
||||
cloud_tour_modal(),
|
||||
],
|
||||
className="h-screen mx-auto",
|
||||
)
|
||||
@@ -157,20 +164,7 @@ def update_nav_bar(pathname):
|
||||
),
|
||||
html.Nav(
|
||||
[
|
||||
html.A(
|
||||
[
|
||||
html.Span(
|
||||
[
|
||||
html.Img(src="assets/favicon.ico", className="w-5"),
|
||||
"Subscribe to Prowler Cloud",
|
||||
],
|
||||
className="flex items-center gap-x-3 text-white",
|
||||
),
|
||||
],
|
||||
href="https://prowler.com/",
|
||||
target="_blank",
|
||||
className="block p-3 uppercase text-xs hover:bg-prowler-stone-950 hover:border-r-4 hover:border-solid hover:border-prowler-lime",
|
||||
),
|
||||
cloud_promo_card(),
|
||||
html.Ul(generate_help_menu(), className=""),
|
||||
],
|
||||
className="flex flex-col gap-y-6 mt-auto",
|
||||
@@ -178,3 +172,7 @@ def update_nav_bar(pathname):
|
||||
],
|
||||
className="flex flex-col bg-prowler-stone-900 py-7 h-full",
|
||||
)
|
||||
|
||||
|
||||
# Wire the Prowler Cloud product tour open/close/navigation callbacks.
|
||||
register_cloud_promo_callbacks(dashboard)
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
/* Prowler Cloud promo: sidebar hero + product tour modal.
|
||||
Styled to match the new Prowler Cloud app (cool-dark surface + mint accent),
|
||||
intentionally distinct from the warm stone sidebar so it stands out. */
|
||||
|
||||
:root {
|
||||
--cloud-bg: #0a0e16;
|
||||
--cloud-bg-2: #111a2b;
|
||||
--cloud-mint: #6ee7b7;
|
||||
--cloud-mint-2: #2dd4bf;
|
||||
--cloud-ink: #e6f0ef;
|
||||
--cloud-muted: #9fb1c4;
|
||||
}
|
||||
|
||||
/* ---------- Sidebar hero card ---------- */
|
||||
.cloud-promo-card-wrap {
|
||||
padding: 0 0.75rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.cloud-promo-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
padding: 0.95rem 0.95rem 0.85rem;
|
||||
border-radius: 14px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
color: var(--cloud-ink);
|
||||
background:
|
||||
radial-gradient(120% 120% at 0% 0%, rgba(45, 212, 191, 0.18) 0%, transparent 55%),
|
||||
linear-gradient(160deg, var(--cloud-bg-2) 0%, var(--cloud-bg) 100%);
|
||||
border: 1px solid rgba(110, 231, 183, 0.28);
|
||||
box-shadow: 0 10px 24px -14px rgba(45, 212, 191, 0.55);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
|
||||
}
|
||||
|
||||
.cloud-promo-card:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: rgba(110, 231, 183, 0.6);
|
||||
box-shadow: 0 16px 30px -12px rgba(45, 212, 191, 0.7);
|
||||
}
|
||||
|
||||
/* Soft sheen sweep on hover. */
|
||||
.cloud-promo-card::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, 0.08) 50%, transparent 70%);
|
||||
transform: translateX(-120%);
|
||||
transition: transform 0.6s ease;
|
||||
}
|
||||
.cloud-promo-card:hover::after {
|
||||
transform: translateX(120%);
|
||||
}
|
||||
|
||||
.cloud-promo-eyebrow {
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--cloud-mint);
|
||||
}
|
||||
|
||||
.cloud-promo-title {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.25;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.cloud-promo-cta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
margin-top: 0.15rem;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
color: var(--cloud-mint);
|
||||
}
|
||||
|
||||
.cloud-promo-arrow {
|
||||
transition: transform 0.18s ease;
|
||||
}
|
||||
.cloud-promo-card:hover .cloud-promo-arrow {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
/* ---------- Tour modal ---------- */
|
||||
.cloud-tour-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.cloud-tour-backdrop {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(4, 7, 12, 0.74);
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cloud-tour-dialog {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: min(960px, 100%);
|
||||
max-height: 92vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 18px;
|
||||
background: linear-gradient(180deg, var(--cloud-bg-2) 0%, var(--cloud-bg) 100%);
|
||||
border: 1px solid rgba(110, 231, 183, 0.22);
|
||||
box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.85);
|
||||
animation: cloud-tour-pop 0.22s ease;
|
||||
}
|
||||
|
||||
@keyframes cloud-tour-pop {
|
||||
from { opacity: 0; transform: translateY(10px) scale(0.985); }
|
||||
to { opacity: 1; transform: translateY(0) scale(1); }
|
||||
}
|
||||
|
||||
.cloud-tour-close {
|
||||
position: absolute;
|
||||
top: 0.75rem;
|
||||
right: 0.75rem;
|
||||
z-index: 2;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: none;
|
||||
border-radius: 9px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
color: var(--cloud-ink);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
.cloud-tour-close:hover {
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
|
||||
.cloud-tour-stage {
|
||||
padding: 1.4rem 1.4rem 0;
|
||||
background:
|
||||
radial-gradient(80% 60% at 50% 0%, rgba(45, 212, 191, 0.12) 0%, transparent 60%);
|
||||
}
|
||||
|
||||
.cloud-tour-image {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
/* Fixed 2:1 frame keeps the stage height identical across slides, while the
|
||||
viewport cap guarantees the caption + nav controls always stay visible
|
||||
(never clipped by the dialog's max-height). Tour images are pre-composited
|
||||
to 2000x1000 (2:1), so the ratio is honored with no cropping. */
|
||||
aspect-ratio: 2 / 1;
|
||||
max-width: 100%;
|
||||
max-height: 48vh;
|
||||
width: auto;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
box-shadow: 0 24px 50px -24px rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
.cloud-tour-caption {
|
||||
padding: 1.1rem 1.6rem 0.4rem;
|
||||
}
|
||||
|
||||
.cloud-tour-eyebrow {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: var(--cloud-mint);
|
||||
}
|
||||
|
||||
.cloud-tour-title {
|
||||
margin: 0.35rem 0 0.4rem;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.cloud-tour-text {
|
||||
margin: 0;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.5;
|
||||
color: var(--cloud-muted);
|
||||
max-width: 60ch;
|
||||
/* Reserve ~3 lines so captions of different lengths don't shift height. */
|
||||
min-height: 4.3rem;
|
||||
}
|
||||
|
||||
a.cloud-tour-cta {
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-top: 0.9rem;
|
||||
padding: 0.6rem 1.1rem;
|
||||
border-radius: 10px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
color: #04231d;
|
||||
background: linear-gradient(135deg, var(--cloud-mint) 0%, var(--cloud-mint-2) 100%);
|
||||
box-shadow: 0 12px 24px -12px rgba(45, 212, 191, 0.8);
|
||||
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
a.cloud-tour-cta:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 16px 30px -12px rgba(45, 212, 191, 0.95);
|
||||
}
|
||||
|
||||
.cloud-tour-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 0.9rem 1.6rem 1.4rem;
|
||||
}
|
||||
|
||||
.cloud-tour-nav {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1;
|
||||
color: var(--cloud-ink);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
transition: background 0.15s ease, border-color 0.15s ease;
|
||||
}
|
||||
.cloud-tour-nav:hover {
|
||||
background: rgba(110, 231, 183, 0.14);
|
||||
border-color: rgba(110, 231, 183, 0.5);
|
||||
}
|
||||
|
||||
.cloud-tour-dots {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.cloud-tour-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.22);
|
||||
transition: background 0.15s ease, transform 0.15s ease;
|
||||
}
|
||||
|
||||
.cloud-tour-dot--active {
|
||||
background: linear-gradient(135deg, var(--cloud-mint) 0%, var(--cloud-mint-2) 100%);
|
||||
transform: scale(1.25);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.cloud-tour-title { font-size: 1.15rem; }
|
||||
.cloud-tour-stage { padding: 1rem 1rem 0; }
|
||||
.cloud-tour-caption { padding: 0.9rem 1rem 0.3rem; }
|
||||
.cloud-tour-controls { padding: 0.8rem 1rem 1.1rem; }
|
||||
}
|
||||
|
After Width: | Height: | Size: 284 KiB |
|
After Width: | Height: | Size: 398 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 393 KiB |
|
After Width: | Height: | Size: 289 KiB |
|
After Width: | Height: | Size: 249 KiB |
|
After Width: | Height: | Size: 213 KiB |
|
After Width: | Height: | Size: 86 KiB |
@@ -0,0 +1,328 @@
|
||||
"""Prowler Cloud promo: sidebar hero + image-only product tour.
|
||||
|
||||
Drives CLI dashboard users toward Prowler Cloud. The sidebar shows a catchy,
|
||||
on-brand hero card; clicking it opens a modal that walks through the real
|
||||
Prowler Cloud experience using product screenshots.
|
||||
|
||||
The visual styling lives in ``dashboard/assets/cloud-promo.css`` (Dash loads
|
||||
every CSS file under ``assets/`` automatically, so this does not depend on the
|
||||
precompiled Tailwind bundle).
|
||||
"""
|
||||
|
||||
from dash import dcc, html
|
||||
from dash.dependencies import Input, Output, State
|
||||
|
||||
# Where every CTA points. Single source of truth so links stay consistent.
|
||||
CLOUD_URL = "https://prowler.com/"
|
||||
|
||||
# Ordered product tour. Each slide is one real Prowler Cloud screenshot plus a
|
||||
# short, benefit-led caption. The last slide carries the closing call to action.
|
||||
TOUR_SLIDES = [
|
||||
{
|
||||
"image": "/assets/images/cloud/tour-1-overview.png",
|
||||
"eyebrow": "01 · Overview",
|
||||
"title": "Your whole cloud, one view",
|
||||
"text": (
|
||||
"Prowler ThreatScore, severity breakdown, resource inventory and "
|
||||
"attack surface — thousands of findings, prioritized at a glance."
|
||||
),
|
||||
},
|
||||
{
|
||||
"image": "/assets/images/cloud/tour-2-attack-paths.png",
|
||||
"eyebrow": "02 · Attack Paths",
|
||||
"title": "See the attack path before they do",
|
||||
"text": (
|
||||
"Visualize how attackers chain misconfigurations across roles, "
|
||||
"policies and identities to reach your crown jewels."
|
||||
),
|
||||
},
|
||||
{
|
||||
"image": "/assets/images/cloud/tour-3-lighthouse.png",
|
||||
"eyebrow": "03 · Lighthouse AI",
|
||||
"title": "Ask your cloud anything",
|
||||
"text": (
|
||||
"Lighthouse AI + MCP delivers autonomous triage, prioritization and "
|
||||
"remediation — risk answers in plain English, not spreadsheets."
|
||||
),
|
||||
},
|
||||
{
|
||||
"image": "/assets/images/cloud/tour-4-scans.png",
|
||||
"eyebrow": "04 · Continuous scanning",
|
||||
"title": "Scan every account, on a schedule",
|
||||
"text": (
|
||||
"Onboard whole organizations and scan all your AWS, Azure, GCP, "
|
||||
"M365 and Kubernetes accounts at once, with full history and trends."
|
||||
),
|
||||
},
|
||||
{
|
||||
"image": "/assets/images/cloud/tour-5-compliance.png",
|
||||
"eyebrow": "05 · Compliance",
|
||||
"title": "50+ frameworks, always live",
|
||||
"text": (
|
||||
"CIS, NIST, PCI DSS, ISO 27001, HIPAA, SOC 2, ENS and more — scored "
|
||||
"continuously with one-click evidence export."
|
||||
),
|
||||
},
|
||||
{
|
||||
"image": "/assets/images/cloud/tour-6-integrations.png",
|
||||
"eyebrow": "06 · Integrations",
|
||||
"title": "Plugs into your stack",
|
||||
"text": (
|
||||
"Jira, Slack, AWS Security Hub, Amazon S3, SAML SSO and RBAC — push "
|
||||
"findings where your team already works."
|
||||
),
|
||||
},
|
||||
{
|
||||
"image": "/assets/images/cloud/tour-7-alerts.png",
|
||||
"eyebrow": "07 · Alerts",
|
||||
"title": "Stay ahead with smart alerts",
|
||||
"text": (
|
||||
"Get notified the moment findings match your conditions — daily "
|
||||
"digests or real-time, routed to the people who need them."
|
||||
),
|
||||
},
|
||||
{
|
||||
"image": "/assets/images/cloud/tour-8-import.png",
|
||||
"eyebrow": "From CLI to Cloud",
|
||||
"title": "Bring what you already have",
|
||||
"text": (
|
||||
"Already scanning with the Prowler CLI? Import your existing findings "
|
||||
"into Prowler Cloud in one click — no rescan, no lost history."
|
||||
),
|
||||
"cta": "Start free on Prowler Cloud",
|
||||
},
|
||||
]
|
||||
|
||||
# Component ids reused by the layout and the callbacks.
|
||||
TRIGGER_ID = "cloud-promo-trigger"
|
||||
CLOSE_ID = "cloud-tour-close"
|
||||
BACKDROP_ID = "cloud-tour-backdrop"
|
||||
PREV_ID = "cloud-tour-prev"
|
||||
NEXT_ID = "cloud-tour-next"
|
||||
OVERLAY_ID = "cloud-tour-overlay"
|
||||
OPEN_STORE_ID = "cloud-tour-open"
|
||||
INDEX_STORE_ID = "cloud-tour-index"
|
||||
|
||||
_OVERLAY_HIDDEN = {"display": "none"}
|
||||
_OVERLAY_VISIBLE = {"display": "flex"}
|
||||
|
||||
|
||||
def next_tour_state(trigger_id: str, is_open: bool, index: int, total: int):
|
||||
"""Pure reducer for the tour modal.
|
||||
|
||||
Returns the next ``(is_open, index)`` given which control fired. Kept free of
|
||||
Dash so the navigation logic is unit-testable in isolation.
|
||||
"""
|
||||
if total <= 0:
|
||||
return False, 0
|
||||
if trigger_id == TRIGGER_ID:
|
||||
return True, 0
|
||||
if trigger_id in (CLOSE_ID, BACKDROP_ID):
|
||||
return False, index
|
||||
if trigger_id == NEXT_ID:
|
||||
return is_open, (index + 1) % total
|
||||
if trigger_id == PREV_ID:
|
||||
return is_open, (index - 1) % total
|
||||
return is_open, index
|
||||
|
||||
|
||||
def cloud_promo_card() -> html.Div:
|
||||
"""Catchy, on-brand sidebar hero. Click opens the product tour."""
|
||||
return html.Div(
|
||||
html.Div(
|
||||
[
|
||||
html.Span("Prowler Cloud", className="cloud-promo-eyebrow"),
|
||||
html.Span(
|
||||
"Your cloud, continuously secured.",
|
||||
className="cloud-promo-title",
|
||||
),
|
||||
html.Span(
|
||||
[
|
||||
"See it in action",
|
||||
html.Span("→", className="cloud-promo-arrow"),
|
||||
],
|
||||
className="cloud-promo-cta",
|
||||
),
|
||||
],
|
||||
className="cloud-promo-card",
|
||||
id=TRIGGER_ID,
|
||||
n_clicks=0,
|
||||
),
|
||||
className="cloud-promo-card-wrap",
|
||||
)
|
||||
|
||||
|
||||
def _slide_dots(total: int) -> list:
|
||||
return [
|
||||
html.Span(className="cloud-tour-dot", id={"type": "cloud-tour-dot", "index": i})
|
||||
for i in range(total)
|
||||
]
|
||||
|
||||
|
||||
def cloud_tour_modal() -> html.Div:
|
||||
"""Root-level modal that plays the image-only Prowler Cloud tour."""
|
||||
first = TOUR_SLIDES[0]
|
||||
total = len(TOUR_SLIDES)
|
||||
return html.Div(
|
||||
[
|
||||
dcc.Store(id=OPEN_STORE_ID, data=False),
|
||||
dcc.Store(id=INDEX_STORE_ID, data=0),
|
||||
html.Div(
|
||||
[
|
||||
html.Div(
|
||||
id=BACKDROP_ID, className="cloud-tour-backdrop", n_clicks=0
|
||||
),
|
||||
html.Div(
|
||||
[
|
||||
html.Button(
|
||||
"✕",
|
||||
id=CLOSE_ID,
|
||||
className="cloud-tour-close",
|
||||
n_clicks=0,
|
||||
**{"aria-label": "Close tour"},
|
||||
),
|
||||
html.Div(
|
||||
html.Img(
|
||||
id="cloud-tour-image",
|
||||
src=first["image"],
|
||||
className="cloud-tour-image",
|
||||
alt="Prowler Cloud product screenshot",
|
||||
),
|
||||
className="cloud-tour-stage",
|
||||
),
|
||||
html.Div(
|
||||
[
|
||||
html.Span(
|
||||
first["eyebrow"],
|
||||
id="cloud-tour-eyebrow",
|
||||
className="cloud-tour-eyebrow",
|
||||
),
|
||||
html.H3(
|
||||
first["title"],
|
||||
id="cloud-tour-title",
|
||||
className="cloud-tour-title",
|
||||
),
|
||||
html.P(
|
||||
first["text"],
|
||||
id="cloud-tour-text",
|
||||
className="cloud-tour-text",
|
||||
),
|
||||
html.A(
|
||||
first.get("cta", "Start free on Prowler Cloud"),
|
||||
id="cloud-tour-cta",
|
||||
href=CLOUD_URL,
|
||||
target="_blank",
|
||||
className="cloud-tour-cta",
|
||||
style={"display": "none"},
|
||||
),
|
||||
],
|
||||
className="cloud-tour-caption",
|
||||
),
|
||||
html.Div(
|
||||
[
|
||||
html.Button(
|
||||
"‹",
|
||||
id=PREV_ID,
|
||||
className="cloud-tour-nav",
|
||||
n_clicks=0,
|
||||
**{"aria-label": "Previous"},
|
||||
),
|
||||
html.Div(
|
||||
_slide_dots(total),
|
||||
id="cloud-tour-dots",
|
||||
className="cloud-tour-dots",
|
||||
),
|
||||
html.Button(
|
||||
"›",
|
||||
id=NEXT_ID,
|
||||
className="cloud-tour-nav",
|
||||
n_clicks=0,
|
||||
**{"aria-label": "Next"},
|
||||
),
|
||||
],
|
||||
className="cloud-tour-controls",
|
||||
),
|
||||
],
|
||||
className="cloud-tour-dialog",
|
||||
),
|
||||
],
|
||||
id=OVERLAY_ID,
|
||||
className="cloud-tour-overlay",
|
||||
style=_OVERLAY_HIDDEN,
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def register_cloud_promo_callbacks(app) -> None:
|
||||
"""Wire the tour open/close/navigation into a Dash app."""
|
||||
|
||||
@app.callback(
|
||||
Output(OPEN_STORE_ID, "data"),
|
||||
Output(INDEX_STORE_ID, "data"),
|
||||
Input(TRIGGER_ID, "n_clicks"),
|
||||
Input(CLOSE_ID, "n_clicks"),
|
||||
Input(BACKDROP_ID, "n_clicks"),
|
||||
Input(PREV_ID, "n_clicks"),
|
||||
Input(NEXT_ID, "n_clicks"),
|
||||
State(OPEN_STORE_ID, "data"),
|
||||
State(INDEX_STORE_ID, "data"),
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def _drive_tour(_t, _c, _b, _p, _n, is_open, index):
|
||||
from dash import ctx
|
||||
from dash.exceptions import PreventUpdate
|
||||
|
||||
# The trigger button lives inside the dynamically rendered sidebar, so it
|
||||
# appears after the initial load. Ignore the spurious fire when a control
|
||||
# merely mounts (n_clicks 0/None) — only react to real clicks.
|
||||
if not ctx.triggered or not ctx.triggered[0]["value"]:
|
||||
raise PreventUpdate
|
||||
trigger_id = ctx.triggered_id
|
||||
return next_tour_state(
|
||||
trigger_id, bool(is_open), int(index or 0), len(TOUR_SLIDES)
|
||||
)
|
||||
|
||||
@app.callback(
|
||||
Output(OVERLAY_ID, "style"),
|
||||
Output("cloud-tour-image", "src"),
|
||||
Output("cloud-tour-eyebrow", "children"),
|
||||
Output("cloud-tour-title", "children"),
|
||||
Output("cloud-tour-text", "children"),
|
||||
Output("cloud-tour-cta", "children"),
|
||||
Output("cloud-tour-cta", "style"),
|
||||
Output("cloud-tour-dots", "children"),
|
||||
Input(OPEN_STORE_ID, "data"),
|
||||
Input(INDEX_STORE_ID, "data"),
|
||||
)
|
||||
def _render_tour(is_open, index):
|
||||
index = int(index or 0) % len(TOUR_SLIDES)
|
||||
slide = TOUR_SLIDES[index]
|
||||
overlay_style = _OVERLAY_VISIBLE if is_open else _OVERLAY_HIDDEN
|
||||
cta_label = slide.get("cta")
|
||||
# Always occupy the CTA box (reserve space) so the dialog height stays
|
||||
# constant across slides; only its visibility changes.
|
||||
cta_style = {
|
||||
"display": "inline-flex",
|
||||
"visibility": "visible" if cta_label else "hidden",
|
||||
}
|
||||
dots = [
|
||||
html.Span(
|
||||
className=(
|
||||
"cloud-tour-dot cloud-tour-dot--active"
|
||||
if i == index
|
||||
else "cloud-tour-dot"
|
||||
)
|
||||
)
|
||||
for i in range(len(TOUR_SLIDES))
|
||||
]
|
||||
return (
|
||||
overlay_style,
|
||||
slide["image"],
|
||||
slide["eyebrow"],
|
||||
slide["title"],
|
||||
slide["text"],
|
||||
cta_label or "Start free on Prowler Cloud",
|
||||
cta_style,
|
||||
dots,
|
||||
)
|
||||
@@ -0,0 +1,94 @@
|
||||
"""Tests for the Prowler Cloud promo tour logic and layout."""
|
||||
|
||||
from dashboard.lib import cloud_promo as cp
|
||||
|
||||
|
||||
class TestNextTourState:
|
||||
total = len(cp.TOUR_SLIDES)
|
||||
|
||||
def test_trigger_opens_at_first_slide(self):
|
||||
assert cp.next_tour_state(cp.TRIGGER_ID, False, 3, self.total) == (True, 0)
|
||||
|
||||
def test_close_keeps_index_and_closes(self):
|
||||
assert cp.next_tour_state(cp.CLOSE_ID, True, 2, self.total) == (False, 2)
|
||||
|
||||
def test_backdrop_closes(self):
|
||||
assert cp.next_tour_state(cp.BACKDROP_ID, True, 1, self.total) == (False, 1)
|
||||
|
||||
def test_next_advances_and_wraps(self):
|
||||
assert cp.next_tour_state(cp.NEXT_ID, True, 0, self.total) == (True, 1)
|
||||
assert cp.next_tour_state(cp.NEXT_ID, True, self.total - 1, self.total) == (
|
||||
True,
|
||||
0,
|
||||
)
|
||||
|
||||
def test_prev_goes_back_and_wraps(self):
|
||||
assert cp.next_tour_state(cp.PREV_ID, True, 1, self.total) == (True, 0)
|
||||
assert cp.next_tour_state(cp.PREV_ID, True, 0, self.total) == (
|
||||
True,
|
||||
self.total - 1,
|
||||
)
|
||||
|
||||
def test_unknown_trigger_is_noop(self):
|
||||
assert cp.next_tour_state("whatever", True, 2, self.total) == (True, 2)
|
||||
|
||||
def test_empty_tour_stays_closed(self):
|
||||
assert cp.next_tour_state(cp.NEXT_ID, True, 0, 0) == (False, 0)
|
||||
|
||||
|
||||
class TestSlides:
|
||||
def test_every_slide_has_image_and_copy(self):
|
||||
for slide in cp.TOUR_SLIDES:
|
||||
assert slide["image"].startswith("/assets/images/cloud/")
|
||||
assert slide["title"]
|
||||
assert slide["text"]
|
||||
assert slide["eyebrow"]
|
||||
|
||||
def test_exactly_one_closing_cta(self):
|
||||
with_cta = [s for s in cp.TOUR_SLIDES if s.get("cta")]
|
||||
assert len(with_cta) == 1
|
||||
assert with_cta[0] is cp.TOUR_SLIDES[-1]
|
||||
|
||||
|
||||
class TestLayout:
|
||||
def test_card_uses_trigger_id(self):
|
||||
card = cp.cloud_promo_card()
|
||||
# The clickable element carries the trigger id used by the callback.
|
||||
ids = _collect_ids(card)
|
||||
assert cp.TRIGGER_ID in ids
|
||||
|
||||
def test_modal_exposes_stores_and_controls(self):
|
||||
modal = cp.cloud_tour_modal()
|
||||
ids = _collect_ids(modal)
|
||||
for expected in (
|
||||
cp.OVERLAY_ID,
|
||||
cp.OPEN_STORE_ID,
|
||||
cp.INDEX_STORE_ID,
|
||||
cp.CLOSE_ID,
|
||||
cp.BACKDROP_ID,
|
||||
cp.PREV_ID,
|
||||
cp.NEXT_ID,
|
||||
"cloud-tour-image",
|
||||
):
|
||||
assert expected in ids
|
||||
|
||||
|
||||
def _collect_ids(component):
|
||||
"""Walk a Dash component tree collecting every string id."""
|
||||
ids = []
|
||||
|
||||
def visit(node):
|
||||
comp_id = getattr(node, "id", None)
|
||||
if isinstance(comp_id, str):
|
||||
ids.append(comp_id)
|
||||
children = getattr(node, "children", None)
|
||||
if children is None:
|
||||
return
|
||||
if isinstance(children, (list, tuple)):
|
||||
for child in children:
|
||||
visit(child)
|
||||
else:
|
||||
visit(children)
|
||||
|
||||
visit(component)
|
||||
return ids
|
||||
@@ -40,181 +40,9 @@ When adding a new configurable check to Prowler, update the following files:
|
||||
# aws.awslambda_function_vpc_multi_az
|
||||
lambda_min_azs: 2
|
||||
```
|
||||
- **Provider Schema:** Add the typed field to the provider's Pydantic schema in `prowler/config/schema/<provider>.py`. This is required: the loader validates user configs against these schemas and the shipped `config.yaml` must round-trip with zero warnings. See [Adding a Parameter to the Provider Schema](#adding-a-parameter-to-the-provider-schema) below.
|
||||
- **Test Fixtures:** If tests depend on this configuration, add the variable to `tests/config/fixtures/config.yaml`.
|
||||
- **Documentation:** Document the new variable in the list of configurable checks in `docs/tutorials/configuration_file.md`.
|
||||
|
||||
For a complete list of checks that already support configuration, see the [Configuration File Tutorial](/user-guide/cli/tutorials/configuration_file).
|
||||
|
||||
## Adding a Parameter to the Provider Schema
|
||||
|
||||
Most providers have a typed Pydantic schema in `prowler/config/schema/`, registered in `prowler/config/schema/registry.py`. When a config is loaded and the provider has a registered schema, `validate_provider_config` checks each user-supplied key against it, logs a warning, and drops any field that fails validation. The consumer's `.get(key, default)` then falls back to the built-in default. Providers without a registered schema are passed through unchanged.
|
||||
|
||||
This catches typos in a value (for example, `0.2` typed as `20`, or `"medium"` for an enum that expects `"MEDIUM"`). It does NOT catch typos in a key name: `disalowed_regions` (one `l` missing) is treated as an unknown key and passes through untouched, because third-party check plugins legitimately rely on unknown keys being preserved. Reviewers should still check that any new key the YAML adds is named exactly the same as the field on the schema.
|
||||
|
||||
### Where to Add the Field
|
||||
|
||||
1. Open `prowler/config/schema/<provider>.py` (for example, `aws.py`).
|
||||
2. Add a field on the provider's schema class. Always make it `Optional[...] = None` so the absence of the key is valid.
|
||||
3. Apply the tightest type the value allows. Examples below.
|
||||
|
||||
If you are introducing an entirely new provider rather than a new parameter, also add an entry mapping the provider name to its schema class in `prowler/config/schema/registry.py`. The loader uses that registry to find the schema for the provider it is loading.
|
||||
|
||||
### Choosing the Right Type
|
||||
|
||||
| Value kind | Field declaration |
|
||||
|---|---|
|
||||
| Boolean toggle | `Optional[bool] = None` |
|
||||
| Strictly positive integer (days, counts) | `Optional[int] = Field(default=None, gt=0)` |
|
||||
| Fraction in 0..1 (threshold) | `Optional[float] = Field(default=None, ge=0.0, le=1.0)` |
|
||||
| Closed set of strings | `Optional[Literal["A", "B", "C"]] = None` |
|
||||
| Free-form string | `Optional[str] = None` |
|
||||
| List of strings or ints | `Optional[list[str]] = None` |
|
||||
|
||||
Prefer `Literal[...]` over `str` whenever the value is one of a known set. Prefer `Field(gt=0)` over `int` whenever zero or negative would be nonsensical. The point of the schema is to catch real-world mistakes that previously passed silently.
|
||||
|
||||
### Custom Validators (Only When Needed)
|
||||
|
||||
If the value has structural rules beyond type and range, add a `field_validator`. Examples already in `aws.py`:
|
||||
|
||||
- `_validate_port_range` rejects ports outside `0..65535`.
|
||||
- `_validate_account_ids` rejects anything that isn't a 12-digit AWS account ID.
|
||||
- `_validate_trusted_ips` rejects entries that aren't a valid IP or CIDR.
|
||||
|
||||
Raise `ValueError` from the validator. The framework converts the error into a warning and drops the offending key.
|
||||
|
||||
### Example: Adding a New Parameter
|
||||
|
||||
Say a new check needs `max_iam_role_session_hours`, a strictly positive integer that defaults to 12 in code.
|
||||
|
||||
1. **Schema** (`prowler/config/schema/aws.py`):
|
||||
```python
|
||||
# IAM
|
||||
max_iam_role_session_hours: Optional[int] = Field(default=None, gt=0)
|
||||
```
|
||||
2. **Shipped config** (`prowler/config/config.yaml`):
|
||||
```yaml
|
||||
# aws.iam_role_session_duration_within_limit
|
||||
max_iam_role_session_hours: 12
|
||||
```
|
||||
3. **Consumer** (the check):
|
||||
```python
|
||||
max_hours = iam_client.audit_config.get("max_iam_role_session_hours", 12)
|
||||
```
|
||||
4. **Tests** in `tests/config/schema/aws_schema_test.py`:
|
||||
- one test for a valid value that round-trips,
|
||||
- one test for an invalid value (zero, negative, wrong type) that is dropped.
|
||||
|
||||
### What the Loader Guarantees
|
||||
|
||||
- **Unknown keys pass through.** Third-party check plugins can introduce arbitrary keys without schema edits; they will not be filtered.
|
||||
- **Invalid values never crash the run.** They produce a single warning per field and the key is dropped.
|
||||
- **Coerced values are normalized.** A YAML-quoted `"180"` for an `int` field arrives downstream as the integer `180`.
|
||||
- **The shipped `config.yaml` must round-trip cleanly.** The integration test `test_shipped_default_config_loads_without_warnings` will fail if a key is added to the YAML without a matching schema field, so the two stay in sync.
|
||||
|
||||
## Configuration Value Limits
|
||||
|
||||
Configurable thresholds enforce hard limits. A value outside the documented range is **dropped with a warning** and the check falls back to its built-in default (the same as if the key were absent). These bounds are intentionally conservative: they are not the absolute service maxima but the range that still produces a meaningful security check.
|
||||
|
||||
Use this section as the reference when upgrading an existing config: if a value you set is being rejected, it is outside the range below.
|
||||
|
||||
Only fields with a numeric range, a fixed value set, or a length cap are listed. Fields typed as free-form strings or lists (for example `disallowed_regions`, `secrets_ignore_patterns`, `trusted_account_ids`) have no range limit — they are validated for shape only (a 12-digit account ID, a valid IP/CIDR, a dotted version string), not for magnitude.
|
||||
|
||||
### AWS
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `max_unused_access_keys_days` | `30..180` days | CIS AWS 1.13 recommends 45; NIST IA-5 ≤90 |
|
||||
| `max_console_access_days` | `30..180` days | CIS AWS 1.12 recommends 45 |
|
||||
| `max_unused_sagemaker_access_days` | `7..180` days | |
|
||||
| `max_security_group_rules` | `1..1000` | AWS hard limit is 1000 rules per security group |
|
||||
| `max_ec2_instance_age_in_days` | `1..1095` days | 3 years |
|
||||
| `ec2_high_risk_ports` | each port `1..65535` | port 0 is reserved |
|
||||
| `max_idle_disconnect_timeout_in_seconds` | `60..1800` s | NIST AC-12: cap at 30 min |
|
||||
| `max_disconnect_timeout_in_seconds` | `60..3600` s | |
|
||||
| `max_session_duration_seconds` | `600..86400` s | 10 min .. 24 h (AppStream per-session hard limit) |
|
||||
| `lambda_min_azs` | `1..6` | |
|
||||
| `recommended_cdk_bootstrap_version` | `1..100` | |
|
||||
| `log_group_retention_days` | one of `1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653` | only the CloudWatch Logs API-accepted retention values |
|
||||
| `threat_detection_privilege_escalation_threshold` | `0.0..1.0` | fraction of suspicious actions |
|
||||
| `threat_detection_privilege_escalation_minutes` | `5..43200` min | under 5 min the signal is mostly false positives |
|
||||
| `threat_detection_enumeration_threshold` | `0.0..1.0` | |
|
||||
| `threat_detection_enumeration_minutes` | `5..43200` min | |
|
||||
| `threat_detection_llm_jacking_threshold` | `0.0..1.0` | |
|
||||
| `threat_detection_llm_jacking_minutes` | `5..43200` min | |
|
||||
| `days_to_expire_threshold` (ACM) | `7..365` days | PCI-DSS 4.2.1.1: alert ≥30 days before expiry |
|
||||
| `elb_min_azs` | `1..6` | |
|
||||
| `elbv2_min_azs` | `1..6` | |
|
||||
| `minimum_snapshot_retention_period` | `1..35` days | ElastiCache service hard limit |
|
||||
| `max_days_secret_unused` | `7..365` days | |
|
||||
| `max_days_secret_unrotated` | `1..180` days | NIST IA-5: rotate quarterly; CIS ≤90 |
|
||||
| `min_kinesis_stream_retention_hours` | `24..8760` h | 1 day .. 1 year |
|
||||
| `detect_secrets_plugins[].limit` | `0.0..10.0` | Shannon entropy threshold |
|
||||
| `shodan_api_key` | ≤512 chars | |
|
||||
|
||||
### Azure
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `vm_backup_min_daily_retention_days` | `7..9999` days | Azure Backup hard limit; under 7 days defeats DR/ransomware recovery |
|
||||
| `apim_threat_detection_llm_jacking_threshold` | `0.0..1.0` | fraction of suspicious actions |
|
||||
| `apim_threat_detection_llm_jacking_minutes` | `5..43200` min | under 5 min the signal is mostly false positives |
|
||||
| `shodan_api_key` | ≤512 chars | |
|
||||
|
||||
### GCP
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `mig_min_zones` | `1..5` | |
|
||||
| `max_snapshot_age_days` | `1..1095` days | 3 years |
|
||||
| `max_unused_account_days` | `30..365` days | |
|
||||
| `storage_min_retention_days` | `1..3650` days | |
|
||||
| `shodan_api_key` | ≤512 chars | |
|
||||
|
||||
### Kubernetes
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `audit_log_maxbackup` | `2..1000` | CIS Kubernetes 1.2.18 recommends ≥10 |
|
||||
| `audit_log_maxsize` | `10..10000` MB | CIS Kubernetes 1.2.19 recommends ≥100 MB |
|
||||
| `audit_log_maxage` | `7..3650` days | CIS Kubernetes 1.2.17 recommends ≥30 days |
|
||||
|
||||
### M365
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `sign_in_frequency` | `1..168` h | 1 h .. 7 days; Conditional Access baseline for admins ≤24 h |
|
||||
| `recommended_mailtips_large_audience_threshold` | `5..10000` | Microsoft default 25 |
|
||||
| `audit_log_age` | `30..3650` days | M365 E3 default 90 days; SEC/FINRA require ≥7 years |
|
||||
|
||||
### GitHub
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `inactive_not_archived_days_threshold` | `30..3650` days | CIS GitHub recommends 180 |
|
||||
|
||||
### Cloudflare
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `max_retries` | `0..10` | 0 disables retries |
|
||||
|
||||
### MongoDB Atlas
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `max_service_account_secret_validity_hours` | `1..720` h | 1 h .. 30 days |
|
||||
|
||||
### Vercel
|
||||
|
||||
| Key | Allowed range | Notes |
|
||||
|---|---|---|
|
||||
| `days_to_expire_threshold` | `7..365` days | PCI-DSS 4.2.1.1: alert ≥30 days before expiry |
|
||||
| `stale_token_threshold_days` | `30..3650` days | NIST AC-2(3) typical window 30..90 days |
|
||||
| `stale_invitation_threshold_days` | `7..365` days | |
|
||||
| `max_owner_percentage` | `1..50` % | guidance recommends ≤25% |
|
||||
| `max_owners` | `1..1000` | absolute cap, overrides percentage for large teams |
|
||||
|
||||
These bounds live in the provider schemas under `prowler/config/schema/`; each field's `Field(ge=..., le=...)` (or `field_validator`) is the source of truth and the descriptions there carry the full rationale.
|
||||
|
||||
This approach ensures that checks are easily configurable, making Prowler highly adaptable to different environments and requirements.
|
||||
|
||||
@@ -221,9 +221,9 @@ Before running E2E tests:
|
||||
```
|
||||
|
||||
- **Ensure Prowler API is available**
|
||||
- By default, Playwright uses `UI_API_BASE_URL=http://localhost:8080/api/v1` (configured in `playwright.config.ts`).
|
||||
- By default, Playwright uses `NEXT_PUBLIC_API_BASE_URL=http://localhost:8080/api/v1` (configured in `playwright.config.ts`).
|
||||
- Start Prowler API so it is reachable on that URL (for example, via `docker-compose-dev.yml` or the development orchestration used locally).
|
||||
- If a different API URL is required, set `UI_API_BASE_URL` accordingly before running the tests.
|
||||
- If a different API URL is required, set `NEXT_PUBLIC_API_BASE_URL` accordingly before running the tests.
|
||||
|
||||
- **Ensure Prowler App UI is available**
|
||||
- Playwright automatically starts the Next.js server through the `webServer` block in `playwright.config.ts` (`pnpm run dev` by default).
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
---
|
||||
title: 'Environment Variable Naming Convention'
|
||||
---
|
||||
|
||||
Prowler is a monorepo composed of several runtime components — Prowler App (the web user interface), Prowler API (the backend), Prowler SDK, and Prowler MCP Server (Model Context Protocol) — that frequently share a single `.env` file. To keep that shared configuration unambiguous, each component namespaces its environment variables with a component-specific prefix.
|
||||
|
||||
## Component Prefixes
|
||||
|
||||
Each component owns a dedicated prefix for the environment variables it reads:
|
||||
|
||||
| Component | Prefix | Status |
|
||||
|-----------|--------|--------|
|
||||
| Prowler App (web UI) | `UI_` | Adopted |
|
||||
| Prowler API (backend) | `API_` | Planned |
|
||||
| Prowler SDK | `SDK_` | Planned |
|
||||
| Prowler MCP Server | `MCP_` | Planned |
|
||||
|
||||
## Why Component Prefixes Matter
|
||||
|
||||
Component prefixes solve three concrete problems in a shared configuration file:
|
||||
|
||||
- **Collisions in a shared `.env`:** Several components historically read identically named variables. The API base URL, for example, is consumed by more than one component, so a single unprefixed name is ambiguous. A component prefix removes that ambiguity.
|
||||
- **Explicit ownership:** A prefix states, at a glance, which component consumes a variable.
|
||||
- **Reduced accidental exposure:** For Prowler App, scoping browser-facing configuration under one intentional prefix prevents server-only values from leaking into the client bundle.
|
||||
|
||||
## Prowler App
|
||||
|
||||
Prowler App has adopted the `UI_` prefix. Its public configuration is resolved from the container environment at runtime rather than inlined at build time, so a single pre-built image serves any deployment. For the operational details on changing these values without rebuilding the image, see [Troubleshooting](/troubleshooting).
|
||||
|
||||
The former build-time variables map to the new runtime variables as follows:
|
||||
|
||||
| Former variable | New variable |
|
||||
|-----------------|--------------|
|
||||
| `NEXT_PUBLIC_API_BASE_URL` | `UI_API_BASE_URL` |
|
||||
| `NEXT_PUBLIC_API_DOCS_URL` | `UI_API_DOCS_URL` |
|
||||
| `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID` | `UI_GOOGLE_TAG_MANAGER_ID` |
|
||||
| `NEXT_PUBLIC_SENTRY_DSN`, `SENTRY_DSN` | `UI_SENTRY_DSN` |
|
||||
| `NEXT_PUBLIC_SENTRY_ENVIRONMENT`, `SENTRY_ENVIRONMENT` | `UI_SENTRY_ENVIRONMENT` |
|
||||
|
||||
The build-time-only Sentry variables used for source-map upload — `SENTRY_ORG`, `SENTRY_PROJECT`, `SENTRY_AUTH_TOKEN`, and `SENTRY_RELEASE` — keep their names, as they are not part of the App's runtime configuration.
|
||||
|
||||
## Upcoming Breaking Change
|
||||
|
||||
<Warning>
|
||||
Adopting the `API_`, `SDK_`, and `MCP_` prefixes for Prowler API, Prowler SDK, and Prowler MCP Server is a planned breaking change in a future release. Migrate environment configuration to the new names when upgrading.
|
||||
</Warning>
|
||||
|
||||
Prowler API, Prowler SDK, and Prowler MCP Server have not yet adopted the convention. In a future release, the variables each of these components reads will be namespaced under `API_`, `SDK_`, and `MCP_` respectively. The per-component mapping from current to prefixed names will be documented when each change is released.
|
||||
|
||||
## Deprecated Names
|
||||
|
||||
- **Prowler App:** The bare server-side `SENTRY_DSN` and `SENTRY_ENVIRONMENT` are no longer read; the server and edge runtimes now read `UI_SENTRY_DSN` and `UI_SENTRY_ENVIRONMENT`. The former `NEXT_PUBLIC_*` build-time variables are deprecated but still read at runtime as a fallback when the matching `UI_*` variable is unset. This fallback will be removed in a future release, so set the `UI_*` runtime variables on the running container.
|
||||
- **Prowler API, Prowler SDK, and Prowler MCP Server:** The current, unprefixed variable names are deprecated. They continue to work today and will be removed once the prefixed convention is adopted for each component, as described in [Upcoming Breaking Change](#upcoming-breaking-change).
|
||||
@@ -108,39 +108,6 @@ uv sync
|
||||
source .venv/bin/activate
|
||||
```
|
||||
|
||||
### Running the Local API Development Stack
|
||||
|
||||
For API development, Prowler provides a Makefile-based local stack in addition to the manual and Docker Compose workflows documented in the API README. PostgreSQL, Valkey, and Neo4j run with Docker Compose, while Django and the Celery worker run natively through `uv`.
|
||||
|
||||
Before using this method, ensure `docker compose`, `tmux`, and `uv` are installed.
|
||||
|
||||
This workflow is designed for macOS and should also work on Linux when Docker, `tmux`, and `uv` are available. Windows requires script changes before it can be supported.
|
||||
|
||||
To start the local API stack, run:
|
||||
|
||||
```shell
|
||||
make dev
|
||||
```
|
||||
|
||||
This command starts the required services, creates a `tmux` session with panes for the API, worker, and PostgreSQL logs, waits until the API responds, and prints the API URL and log file paths. The API is available at:
|
||||
|
||||
```text
|
||||
http://localhost:8080/api/v1
|
||||
```
|
||||
|
||||
Use these commands to manage the stack:
|
||||
|
||||
```shell
|
||||
make dev-setup # Bootstrap dependencies, migrations, and fixtures
|
||||
make dev-attach # Attach to the tmux session
|
||||
make dev-launch # Start the stack on fixed ports and attach
|
||||
make dev-stop # Stop the tmux session and containers
|
||||
make dev-clean # Remove stopped development containers
|
||||
make dev-wipe # Stop everything and delete local development data
|
||||
make dev-status # Show development container status
|
||||
```
|
||||
|
||||
The UI is not started by this workflow. Start it separately by following the UI development instructions in the `ui/` directory.
|
||||
|
||||
### Pre-Commit Hooks
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Before adding a new framework, complete the following checks:
|
||||
- **Verify the framework is not already supported.** Inspect `prowler/compliance/` and every `prowler/compliance/<provider>/` for an existing JSON file matching the name and version.
|
||||
- **Confirm the required checks exist.** Every requirement that can be automated must point to one or more existing Prowler checks. For each missing check, implement it first by following the [Prowler Checks](/developer-guide/checks) guide.
|
||||
- **Review a reference framework.** Use an existing framework with a similar structure as your template:
|
||||
- Universal: `prowler/compliance/dora_2022_2554.json`, `prowler/compliance/csa_ccm_4.0.json`.
|
||||
- Universal: `prowler/compliance/dora.json`, `prowler/compliance/csa_ccm_4.0.json`.
|
||||
- Legacy: `prowler/compliance/aws/cis_2.0_aws.json` (canonical CIS shape), `prowler/compliance/aws/ccc_aws.json`, `prowler/compliance/aws/ens_rd2022_aws.json`, `prowler/compliance/aws/nist_800_53_revision_5_aws.json`.
|
||||
|
||||
## Universal Compliance Framework
|
||||
@@ -51,9 +51,9 @@ Place the file at the top level of the compliance directory:
|
||||
prowler/compliance/<framework_name>.json
|
||||
```
|
||||
|
||||
Examples in the repository: `prowler/compliance/csa_ccm_4.0.json`, `prowler/compliance/dora_2022_2554.json`.
|
||||
Examples in the repository: `prowler/compliance/csa_ccm_4.0.json`, `prowler/compliance/dora.json`.
|
||||
|
||||
The file is auto-discovered — there is **no** need to register it in any `__init__.py`, modify `prowler/lib/outputs/`, or update any other Python module. The framework key Prowler CLI accepts via `--compliance` is the basename of the JSON file without `.json` (`dora_2022_2554.json` → `dora_2022_2554`).
|
||||
The file is auto-discovered — there is **no** need to register it in any `__init__.py`, modify `prowler/lib/outputs/`, or update any other Python module. The framework key Prowler CLI accepts via `--compliance` is the basename of the JSON file without `.json` (`dora.json` → `dora`).
|
||||
|
||||
### Top-level structure
|
||||
|
||||
@@ -70,7 +70,7 @@ The file is auto-discovered — there is **no** need to register it in any `__in
|
||||
}
|
||||
```
|
||||
|
||||
A `provider` field at the top level is **optional**. The framework's effective provider list is derived by `ComplianceFramework.get_providers()` (`compliance_models.py:739`) from the union of all keys appearing in `requirement.checks` across all requirements; the explicit `provider` field is used **only as a fallback** when no requirement carries any `checks` key. This is what enables a single file (e.g. `dora_2022_2554.json`) to cover AWS today and add Azure / GCP / etc. tomorrow without restructuring.
|
||||
A `provider` field at the top level is **optional**. The framework's effective provider list is derived by `ComplianceFramework.get_providers()` (`compliance_models.py:739`) from the union of all keys appearing in `requirement.checks` across all requirements; the explicit `provider` field is used **only as a fallback** when no requirement carries any `checks` key. This is what enables a single file (e.g. `dora.json`) to cover AWS today and add Azure / GCP / etc. tomorrow without restructuring.
|
||||
|
||||
Provider keys inside `requirement.checks` must match the directory names under `prowler/providers/`. The valid keys at present are: `aws`, `azure`, `gcp`, `m365`, `kubernetes`, `iac`, `github`, `googleworkspace`, `alibabacloud`, `cloudflare`, `mongodbatlas`, `nhn`, `openstack`, `oraclecloud`, `llm`. Comparison in `supports_provider()` is case-insensitive, but lowercase is the convention used everywhere in the repository.
|
||||
|
||||
@@ -493,7 +493,7 @@ Before opening a PR, validate the JSON loads cleanly against the model and that
|
||||
|
||||
### 1. Schema validation
|
||||
|
||||
For **universal** frameworks, load the file and inspect what was parsed. The framework key inside `bulk` is the **basename of the JSON file** (without `.json`); for `prowler/compliance/dora_2022_2554.json` that key is `dora_2022_2554`, for `prowler/compliance/aws/cis_5.0_aws.json` it is `cis_5.0_aws`.
|
||||
For **universal** frameworks, load the file and inspect what was parsed. The framework key inside `bulk` is the **basename of the JSON file** (without `.json`); for `prowler/compliance/dora.json` that key is `dora`, for `prowler/compliance/aws/cis_5.0_aws.json` it is `cis_5.0_aws`.
|
||||
|
||||
```python
|
||||
from prowler.lib.check.compliance_models import (
|
||||
@@ -619,7 +619,7 @@ The following issues are the most common when contributing a compliance framewor
|
||||
|
||||
Use the following files as templates when modeling a new contribution.
|
||||
|
||||
- `prowler/compliance/dora_2022_2554.json` — universal schema, single-provider populated (AWS), ready to extend with more providers.
|
||||
- `prowler/compliance/dora.json` — universal schema, single-provider populated (AWS), ready to extend with more providers.
|
||||
- `prowler/compliance/csa_ccm_4.0.json` — universal schema, multi-provider populated (AWS, Azure, GCP, AlibabaCloud, OracleCloud).
|
||||
- `prowler/compliance/aws/cis_2.0_aws.json` — legacy CIS attribute shape.
|
||||
- `prowler/compliance/aws/nist_800_53_revision_5_aws.json` — legacy generic attribute shape.
|
||||
|
||||
@@ -359,13 +359,6 @@
|
||||
"user-guide/providers/okta/getting-started-okta",
|
||||
"user-guide/providers/okta/authentication"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Linode",
|
||||
"pages": [
|
||||
"user-guide/providers/linode/getting-started-linode",
|
||||
"user-guide/providers/linode/authentication"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -424,7 +417,6 @@
|
||||
"group": "Miscellaneous",
|
||||
"pages": [
|
||||
"developer-guide/documentation",
|
||||
"developer-guide/environment-variables",
|
||||
{
|
||||
"group": "Testing",
|
||||
"pages": [
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
title: 'Troubleshooting'
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
|
||||
## Running `prowler` I get `[File: utils.py:15] [Module: utils] CRITICAL: path/redacted: OSError[13]`
|
||||
|
||||
That is an error related to file descriptors or opened files allowed by your operating system.
|
||||
@@ -83,39 +81,6 @@ docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Worker Uses Too Much Memory on Hosts with Many CPUs
|
||||
|
||||
<VersionBadge version="5.31.0" />
|
||||
|
||||
When Prowler App runs self-hosted on a machine or Kubernetes node with many CPUs,
|
||||
the Celery worker may create one prefork process per detected CPU if concurrency
|
||||
is not configured explicitly. Each process loads the SDK runtime and cloud
|
||||
provider clients, so idle memory can be high and worker containers can be
|
||||
terminated by their memory limit.
|
||||
|
||||
Set `DJANGO_CELERY_WORKER_CONCURRENCY` in the worker runtime environment to cap
|
||||
the number of prefork processes:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
worker:
|
||||
environment:
|
||||
DJANGO_CELERY_WORKER_CONCURRENCY: "4"
|
||||
```
|
||||
|
||||
For Kubernetes deployments, set the same variable on the worker Deployment:
|
||||
|
||||
```yaml
|
||||
env:
|
||||
- name: DJANGO_CELERY_WORKER_CONCURRENCY
|
||||
value: "4"
|
||||
```
|
||||
|
||||
Lower values reduce idle memory and the number of tasks a worker can run in
|
||||
parallel. Increase the value only when the worker has enough memory for the
|
||||
expected scan workload. Leaving the variable unset preserves Celery's default
|
||||
CPU-based concurrency.
|
||||
|
||||
### API Container Fails to Start with JWT Key Permission Error
|
||||
|
||||
See [GitHub Issue #8897](https://github.com/prowler-cloud/prowler/issues/8897) for more details.
|
||||
@@ -236,29 +201,35 @@ When running Prowler behind a reverse proxy (nginx, Traefik, etc.) or load balan
|
||||
|
||||
**Root Cause:**
|
||||
|
||||
The API base and docs URLs are resolved from the container environment **at runtime**. A single pre-built Docker image (`prowlercloud/prowler-ui:stable`) therefore serves any environment: point the URLs at your external domain and restart the container — no rebuild is required.
|
||||
Next.js environment variables prefixed with `NEXT_PUBLIC_` are **bundled at build time**, not runtime. The pre-built Docker images from Docker Hub (`prowlercloud/prowler-ui:stable`) are built with default internal URLs. Simply setting `NEXT_PUBLIC_API_BASE_URL` in your `.env` file or environment variables and restarting the container will **NOT** work because these values are already compiled into the JavaScript bundle.
|
||||
|
||||
**Solution:**
|
||||
|
||||
Set the runtime environment variables to your external URL and restart the UI container:
|
||||
You must **rebuild** the UI Docker image with your external URL:
|
||||
|
||||
```bash
|
||||
# Clone the repository (if you haven't already)
|
||||
git clone https://github.com/prowler-cloud/prowler.git
|
||||
cd prowler/ui
|
||||
|
||||
# Build with your external URL as a build argument
|
||||
docker build \
|
||||
--build-arg NEXT_PUBLIC_API_BASE_URL=https://prowler.example.com/api/v1 \
|
||||
--build-arg NEXT_PUBLIC_API_DOCS_URL=https://prowler.example.com/api/v1/docs \
|
||||
-t prowler-ui-custom:latest \
|
||||
--target prod \
|
||||
.
|
||||
```
|
||||
|
||||
Then update your `docker-compose.yml` to use your custom image instead of the pre-built one:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
ui:
|
||||
image: prowlercloud/prowler-ui:stable
|
||||
environment:
|
||||
UI_API_BASE_URL: https://prowler.example.com/api/v1
|
||||
UI_API_DOCS_URL: https://prowler.example.com/api/v1/docs
|
||||
image: prowler-ui-custom:latest # Use your custom-built image
|
||||
# ... rest of configuration
|
||||
```
|
||||
|
||||
The same values can be supplied through your `.env` file:
|
||||
|
||||
```bash
|
||||
UI_API_BASE_URL=https://prowler.example.com/api/v1
|
||||
UI_API_DOCS_URL=https://prowler.example.com/api/v1/docs
|
||||
```
|
||||
|
||||
<Note>
|
||||
Earlier releases inlined these values into the JavaScript bundle at build time (via the `NEXT_PUBLIC_` prefix) and required a rebuild with `--build-arg`. That is no longer necessary: `UI_API_BASE_URL` and `UI_API_DOCS_URL` are read at container start, so updating them and restarting is sufficient.
|
||||
The `NEXT_PUBLIC_` prefix is a Next.js convention that exposes environment variables to the browser. Since the browser bundle is compiled during `docker build`, these variables must be provided as build arguments, not runtime environment variables.
|
||||
</Note>
|
||||
|
||||
@@ -10,20 +10,14 @@ prowler/config/config.yaml
|
||||
|
||||
Additionally, you can input a custom configuration file using the `--config-file` argument.
|
||||
|
||||
<Note>
|
||||
Numeric thresholds enforce hard limits. A value outside the accepted range is dropped with a warning and the check falls back to its built-in default. See [Configuration Value Limits](/developer-guide/configurable-checks#configuration-value-limits) for the exact range of every bounded option (max-days caps, percentages, counts, etc.).
|
||||
</Note>
|
||||
|
||||
## AWS
|
||||
|
||||
### Configurable Checks
|
||||
|
||||
The following list includes all the AWS checks with configurable variables that can be changed in the configuration yaml file:
|
||||
|
||||
| Check Name | Value | Type |
|
||||
|---------------------------------------------------------------|--------------------------------------------------|-----------------|
|
||||
| `acm_certificates_expiration_check` | `days_to_expire_threshold` | Integer |
|
||||
| `acmpca_certificate_authority_pqc_key_algorithm` | `acmpca_pqc_key_algorithms` | List of Strings |
|
||||
| `appstream_fleet_maximum_session_duration` | `max_session_duration_seconds` | Integer |
|
||||
| `appstream_fleet_session_disconnect_timeout` | `max_disconnect_timeout_in_seconds` | Integer |
|
||||
| `appstream_fleet_session_idle_disconnect_timeout` | `max_idle_disconnect_timeout_in_seconds` | Integer |
|
||||
@@ -61,9 +55,6 @@ The following list includes all the AWS checks with configurable variables that
|
||||
| `elasticache_redis_cluster_backup_enabled` | `minimum_snapshot_retention_period` | Integer |
|
||||
| `elb_is_in_multiple_az` | `elb_min_azs` | Integer |
|
||||
| `elbv2_is_in_multiple_az` | `elbv2_min_azs` | Integer |
|
||||
| `rolesanywhere_trust_anchor_pqc_pki` | `rolesanywhere_pqc_pca_key_algorithms` | List of Strings |
|
||||
| `cloudfront_distributions_pqc_tls_enabled` | `cloudfront_pqc_min_protocol_versions` | List of Strings |
|
||||
| `apigateway_domain_name_pqc_tls_enabled` | `apigateway_pqc_tls_allowed_policies` | List of Strings |
|
||||
| `guardduty_is_enabled` | `mute_non_default_regions` | Boolean |
|
||||
| `iam_user_access_not_stale_to_sagemaker` | `max_unused_sagemaker_access_days` | Integer |
|
||||
| `iam_user_accesskey_unused` | `max_unused_access_keys_days` | Integer |
|
||||
@@ -76,7 +67,6 @@ The following list includes all the AWS checks with configurable variables that
|
||||
| `secretsmanager_secret_rotated_periodically` | `max_days_secret_unrotated` | Integer |
|
||||
| `ssm_document_secrets` | `secrets_ignore_patterns` | List of Strings |
|
||||
| `trustedadvisor_premium_support_plan_subscribed` | `verify_premium_support_plans` | Boolean |
|
||||
| `transfer_server_pqc_ssh_kex_enabled` | `transfer_pqc_ssh_allowed_policies` | List of Strings |
|
||||
| `dynamodb_table_cross_account_access` | `trusted_account_ids` | List of Strings |
|
||||
| `eventbridge_bus_cross_account_access` | `trusted_account_ids` | List of Strings |
|
||||
| `eventbridge_schema_registry_cross_account_access` | `trusted_account_ids` | List of Strings |
|
||||
|
||||
@@ -138,10 +138,6 @@ To keep permissions focused:
|
||||
|
||||
4. Continue through the wizard and finish. No principals need to be granted access in step 3 unless you want other identities to impersonate this account.
|
||||
|
||||
<Note>
|
||||
To use this service account with `--organization-id`, additionally grant `roles/cloudasset.viewer` at the organization node and enable the Cloud Asset API in the service account's host project. See [Scanning a Specific GCP Organization](./organization). Without these, organization-wide scans silently fall back to listing only the projects accessible to the service account.
|
||||
</Note>
|
||||
|
||||
### Step 3: Generate a JSON Key
|
||||
|
||||
1. Open the newly created service account, move to the **Keys** tab, and choose **Add key > Create new key**.
|
||||
|
||||
@@ -11,19 +11,8 @@ prowler gcp --organization-id organization-id
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Ensure the credentials used have one of the following roles bound **at the organization node** (not at a project): Cloud Asset Viewer (`roles/cloudasset.viewer`) or Cloud Asset Owner (`roles/cloudasset.owner`). The role must be bound directly on the organization so the Cloud Asset API can enumerate projects across the whole hierarchy.
|
||||
|
||||
```bash
|
||||
gcloud organizations add-iam-policy-binding <organization-id> \
|
||||
--member="serviceAccount:<service-account-email>" \
|
||||
--role="roles/cloudasset.viewer"
|
||||
```
|
||||
|
||||
The Cloud Asset API (`cloudasset.googleapis.com`) must also be enabled in the project that owns the credentials (the service account's host project, or the quota project for user credentials):
|
||||
|
||||
```bash
|
||||
gcloud services enable cloudasset.googleapis.com --project <credentials-project-id>
|
||||
```
|
||||
Ensure the credentials used have one of the following roles at the organization level:
|
||||
Cloud Asset Viewer (`roles/cloudasset.viewer`), or Cloud Asset Owner (`roles/cloudasset.owner`).
|
||||
|
||||
</Warning>
|
||||
<Note>
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
---
|
||||
title: "Linode Authentication in Prowler"
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
|
||||
<VersionBadge version="5.31.0" />
|
||||
|
||||
Prowler for Linode uses a **Personal Access Token** (PAT) for authentication. Prowler reads the token **exclusively** from the `LINODE_TOKEN` environment variable, so the secret is never exposed in shell history or process listings. There are no credential CLI flags.
|
||||
|
||||
## Required Permissions
|
||||
|
||||
Prowler requires read-only access to your Linode account. The following OAuth scopes are needed on the Personal Access Token:
|
||||
|
||||
| Scope | Access | Description |
|
||||
|-------|--------|-------------|
|
||||
| `account` | `Read Only` | Required to list users and verify account identity |
|
||||
| `linodes` | `Read Only` | Required to list instances and their configurations |
|
||||
| `firewall` | `Read Only` | Required to list firewalls and their rules |
|
||||
|
||||
<Warning>
|
||||
Ensure the token has all required scopes. Missing permissions will cause some checks to fail or return incomplete results.
|
||||
</Warning>
|
||||
|
||||
---
|
||||
|
||||
## Personal Access Token
|
||||
|
||||
### Step 1: Create a Personal Access Token
|
||||
|
||||
1. Log into the [Linode Cloud Manager](https://cloud.linode.com).
|
||||
2. Click on your username in the top-right corner, then select **API Tokens** under the "My Profile" section.
|
||||
3. Click **Create a Personal Access Token**.
|
||||
4. Configure the token:
|
||||
- **Label:** A descriptive name (e.g., "Prowler Security Scanner")
|
||||
- **Expiry:** Set an appropriate expiration (e.g., 6 months)
|
||||
- **Permissions:** Set the following scopes to **Read Only**:
|
||||
- Account
|
||||
- Linodes
|
||||
- Firewall
|
||||
- All other scopes can be set to **No Access**
|
||||
5. Click **Create Token**.
|
||||
6. Copy the token immediately — it will not be shown again.
|
||||
|
||||
### Step 2: Configure Authentication
|
||||
|
||||
Set the `LINODE_TOKEN` environment variable:
|
||||
|
||||
```bash
|
||||
export LINODE_TOKEN="your-personal-access-token"
|
||||
```
|
||||
|
||||
Then run Prowler:
|
||||
|
||||
```bash
|
||||
prowler linode
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verifying Authentication
|
||||
|
||||
To verify that Prowler can connect to your Linode account, run:
|
||||
|
||||
```bash
|
||||
prowler linode --list-checks
|
||||
```
|
||||
|
||||
If authentication succeeds, you will see a list of available checks. If it fails, Prowler will display an error message indicating the credentials issue.
|
||||
|
||||
---
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
For automated pipelines, set the token as a secret environment variable:
|
||||
|
||||
**GitHub Actions:**
|
||||
|
||||
```yaml
|
||||
env:
|
||||
LINODE_TOKEN: ${{ secrets.LINODE_TOKEN }}
|
||||
|
||||
steps:
|
||||
- name: Run Prowler
|
||||
run: prowler linode
|
||||
```
|
||||
|
||||
**GitLab CI:**
|
||||
|
||||
```yaml
|
||||
variables:
|
||||
LINODE_TOKEN: $LINODE_TOKEN
|
||||
|
||||
prowler_scan:
|
||||
script:
|
||||
- prowler linode
|
||||
```
|
||||
@@ -1,61 +0,0 @@
|
||||
---
|
||||
title: 'Getting Started With Linode on Prowler'
|
||||
---
|
||||
|
||||
import { VersionBadge } from "/snippets/version-badge.mdx"
|
||||
|
||||
<VersionBadge version="5.31.0" />
|
||||
|
||||
Prowler for Linode scans your Linode infrastructure for security misconfigurations, including compute settings, networking rules, user account security, and more.
|
||||
|
||||
<Note>
|
||||
Linode support in Prowler is community-maintained. For commercial support or to request additional service coverage, [contact us](https://prowler.com/contact).
|
||||
</Note>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Set up authentication for Linode with the [Linode Authentication](/user-guide/providers/linode/authentication) guide before starting:
|
||||
|
||||
- Create a Linode Personal Access Token with read-only permissions
|
||||
- The token requires at minimum: `account:read_only`, `linodes:read_only`, and `firewall:read_only` scopes
|
||||
|
||||
## Prowler CLI
|
||||
|
||||
### Run Prowler for Linode
|
||||
|
||||
Once authenticated with a Personal Access Token, set the `LINODE_TOKEN` environment variable and run Prowler for Linode. Prowler reads the token exclusively from the environment variable, so the secret is never exposed in shell history or process listings:
|
||||
|
||||
```bash
|
||||
export LINODE_TOKEN="your-personal-access-token"
|
||||
prowler linode
|
||||
```
|
||||
|
||||
### Run Specific Checks
|
||||
|
||||
```bash
|
||||
prowler linode --checks compute_instance_backups_enabled compute_instance_watchdog_enabled
|
||||
```
|
||||
|
||||
### Run a Specific Service
|
||||
|
||||
```bash
|
||||
prowler linode --services networking
|
||||
```
|
||||
|
||||
### Scan Specific Regions
|
||||
|
||||
Use `--region` (alias `--filter-region` / `-f`) to limit the scan to one or more Linode regions. Region-less resources (account administration and Cloud Firewalls) are always scanned; only regional resources such as instances are filtered. When the flag is omitted, all regions are scanned.
|
||||
|
||||
```bash
|
||||
prowler linode --region eu-central us-east
|
||||
```
|
||||
|
||||
## Available Services
|
||||
|
||||
Prowler for Linode currently supports the following services:
|
||||
|
||||
| Service | Description |
|
||||
|---------|-------------|
|
||||
| `administration` | Account administration includes users and access controls such as two-factor authentication |
|
||||
| `compute` | Compute includes Linode instances and their workload configuration |
|
||||
| `networking` | Networking includes Cloud Firewalls and their stateful network rules |
|
||||
@@ -108,10 +108,10 @@ Prowler App updates user attributes each time a user logs in. Any changes made i
|
||||
The `userType` attribute controls which Prowler role is assigned to the user:
|
||||
|
||||
- If `userType` matches an existing Prowler role name, the user receives that role automatically.
|
||||
- If `userType` does not match any existing role, Prowler App creates a new role with that name **with read-only access** (visibility over all providers, no management permissions). A Prowler administrator can adjust its permissions afterward through the [RBAC Management](/user-guide/tutorials/prowler-app-rbac) tab.
|
||||
- If `userType` is not set, the user's existing roles are left unchanged.
|
||||
- If `userType` does not match any existing role, Prowler App creates a new role with that name **without permissions**.
|
||||
- If `userType` is not set, the user receives the `no_permissions` role.
|
||||
|
||||
The `userType` value is **case-sensitive** - for example, `Backend` and `backend` are treated as different roles.
|
||||
In all cases where the resulting role has no permissions, a Prowler administrator must configure the appropriate permissions through the [RBAC Management](/user-guide/tutorials/prowler-app-rbac) tab. The `userType` value is **case-sensitive** - for example, `Backend` and `backend` are treated as different roles.
|
||||
|
||||
</Warning>
|
||||
|
||||
@@ -223,9 +223,9 @@ To test the `userType` → role mapping, set the **Department** attribute in the
|
||||
After a successful SSO login, the user profile in Prowler App reflects the attributes sent by Google Workspace:
|
||||
|
||||
- **Name**: Populated from the `firstName` and `lastName` attributes.
|
||||
- **Role**: Created automatically from the `userType` attribute (e.g., `Backend`). If the role did not exist previously, it is created with read-only access by default.
|
||||
- **Permissions**: If the assigned permissions need to be adjusted, a Prowler administrator can either:
|
||||
- Edit the permissions of the new role via the [RBAC Management](/user-guide/tutorials/prowler-app-rbac) tab.
|
||||
- **Role**: Created automatically from the `userType` attribute (e.g., `Backend`). If the role did not exist previously, it is created with no permissions by default.
|
||||
- **Permissions**: In the screenshot below, the user has no permissions because the `Backend` role did not exist prior to login and was created automatically without any permissions. To resolve this, a Prowler administrator can either:
|
||||
- Assign the appropriate permissions to the new role via the [RBAC Management](/user-guide/tutorials/prowler-app-rbac) tab.
|
||||
- Set the `userType` attribute in the IdP to match an existing Prowler role that already has the desired permissions. The updated role is applied on the next SAML login.
|
||||
|
||||
For more details on role assignment behavior and attribute mapping, refer to the [SAML SSO Configuration](/user-guide/tutorials/prowler-app-sso#configure-attribute-mapping-in-the-idp) page.
|
||||
|
||||
@@ -87,7 +87,7 @@ Choose a Method:
|
||||
|----------------|---------------------------------------------------------------------------------------------------------|----------|
|
||||
| `firstName` | The user's first name. | Yes |
|
||||
| `lastName` | The user's last name. | Yes |
|
||||
| `userType` | Determines which Prowler role the user receives (e.g., `admin`, `auditor`). If a role with that name already exists, the user receives it automatically; if it does not exist, Prowler App creates a new role with that name with read-only access (visibility over all providers, no management permissions). If `userType` is not defined, the user's existing roles are left unchanged. Role permissions can be edited in the [RBAC Management tab](/user-guide/tutorials/prowler-app-rbac). | No |
|
||||
| `userType` | Determines which Prowler role the user receives (e.g., `admin`, `auditor`). If a role with that name already exists, the user receives it automatically; if it does not exist, Prowler App creates a new role with that name without permissions. If `userType` is not defined, the user is assigned the `no_permissions` role. Role permissions can be edited in the [RBAC Management tab](/user-guide/tutorials/prowler-app-rbac). | No |
|
||||
| `organization` | The user's company name. | No |
|
||||
|
||||
<Info>
|
||||
@@ -140,7 +140,7 @@ Choose a Method:
|
||||

|
||||
|
||||
* **Organization** (`organization`): Maps to the company name displayed in Prowler App. This attribute is optional.
|
||||
* **User type** (`userType`): Determines the Prowler role assigned to the user. This attribute is **case-sensitive**: if it matches the exact name of an existing role in Prowler App the user receives that role; if no role with that name exists, a new one is created with read-only access.
|
||||
* **User type** (`userType`): Determines the Prowler role assigned to the user. This attribute is **case-sensitive** and must match the exact name of an existing role in Prowler App.
|
||||
|
||||

|
||||
|
||||
@@ -152,10 +152,14 @@ Choose a Method:
|
||||
The `userType` attribute controls which Prowler role is assigned to the user:
|
||||
|
||||
* If a role with the specified name already exists in Prowler App, the user automatically receives that role.
|
||||
* If the role does not exist, Prowler App creates a new role with that exact name with read-only access: the user can see all providers and their findings but cannot manage anything. A Prowler administrator (a user whose role includes the "Manage Account" permission) can adjust its permissions afterward through the [RBAC Management tab](/user-guide/tutorials/prowler-app-rbac).
|
||||
* If `userType` is not defined in the user's Okta profile, the user's existing roles in Prowler App are left unchanged.
|
||||
* If the role does not exist, Prowler App creates a new role with that exact name but without any permissions, preventing the user from performing any actions.
|
||||
* If `userType` is not defined in the user's Okta profile, the user is assigned the `no_permissions` role.
|
||||
|
||||
**Example:** To assign the `IT` role to a user, set the `userType` value to `IT` in Okta. If a role named `IT` already exists in Prowler App, the user receives it automatically upon login. If it does not exist, Prowler App creates a new role called `IT` with read-only access, and a Prowler administrator can adjust its permissions as needed.
|
||||
In all cases where the resulting role has no permissions, a Prowler administrator (a user whose role includes the "Manage Account" permission) must configure the appropriate permissions through the [RBAC Management tab](/user-guide/tutorials/prowler-app-rbac).
|
||||
|
||||
This behavior is intentional: by defaulting to no permissions, Prowler App ensures that a misconfiguration in Okta cannot inadvertently grant elevated access.
|
||||
|
||||
**Example:** To assign the `IT` role to a user, set the `userType` value to `IT` in Okta. If a role named `IT` already exists in Prowler App, the user receives it automatically upon login. If it does not exist, Prowler App creates a new role called `IT` without permissions, and a Prowler administrator must configure the desired permissions for it.
|
||||
|
||||
</Warning>
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@
|
||||
"lightsail:GetRelationalDatabases",
|
||||
"macie2:GetMacieSession",
|
||||
"macie2:GetAutomatedDiscoveryConfiguration",
|
||||
"rolesanywhere:ListTagsForResource",
|
||||
"rolesanywhere:ListTrustAnchors",
|
||||
"s3:GetAccountPublicAccessBlock",
|
||||
"shield:DescribeProtection",
|
||||
"shield:GetSubscriptionState",
|
||||
@@ -63,9 +61,7 @@
|
||||
],
|
||||
"Resource": [
|
||||
"arn:*:apigateway:*::/restapis/*",
|
||||
"arn:*:apigateway:*::/apis/*",
|
||||
"arn:*:apigateway:*::/domainnames",
|
||||
"arn:*:apigateway:*::/domainnames/*"
|
||||
"arn:*:apigateway:*::/apis/*"
|
||||
],
|
||||
"Sid": "AllowAPIGatewayReadOnly"
|
||||
}
|
||||
|
||||
@@ -129,8 +129,6 @@ Resources:
|
||||
- "lightsail:GetRelationalDatabases"
|
||||
- "macie2:GetMacieSession"
|
||||
- "macie2:GetAutomatedDiscoveryConfiguration"
|
||||
- "rolesanywhere:ListTagsForResource"
|
||||
- "rolesanywhere:ListTrustAnchors"
|
||||
- "s3:GetAccountPublicAccessBlock"
|
||||
- "shield:DescribeProtection"
|
||||
- "shield:GetSubscriptionState"
|
||||
@@ -152,8 +150,6 @@ Resources:
|
||||
Resource:
|
||||
- "arn:*:apigateway:*::/restapis/*"
|
||||
- "arn:*:apigateway:*::/apis/*"
|
||||
- "arn:*:apigateway:*::/domainnames"
|
||||
- "arn:*:apigateway:*::/domainnames/*"
|
||||
- !If
|
||||
- OrganizationsEnabled
|
||||
- PolicyName: ProwlerOrganizations
|
||||
|
||||
@@ -11,82 +11,28 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `config_delegated_admin_and_org_aggregator_all_regions` check for AWS provider, verifying that AWS Config has a delegated administrator and an organization aggregator covering all AWS regions [(#11259)](https://github.com/prowler-cloud/prowler/pull/11259)
|
||||
- `sagemaker_clarify_exists` check for AWS provider [(#11211)](https://github.com/prowler-cloud/prowler/pull/11211)
|
||||
- `cloudsql_instance_high_availability_enabled` check for GCP provider, verifying Cloud SQL primary instances use `REGIONAL` availability for automatic zone failover [(#11024)](https://github.com/prowler-cloud/prowler/pull/11024)
|
||||
- `cloudfunction_function_inside_vpc` check for GCP provider, verifying Cloud Functions have a Serverless VPC Access connector for private egress [(#11021)](https://github.com/prowler-cloud/prowler/pull/11021)
|
||||
- `cloudfunction_function_not_publicly_accessible` check for GCP provider, detecting Cloud Functions with `allUsers` or `allAuthenticatedUsers` IAM invocation bindings [(#11022)](https://github.com/prowler-cloud/prowler/pull/11022)
|
||||
- `secretmanager_secret_not_publicly_accessible` check for GCP provider, detecting Secret Manager secrets with public IAM bindings [(#11025)](https://github.com/prowler-cloud/prowler/pull/11025)
|
||||
- `identity_storage_service_level_admins_scoped` check for OCI provider CIS 3.1 control 1.15, ensuring storage service-level administrators exclude delete permissions [(#11523)](https://github.com/prowler-cloud/prowler/pull/11523)
|
||||
- `cosmosdb_account_automatic_failover_enabled` check for Azure provider [(#11031)](https://github.com/prowler-cloud/prowler/pull/11031)
|
||||
- `cosmosdb_account_backup_policy_continuous` check for Azure provider [(#11032)](https://github.com/prowler-cloud/prowler/pull/11032)
|
||||
- `cosmosdb_account_minimum_tls_version` check for Azure provider, verifying Cosmos DB accounts enforce TLS 1.2 or higher for client connections [(#11033)](https://github.com/prowler-cloud/prowler/pull/11033)
|
||||
- `cosmosdb_account_public_network_access_disabled` check for Azure provider, verifying Cosmos DB accounts have public network access disabled so connectivity is restricted to private endpoints or VNet service endpoints [(#11034)](https://github.com/prowler-cloud/prowler/pull/11034)
|
||||
- `databricks_workspace_public_network_access_disabled` check for Azure provider, verifying Databricks workspaces have public network access disabled so connectivity is restricted to Azure Private Link private endpoints [(#11035)](https://github.com/prowler-cloud/prowler/pull/11035)
|
||||
- `databricks_workspace_no_public_ip_enabled` check for Azure provider, verifying Databricks workspaces use secure cluster connectivity (no public IP) so compute nodes are not assigned public IP addresses [(#11036)](https://github.com/prowler-cloud/prowler/pull/11036)
|
||||
- `defender_ensure_defender_cspm_is_on` check for Azure provider, verifying Microsoft Defender Cloud Security Posture Management (CSPM) is enabled on the Standard tier [(#11037)](https://github.com/prowler-cloud/prowler/pull/11037)
|
||||
- `mysql_flexible_server_geo_redundant_backup_enabled` check for Azure provider, verifying MySQL Flexible Servers have geo-redundant backup enabled so backups are replicated to the paired region [(#11041)](https://github.com/prowler-cloud/prowler/pull/11041)
|
||||
- `mysql_flexible_server_high_availability_enabled` check for Azure provider, verifying MySQL Flexible Servers have high availability enabled for automatic failover to a standby replica [(#11042)](https://github.com/prowler-cloud/prowler/pull/11042)
|
||||
- `postgresql_flexible_server_geo_redundant_backup_enabled` check for Azure provider, verifying PostgreSQL Flexible Servers have geo-redundant backup enabled so backups are replicated to the paired region [(#11045)](https://github.com/prowler-cloud/prowler/pull/11045)
|
||||
- `postgresql_flexible_server_high_availability_enabled` check for Azure provider, verifying PostgreSQL Flexible Servers have high availability enabled for automatic failover to a standby replica [(#11046)](https://github.com/prowler-cloud/prowler/pull/11046)
|
||||
- `aks_cluster_azure_monitor_enabled` check for Azure provider, verifying AKS clusters have Azure Monitor (Container Insights) enabled for metrics, logs, and alerting [(#11029)](https://github.com/prowler-cloud/prowler/pull/11029)
|
||||
- `aks_cluster_local_accounts_disabled` check for Azure provider, verifying AKS clusters have local accounts disabled so authentication is forced through Microsoft Entra ID [(#11030)](https://github.com/prowler-cloud/prowler/pull/11030)
|
||||
- `network_subnet_nsg_associated` check for Azure provider, verifying virtual network subnets have a network security group associated to enforce traffic filtering [(#11043)](https://github.com/prowler-cloud/prowler/pull/11043)
|
||||
- `network_vnet_ddos_protection_enabled` check for Azure provider, verifying virtual networks have Azure DDoS Network Protection enabled [(#11044)](https://github.com/prowler-cloud/prowler/pull/11044)
|
||||
- `entra_app_registration_credential_not_expired` check for Azure provider, verifying Entra ID app registration secrets and certificates are not expired, expiring within 30 days, or without an expiration date [(#11038)](https://github.com/prowler-cloud/prowler/pull/11038)
|
||||
- `entra_authentication_methods_policy_strong_auth_enforced` check for Azure provider, verifying the Entra ID authentication methods policy enforces MFA registration and enables at least one strong method (Microsoft Authenticator, FIDO2, or X.509 certificate) [(#11039)](https://github.com/prowler-cloud/prowler/pull/11039)
|
||||
- `aks_cluster_auto_upgrade_enabled` check for Azure provider [(#11027)](https://github.com/prowler-cloud/prowler/pull/11027)
|
||||
- Public `Provider.get_class()` method that resolves a provider class by name for both built-in and external (entry-point) providers [(#11398)](https://github.com/prowler-cloud/prowler/pull/11398)
|
||||
- Jira timeout preventing the calls from hanging indefinitely when the Jira endpoint is unreachable or slow [(#11602)](https://github.com/prowler-cloud/prowler/pull/11602)
|
||||
- TLS certificate verification in the `codepipeline_project_repo_private` check, which previously used an unverified SSL context, leaving the repository-visibility probe open to MITM tampering [(#11603)](https://github.com/prowler-cloud/prowler/pull/11603)
|
||||
- Support for Linode cloud provider, with compute, networking and administration services [(#11633)](https://github.com/prowler-cloud/prowler/pull/11633)
|
||||
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the Azure provider, mapping existing Azure checks across the five DORA pillars [(#11551)](https://github.com/prowler-cloud/prowler/pull/11551)
|
||||
- Rename DORA to DORA_2022_2554 to follow the naming <name>_<version> in compliance frameworks [(#11551)](https://github.com/prowler-cloud/prowler/pull/11551)
|
||||
- `entra_directory_sync_object_takeover_blocked` check for the M365 provider, verifying that hybrid Entra tenants block cloud object takeover through both soft-match and hard-match directory synchronization [(#11098)](https://github.com/prowler-cloud/prowler/pull/11098)
|
||||
- `entra_conditional_access_policy_no_deleted_object_references` check for M365 provider [(#11236)](https://github.com/prowler-cloud/prowler/pull/11236)
|
||||
- `aks_cluster_defender_enabled` check for Azure provider, verifying that AKS clusters have Microsoft Defender security monitoring enabled [(#11028)](https://github.com/prowler-cloud/prowler/pull/11028)
|
||||
- `recovery_vault_has_protected_items` check for Azure provider, verifying that Recovery Services vaults have at least one protected backup item [(#11048)](https://github.com/prowler-cloud/prowler/pull/11048)
|
||||
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the GCP provider, mapping existing GCP checks across the five DORA pillars [(#11642)](https://github.com/prowler-cloud/prowler/pull/11642)
|
||||
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the Cloudflare provider, mapping existing Cloudflare edge/network checks across the applicable DORA pillars [(#11645)](https://github.com/prowler-cloud/prowler/pull/11645)
|
||||
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the AlibabaCloud provider, mapping existing AlibabaCloud checks across the applicable DORA pillars [(#11646)](https://github.com/prowler-cloud/prowler/pull/11646)
|
||||
- `cloudfront_distributions_pqc_tls_enabled` check for AWS provider to verify CloudFront distributions enforce a post-quantum TLS 1.3 security policy [(#11317)](https://github.com/prowler-cloud/prowler/pull/11317)
|
||||
- `apigateway_domain_name_pqc_tls_enabled` check for AWS provider to verify API Gateway custom domain names use a post-quantum TLS security policy [(#11316)](https://github.com/prowler-cloud/prowler/pull/11316)
|
||||
- `transfer_server_pqc_ssh_kex_enabled` check for AWS provider to verify Transfer Family servers use a post-quantum hybrid SSH key exchange security policy [(#11315)](https://github.com/prowler-cloud/prowler/pull/11315)
|
||||
- `acmpca_certificate_authority_pqc_key_algorithm` check and new `acmpca` service for AWS provider to verify AWS Private CA certificate authorities use a post-quantum (ML-DSA) key algorithm [(#11318)](https://github.com/prowler-cloud/prowler/pull/11318)
|
||||
- `rolesanywhere_trust_anchor_pqc_pki` check and new `rolesanywhere` service for AWS provider to verify IAM Roles Anywhere trust anchors are backed by a post-quantum (ML-DSA) PKI [(#11319)](https://github.com/prowler-cloud/prowler/pull/11319)
|
||||
- Kubernetes core checks for container CPU limits, CPU requests, memory limits, memory requests, fixed image tags, liveness probes, and readiness probes [(#11373)](https://github.com/prowler-cloud/prowler/pull/11373)
|
||||
- Per-requirement configuration validation for compliance frameworks via `ConfigRequirements`, so a requirement is reported as FAIL when its configurable checks ran with a configuration too loose to satisfy it (applied across all compliance outputs: CSV, OCSF, and console tables) [(#11667)](https://github.com/prowler-cloud/prowler/pull/11667)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- Replaced the unmaintained `awsipranges` dependency with a small standard-library helper for the `route53_dangling_ip_subdomain_takeover` check [(#9293)](https://github.com/prowler-cloud/prowler/pull/9293)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- Azure PostgreSQL flexible server inventory no longer aborts the whole subscription when the `connection_throttle.enable` parameter is missing (e.g. PostgreSQL v18), and logs the expected "Entra ID authentication not enabled" case as a warning instead of an error, so servers are still scanned [(#11045)](https://github.com/prowler-cloud/prowler/pull/11045)
|
||||
- `iam_policy_allows_privilege_escalation` now includes the `privilege-escalation` category [(#11648)](https://github.com/prowler-cloud/prowler/pull/11648)
|
||||
|
||||
### 🔐 Security
|
||||
|
||||
- `pytest` from 8.3.5 to 9.0.3, patching a known vulnerability in the SDK test dependency [(#11291)](https://github.com/prowler-cloud/prowler/pull/11291)
|
||||
- `black` from 25.1.0 to 26.3.1, patching a known vulnerability in the SDK formatter dependency [(#11290)](https://github.com/prowler-cloud/prowler/pull/11290)
|
||||
- `microsoft-kiota-*` to 1.9.9 and `aiohttp` to 3.14.0, patching known CVEs [(#11596)](https://github.com/prowler-cloud/prowler/pull/11596)
|
||||
- Container base image bumped to `python:3.12.13-slim-bookworm` (patches `libgnutls30` CVE-2026-33845 and CVE-2026-42010) and `trivy` bumped to 0.71.0 (patches embedded `golang.org/x/crypto` and Go stdlib CVEs); `.trivyignore` documents remaining bookworm criticals with no-fix or not-affected rationale [(#11592)](https://github.com/prowler-cloud/prowler/pull/11592)
|
||||
|
||||
---
|
||||
|
||||
## [5.30.3] (Prowler v5.30.3)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- CLI compliance summary tables no longer undercount findings mapped to multiple sections nor double-count a single finding mapped to several requirements within the same group/split, and the Provider column no longer leaks a value from another framework [(#11567)](https://github.com/prowler-cloud/prowler/pull/11567)
|
||||
|
||||
---
|
||||
|
||||
## [5.30.2] (Prowler v5.30.2)
|
||||
## [5.30.2] (Prowler UNRELEASED)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- GCP `logging_log_metric_filter_and_alert_*` checks now credit org-level aggregated sinks filtered to the Admin Activity audit stream [(#11575)](https://github.com/prowler-cloud/prowler/pull/11575)
|
||||
- A broken built-in provider no longer aborts the CLI when a different provider was invoked [(#11618)](https://github.com/prowler-cloud/prowler/pull/11618)
|
||||
- GCP organization scans with `--organization-id` no longer silently fall back to the credentials' host project when the Cloud Asset API call fails [(#11280)](https://github.com/prowler-cloud/prowler/pull/11280)
|
||||
|
||||
---
|
||||
|
||||
@@ -221,7 +167,6 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `entra_service_principal_no_secrets_for_permanent_tier0_roles` check for M365 provider [(#10788)](https://github.com/prowler-cloud/prowler/pull/10788)
|
||||
- `iam_user_access_not_stale_to_sagemaker` check for AWS provider with configurable `max_unused_sagemaker_access_days` (default 90) [(#11000)](https://github.com/prowler-cloud/prowler/pull/11000)
|
||||
- `cloudtrail_bedrock_logging_enabled` check for AWS provider [(#10858)](https://github.com/prowler-cloud/prowler/pull/10858)
|
||||
- Per-provider scan configuration schema with bounds validation that drops out-of-range values with a warning on config load [(#11518)](https://github.com/prowler-cloud/prowler/pull/11518)
|
||||
- Okta provider with OAuth 2.0 authentication and `signon_global_session_idle_timeout_15min` check [(#11079)](https://github.com/prowler-cloud/prowler/pull/11079)
|
||||
- `sagemaker_domain_sso_configured` check for AWS provider [(#11094)](https://github.com/prowler-cloud/prowler/pull/11094)
|
||||
- Scaleway provider with `iam_api_keys_no_root_owned` check [(#11166)](https://github.com/prowler-cloud/prowler/pull/11166)
|
||||
|
||||
@@ -147,7 +147,6 @@ from prowler.providers.iac.models import IACOutputOptions
|
||||
from prowler.providers.image.exceptions.exceptions import ImageBaseException
|
||||
from prowler.providers.image.models import ImageOutputOptions
|
||||
from prowler.providers.kubernetes.models import KubernetesOutputOptions
|
||||
from prowler.providers.linode.models import LinodeOutputOptions
|
||||
from prowler.providers.llm.models import LLMOutputOptions
|
||||
from prowler.providers.m365.models import M365OutputOptions
|
||||
from prowler.providers.mongodbatlas.models import MongoDBAtlasOutputOptions
|
||||
@@ -440,10 +439,6 @@ def prowler():
|
||||
output_options = ScalewayOutputOptions(
|
||||
args, bulk_checks_metadata, global_provider.identity
|
||||
)
|
||||
elif provider == "linode":
|
||||
output_options = LinodeOutputOptions(
|
||||
args, bulk_checks_metadata, global_provider.identity
|
||||
)
|
||||
else:
|
||||
# Dynamic fallback: any external/custom provider
|
||||
try:
|
||||
|
||||
@@ -109,14 +109,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"ram_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "ram_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -849,14 +841,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"sls_logstore_retention_period"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "sls_logstore_retention_period",
|
||||
"ConfigKey": "min_log_retention_days",
|
||||
"Operator": "gte",
|
||||
"Value": 365
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1369,14 +1353,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"rds_instance_sql_audit_retention"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "rds_instance_sql_audit_retention",
|
||||
"ConfigKey": "min_rds_audit_retention_days",
|
||||
"Operator": "gte",
|
||||
"Value": 180
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -47,14 +47,6 @@
|
||||
"Checks": [
|
||||
"ram_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "ram_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Title": "Inactive users disabled for console access",
|
||||
@@ -703,14 +695,6 @@
|
||||
"Checks": [
|
||||
"rds_instance_sql_audit_retention"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "rds_instance_sql_audit_retention",
|
||||
"ConfigKey": "min_rds_audit_retention_days",
|
||||
"Operator": "gte",
|
||||
"Value": 180
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Title": "RDS SQL audit retention configured",
|
||||
|
||||
@@ -13,14 +13,6 @@
|
||||
"config_recorder_all_regions_enabled",
|
||||
"inspector2_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Patch applications",
|
||||
@@ -268,14 +260,6 @@
|
||||
"config_recorder_all_regions_enabled",
|
||||
"inspector2_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "2 Patch operating systems",
|
||||
@@ -758,14 +742,6 @@
|
||||
"accessanalyzer_enabled",
|
||||
"accessanalyzer_enabled_without_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "4 Restrict administrative privileges",
|
||||
|
||||
@@ -37,26 +37,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"accessanalyzer_enabled",
|
||||
"macie_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -279,20 +259,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -548,14 +514,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled",
|
||||
"accessanalyzer_enabled_without_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -572,20 +530,6 @@
|
||||
"securityhub_enabled",
|
||||
"accessanalyzer_enabled",
|
||||
"accessanalyzer_enabled_without_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -722,14 +666,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -744,14 +680,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -766,14 +694,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -788,14 +708,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -810,14 +722,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -832,14 +736,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -866,14 +762,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -889,14 +777,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_centrally_managed"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -912,14 +792,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -935,14 +807,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -958,14 +822,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -981,14 +837,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1004,14 +852,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1027,14 +867,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1050,14 +882,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1073,14 +897,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1096,14 +912,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -404,14 +404,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled",
|
||||
"accessanalyzer_enabled_without_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -868,20 +860,6 @@
|
||||
"guardduty_lambda_protection_enabled",
|
||||
"guardduty_rds_protection_enabled",
|
||||
"guardduty_ec2_malware_protection_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_delegated_admin_enabled_all_regions",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -916,14 +894,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -994,14 +964,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled",
|
||||
"config_recorder_using_aws_service_role"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1195,4 +1157,4 @@
|
||||
"Checks": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -12,14 +12,6 @@
|
||||
"Checks": [
|
||||
"acm_certificates_expiration_check"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_expiration_check",
|
||||
"ConfigKey": "days_to_expire_threshold",
|
||||
"Operator": "gte",
|
||||
"Value": 30
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "ACM.1",
|
||||
@@ -37,17 +29,6 @@
|
||||
"Checks": [
|
||||
"acm_certificates_with_secure_key_algorithms"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "ACM.2",
|
||||
@@ -796,14 +777,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "Config.1",
|
||||
@@ -919,14 +892,6 @@
|
||||
"Checks": [
|
||||
"documentdb_cluster_backup_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "documentdb_cluster_backup_enabled",
|
||||
"ConfigKey": "minimum_backup_retention_period",
|
||||
"Operator": "gte",
|
||||
"Value": 7
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "DocumentDB.2",
|
||||
@@ -2405,14 +2370,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "GuardDuty.1",
|
||||
@@ -2590,20 +2547,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "IAM.8",
|
||||
@@ -2692,20 +2635,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "IAM.22",
|
||||
@@ -3022,14 +2951,6 @@
|
||||
"Checks": [
|
||||
"neptune_cluster_backup_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "neptune_cluster_backup_enabled",
|
||||
"ConfigKey": "minimum_backup_retention_period",
|
||||
"Operator": "gte",
|
||||
"Value": 7
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"ItemId": "Neptune.5",
|
||||
|
||||
@@ -176,14 +176,6 @@
|
||||
"iam_user_with_temporary_credentials",
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -585,14 +585,6 @@
|
||||
"cloudtrail_multi_region_enabled",
|
||||
"vpc_flow_logs_enabled",
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -654,20 +646,6 @@
|
||||
"guardduty_no_high_severity_findings",
|
||||
"macie_is_enabled",
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -800,14 +778,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"vpc_flow_logs_enabled",
|
||||
"apigateway_restapi_authorizers_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1181,9 +1151,6 @@
|
||||
"elb_insecure_ssl_ciphers",
|
||||
"elb_ssl_listeners",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_ssl_listeners",
|
||||
"s3_bucket_secure_transport_policy"
|
||||
]
|
||||
|
||||
@@ -382,14 +382,6 @@
|
||||
"cloudtrail_multi_region_enabled",
|
||||
"config_recorder_all_regions_enabled",
|
||||
"s3_multi_region_access_point_public_access_block"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2242,14 +2234,6 @@
|
||||
"vpc_different_regions",
|
||||
"autoscaling_group_multiple_az",
|
||||
"storagegateway_gateway_fault_tolerant"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2277,14 +2261,6 @@
|
||||
"organizations_scp_check_deny_regions",
|
||||
"s3_multi_region_access_point_public_access_block",
|
||||
"vpc_different_regions"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2332,14 +2308,6 @@
|
||||
"organizations_scp_check_deny_regions",
|
||||
"s3_multi_region_access_point_public_access_block",
|
||||
"vpc_different_regions"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -3010,14 +2978,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"athena_workgroup_enforce_configuration",
|
||||
"shield_advanced_protection_in_global_accelerators"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -3521,14 +3481,6 @@
|
||||
"cloudtrail_cloudwatch_logging_enabled",
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -4347,14 +4299,6 @@
|
||||
"guardduty_no_high_severity_findings",
|
||||
"guardduty_rds_protection_enabled",
|
||||
"guardduty_s3_protection_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -4976,17 +4920,6 @@
|
||||
"elbv2_nlb_tls_termination_enabled",
|
||||
"transfer_server_in_transit_encryption_enabled",
|
||||
"kafka_cluster_mutual_tls_authentication_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -5013,17 +4946,6 @@
|
||||
"elbv2_nlb_tls_termination_enabled",
|
||||
"transfer_server_in_transit_encryption_enabled",
|
||||
"kafka_cluster_mutual_tls_authentication_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -5298,14 +5220,6 @@
|
||||
"rds_instance_default_admin",
|
||||
"accessanalyzer_enabled",
|
||||
"efs_access_point_enforce_user_identity"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -5823,14 +5737,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled",
|
||||
"accessanalyzer_enabled_without_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6194,17 +6100,6 @@
|
||||
"cloudfront_distributions_origin_traffic_encrypted",
|
||||
"glue_development_endpoints_job_bookmark_encryption_enabled",
|
||||
"cloudtrail_kms_encryption_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6301,17 +6196,6 @@
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"iam_no_expired_server_certificates_stored",
|
||||
"rds_instance_certificate_expiration"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6423,17 +6307,6 @@
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"iam_no_expired_server_certificates_stored",
|
||||
"rds_instance_certificate_expiration"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6520,14 +6393,6 @@
|
||||
"sns_topics_not_publicly_accessible",
|
||||
"sqs_queues_not_publicly_accessible",
|
||||
"vpc_peering_routing_tables_with_least_privilege"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6547,14 +6412,6 @@
|
||||
"ec2_instance_profile_attached",
|
||||
"accessanalyzer_enabled",
|
||||
"accessanalyzer_enabled_without_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6730,17 +6587,6 @@
|
||||
"kms_cmk_not_multi_region",
|
||||
"kms_key_not_publicly_accessible",
|
||||
"ec2_ebs_volume_encryption"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6963,17 +6809,6 @@
|
||||
"secretsmanager_not_publicly_accessible",
|
||||
"secretsmanager_secret_rotated_periodically",
|
||||
"secretsmanager_secret_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -7007,17 +6842,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"acm_certificates_with_secure_key_algorithms"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -7091,17 +6915,6 @@
|
||||
"secretsmanager_secret_rotated_periodically",
|
||||
"secretsmanager_secret_unused",
|
||||
"acm_certificates_with_secure_key_algorithms"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -7124,17 +6937,6 @@
|
||||
"secretsmanager_secret_rotated_periodically",
|
||||
"secretsmanager_secret_unused",
|
||||
"acm_certificates_with_secure_key_algorithms"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -8240,14 +8042,6 @@
|
||||
"cloudtrail_multi_region_enabled",
|
||||
"cloudtrail_multi_region_enabled_logging_management_events",
|
||||
"cloudtrail_log_file_validation_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -9016,14 +8810,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"cloudtrail_log_file_validation_enabled",
|
||||
"ssmincidents_enabled_with_plans"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -9946,14 +9732,6 @@
|
||||
"accessanalyzer_enabled_without_findings",
|
||||
"cloudfront_distributions_s3_origin_access_control",
|
||||
"cloudtrail_logs_s3_bucket_access_logging_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -10589,14 +10367,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled",
|
||||
"accessanalyzer_enabled_without_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -10687,14 +10457,6 @@
|
||||
"ec2_instance_profile_attached",
|
||||
"iam_role_cross_account_readonlyaccess_policy",
|
||||
"iam_securityaudit_role_created"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -49,9 +49,6 @@
|
||||
"elb_insecure_ssl_ciphers",
|
||||
"elb_ssl_listeners",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_ssl_listeners",
|
||||
"elbv2_nlb_tls_termination_enabled",
|
||||
"s3_bucket_secure_transport_policy",
|
||||
@@ -275,17 +272,6 @@
|
||||
"acm_certificates_expiration_check",
|
||||
"acm_certificates_with_secure_key_algorithms",
|
||||
"acm_certificates_transparency_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -805,17 +791,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"acm_certificates_with_secure_key_algorithms"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1526,14 +1501,6 @@
|
||||
"iam_policy_no_full_access_to_kms",
|
||||
"iam_policy_no_full_access_to_cloudtrail",
|
||||
"iam_policy_attached_only_to_group_or_roles"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1696,14 +1663,6 @@
|
||||
"cloudwatch_changes_to_network_route_tables_alarm_configured",
|
||||
"cloudwatch_changes_to_vpcs_alarm_configured",
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1829,14 +1788,6 @@
|
||||
"cloudtrail_threat_detection_enumeration",
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -4357,14 +4308,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"acm_certificates_expiration_check"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_expiration_check",
|
||||
"ConfigKey": "days_to_expire_threshold",
|
||||
"Operator": "gte",
|
||||
"Value": 30
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6230,20 +6173,6 @@
|
||||
"Checks": [
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6340,14 +6269,6 @@
|
||||
"cloudwatch_log_metric_filter_root_usage",
|
||||
"cloudwatch_log_metric_filter_sign_in_without_mfa",
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -6450,14 +6371,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled",
|
||||
"accessanalyzer_enabled_without_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -75,20 +75,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -279,14 +265,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -758,14 +736,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "3 Logging",
|
||||
|
||||
@@ -75,20 +75,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -279,14 +265,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -824,14 +802,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "3 Logging",
|
||||
@@ -1084,14 +1054,6 @@
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "4 Monitoring",
|
||||
|
||||
@@ -75,20 +75,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -279,14 +265,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -824,14 +802,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "3 Logging",
|
||||
@@ -1084,14 +1054,6 @@
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "4 Monitoring",
|
||||
|
||||
@@ -75,20 +75,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -279,14 +265,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -778,14 +756,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "3 Logging",
|
||||
@@ -1038,14 +1008,6 @@
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "4 Monitoring",
|
||||
|
||||
@@ -254,20 +254,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -445,14 +431,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -772,14 +750,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "3 Logging",
|
||||
@@ -1264,14 +1234,6 @@
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "4 Monitoring",
|
||||
|
||||
@@ -232,20 +232,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -423,14 +409,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "1 Identity and Access Management",
|
||||
@@ -750,14 +728,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "3 Logging",
|
||||
@@ -1242,14 +1212,6 @@
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "4 Monitoring",
|
||||
|
||||
@@ -232,20 +232,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 45
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "2 Identity and Access Management",
|
||||
@@ -423,14 +409,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "2 Identity and Access Management",
|
||||
@@ -750,14 +728,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "4 Logging",
|
||||
@@ -1242,14 +1212,6 @@
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "5 Monitoring",
|
||||
|
||||
@@ -136,20 +136,6 @@
|
||||
"ec2_securitygroup_default_restrict_traffic",
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22",
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_all_ports"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -381,20 +367,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -598,14 +598,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -632,14 +624,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -771,14 +755,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -805,14 +781,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -945,14 +913,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -980,14 +940,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1014,14 +966,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1799,14 +1743,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1885,14 +1821,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1945,14 +1873,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2005,14 +1925,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2039,14 +1951,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2073,14 +1977,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2107,14 +2003,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2168,14 +2056,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2202,14 +2082,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2494,10 +2366,7 @@
|
||||
}
|
||||
],
|
||||
"Checks": [
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled"
|
||||
"elbv2_insecure_ssl_ciphers"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2520,10 +2389,7 @@
|
||||
}
|
||||
],
|
||||
"Checks": [
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled"
|
||||
"elbv2_insecure_ssl_ciphers"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -4438,14 +4304,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"drs_job_exist"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -37,14 +37,6 @@
|
||||
"ssm_managed_compliant_patching",
|
||||
"ssm_managed_instance_compliance_association_compliant",
|
||||
"ssm_managed_instance_compliance_patch_compliant"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -154,20 +146,6 @@
|
||||
"inspector2_active_findings_exist",
|
||||
"securityhub_enabled",
|
||||
"sns_topics_kms_encryption_at_rest_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -227,14 +205,6 @@
|
||||
"resourceexplorer_indexes_found",
|
||||
"ssm_managed_instance_compliance_association_compliant",
|
||||
"trustedadvisor_premium_support_plan_subscribed"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -379,14 +349,6 @@
|
||||
"config_recorder_all_regions_enabled",
|
||||
"inspector2_is_enabled",
|
||||
"resourceexplorer_indexes_found"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -46,20 +46,6 @@
|
||||
"redshift_cluster_audit_logging",
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -129,20 +115,6 @@
|
||||
"ec2_networkacl_allow_ingress_any_port",
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22",
|
||||
"ec2_networkacl_allow_ingress_any_port"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -201,14 +173,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"cloudwatch_log_group_retention_policy_specific_days_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "cloudwatch_log_group_retention_policy_specific_days_enabled",
|
||||
"ConfigKey": "log_group_retention_days",
|
||||
"Operator": "gte",
|
||||
"Value": 90
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -234,20 +198,6 @@
|
||||
"rds_instance_enhanced_monitoring_enabled",
|
||||
"redshift_cluster_audit_logging",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -301,14 +251,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"ssm_managed_compliant_patching",
|
||||
"ssm_managed_compliant_patching"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -394,20 +336,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -445,14 +373,6 @@
|
||||
"rds_instance_multi_az",
|
||||
"redshift_cluster_automated_snapshot",
|
||||
"s3_bucket_object_versioning"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -36,20 +36,6 @@
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -79,20 +65,6 @@
|
||||
"redshift_cluster_audit_logging",
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -110,20 +82,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -182,20 +140,6 @@
|
||||
"redshift_cluster_audit_logging",
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -247,38 +191,6 @@
|
||||
"iam_user_access_not_stale_to_sagemaker",
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_access_not_stale_to_bedrock",
|
||||
"ConfigKey": "max_unused_bedrock_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_role_access_not_stale_to_bedrock",
|
||||
"ConfigKey": "max_unused_bedrock_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_access_not_stale_to_sagemaker",
|
||||
"ConfigKey": "max_unused_sagemaker_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -459,20 +371,6 @@
|
||||
"ec2_networkacl_allow_ingress_any_port",
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22",
|
||||
"ec2_networkacl_allow_ingress_any_port"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -609,20 +507,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -691,14 +575,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"cloudwatch_log_group_retention_policy_specific_days_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "cloudwatch_log_group_retention_policy_specific_days_enabled",
|
||||
"ConfigKey": "log_group_retention_days",
|
||||
"Operator": "gte",
|
||||
"Value": 90
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -755,20 +631,6 @@
|
||||
"rds_instance_enhanced_monitoring_enabled",
|
||||
"redshift_cluster_audit_logging",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -858,14 +720,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"ssm_managed_compliant_patching",
|
||||
"ssm_managed_compliant_patching"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1033,20 +887,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1069,20 +909,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1101,20 +927,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1133,20 +945,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1163,14 +961,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1205,20 +995,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1285,14 +1061,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"rds_instance_multi_az",
|
||||
"s3_bucket_object_versioning"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1377,9 +1145,6 @@
|
||||
"Checks": [
|
||||
"apigateway_restapi_client_certificate_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"opensearch_service_domains_node_to_node_encryption_enabled",
|
||||
"s3_bucket_secure_transport_policy"
|
||||
@@ -1399,9 +1164,6 @@
|
||||
"Checks": [
|
||||
"apigateway_restapi_client_certificate_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"opensearch_service_domains_node_to_node_encryption_enabled",
|
||||
"s3_bucket_secure_transport_policy"
|
||||
@@ -1517,14 +1279,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1547,20 +1301,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"redshift_cluster_audit_logging",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1588,20 +1328,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"redshift_cluster_audit_logging",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1629,20 +1355,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"redshift_cluster_audit_logging",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1670,20 +1382,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"redshift_cluster_audit_logging",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1710,20 +1408,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -37,14 +37,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -82,20 +74,6 @@
|
||||
"cloudtrail_cloudwatch_logging_enabled",
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -170,20 +148,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -202,20 +166,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled",
|
||||
"ssm_managed_compliant_patching"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -233,20 +183,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -301,20 +237,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -332,20 +254,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -459,14 +367,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -486,20 +386,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -518,20 +404,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled",
|
||||
"ssm_managed_compliant_patching"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -615,9 +487,6 @@
|
||||
"Checks": [
|
||||
"apigateway_restapi_client_certificate_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"s3_bucket_secure_transport_policy"
|
||||
]
|
||||
@@ -954,20 +823,6 @@
|
||||
"cloudwatch_changes_to_vpcs_alarm_configured",
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1013,20 +868,6 @@
|
||||
"redshift_cluster_audit_logging",
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -59,14 +59,6 @@
|
||||
"cloudwatch_log_metric_filter_security_group_changes",
|
||||
"cloudwatch_log_metric_filter_unauthorized_api_calls",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -93,14 +85,6 @@
|
||||
"kms_cmk_rotation_enabled",
|
||||
"redshift_cluster_audit_logging",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -266,9 +266,6 @@
|
||||
"ec2_ebs_default_encryption",
|
||||
"efs_encryption_at_rest_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"opensearch_service_domains_encryption_at_rest_enabled",
|
||||
"opensearch_service_domains_node_to_node_encryption_enabled",
|
||||
@@ -350,20 +347,6 @@
|
||||
"cloudtrail_cloudwatch_logging_enabled",
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -19,14 +19,6 @@
|
||||
"Checks": [
|
||||
"cloudtrail_multi_region_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -154,14 +146,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -254,14 +238,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -277,14 +253,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -19,20 +19,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled",
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -116,20 +102,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -189,20 +161,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -370,20 +328,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"cloudwatch_log_metric_filter_authentication_failures",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -429,20 +373,6 @@
|
||||
"cloudwatch_log_metric_filter_authentication_failures",
|
||||
"cloudwatch_log_metric_filter_root_usage",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -472,20 +402,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -598,20 +514,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -747,20 +649,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -868,20 +756,6 @@
|
||||
"s3_bucket_secure_transport_policy",
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -35,10 +35,7 @@
|
||||
],
|
||||
"Checks": [
|
||||
"elb_insecure_ssl_ciphers",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled"
|
||||
"elbv2_insecure_ssl_ciphers"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -311,14 +308,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -883,38 +872,6 @@
|
||||
"iam_user_access_not_stale_to_sagemaker",
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_access_not_stale_to_bedrock",
|
||||
"ConfigKey": "max_unused_bedrock_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_role_access_not_stale_to_bedrock",
|
||||
"ConfigKey": "max_unused_bedrock_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_access_not_stale_to_sagemaker",
|
||||
"ConfigKey": "max_unused_sagemaker_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1092,20 +1049,6 @@
|
||||
"Checks": [
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1315,20 +1258,6 @@
|
||||
"Checks": [
|
||||
"iam_user_accesskey_unused",
|
||||
"iam_user_console_access_unused"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "iam_user_accesskey_unused",
|
||||
"ConfigKey": "max_unused_access_keys_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
},
|
||||
{
|
||||
"Check": "iam_user_console_access_unused",
|
||||
"ConfigKey": "max_console_access_days",
|
||||
"Operator": "lte",
|
||||
"Value": 90
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -20,14 +20,6 @@
|
||||
"Checks": [
|
||||
"securityhub_enabled",
|
||||
"wellarchitected_workload_no_high_or_medium_risks"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -285,14 +277,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -347,14 +331,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -386,14 +362,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -410,14 +378,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -464,14 +424,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"guardduty_centrally_managed"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -520,14 +472,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"guardduty_centrally_managed"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -546,14 +490,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"guardduty_centrally_managed"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1068,14 +1004,6 @@
|
||||
"organizations_account_part_of_organizations",
|
||||
"accessanalyzer_enabled",
|
||||
"accessanalyzer_enabled_without_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1152,14 +1080,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1191,14 +1111,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1837,14 +1749,6 @@
|
||||
"vpc_default_security_group_closed",
|
||||
"vpc_flow_logs_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1211,14 +1211,6 @@
|
||||
"rds_instance_default_admin",
|
||||
"redshift_cluster_non_default_database_name"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. Control Measures Requirements",
|
||||
@@ -1424,14 +1416,6 @@
|
||||
"iam_user_administrator_access_policy",
|
||||
"organizations_delegated_administrators"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. Control Measures Requirements",
|
||||
@@ -1502,14 +1486,6 @@
|
||||
"ssm_documents_set_as_public",
|
||||
"vpc_endpoint_services_allowed_principals_trust_boundaries"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. Control Measures Requirements",
|
||||
@@ -2064,9 +2040,6 @@
|
||||
"elb_ssl_listeners",
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_nlb_tls_termination_enabled",
|
||||
"elbv2_ssl_listeners",
|
||||
"glue_data_catalogs_connection_passwords_encryption_enabled",
|
||||
@@ -2106,17 +2079,6 @@
|
||||
"transfer_server_in_transit_encryption_enabled",
|
||||
"workspaces_volume_encryption_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. Control Measures Requirements",
|
||||
@@ -2854,20 +2816,6 @@
|
||||
"wafv2_webacl_rule_logging_enabled",
|
||||
"wafv2_webacl_with_rules"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. Control Measures Requirements",
|
||||
@@ -3142,9 +3090,6 @@
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"elbv2_desync_mitigation_mode",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_internet_facing",
|
||||
"elbv2_listeners_underneath",
|
||||
"elbv2_logging_enabled",
|
||||
@@ -3368,47 +3313,6 @@
|
||||
"workspaces_volume_encryption_enabled",
|
||||
"workspaces_vpc_2private_1public_subnets_nat"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. Control Measures Requirements",
|
||||
@@ -3801,14 +3705,6 @@
|
||||
"s3_bucket_event_notifications_enabled",
|
||||
"trustedadvisor_errors_and_warnings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. Control Measures Requirements",
|
||||
@@ -3927,14 +3823,6 @@
|
||||
"s3_bucket_object_lock",
|
||||
"s3_bucket_object_versioning"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. Control Measures Requirements",
|
||||
@@ -3972,14 +3860,6 @@
|
||||
"Checks": [
|
||||
"drs_job_exist"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. Control Measures Requirements",
|
||||
|
||||
@@ -1211,14 +1211,6 @@
|
||||
"rds_instance_default_admin",
|
||||
"redshift_cluster_non_default_database_name"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. 보호대책 요구사항",
|
||||
@@ -1424,14 +1416,6 @@
|
||||
"iam_user_administrator_access_policy",
|
||||
"organizations_delegated_administrators"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. 보호대책 요구사항",
|
||||
@@ -1501,14 +1485,6 @@
|
||||
"ssm_documents_set_as_public",
|
||||
"vpc_endpoint_services_allowed_principals_trust_boundaries"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. 보호대책 요구사항",
|
||||
@@ -2066,9 +2042,6 @@
|
||||
"elb_ssl_listeners",
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_nlb_tls_termination_enabled",
|
||||
"elbv2_ssl_listeners",
|
||||
"glue_data_catalogs_connection_passwords_encryption_enabled",
|
||||
@@ -2108,17 +2081,6 @@
|
||||
"transfer_server_in_transit_encryption_enabled",
|
||||
"workspaces_volume_encryption_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. 보호대책 요구사항",
|
||||
@@ -2857,20 +2819,6 @@
|
||||
"wafv2_webacl_rule_logging_enabled",
|
||||
"wafv2_webacl_with_rules"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. 보호대책 요구사항",
|
||||
@@ -3145,9 +3093,6 @@
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"elbv2_desync_mitigation_mode",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_internet_facing",
|
||||
"elbv2_listeners_underneath",
|
||||
"elbv2_logging_enabled",
|
||||
@@ -3371,47 +3316,6 @@
|
||||
"workspaces_volume_encryption_enabled",
|
||||
"workspaces_vpc_2private_1public_subnets_nat"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. 보호대책 요구사항",
|
||||
@@ -3804,14 +3708,6 @@
|
||||
"s3_bucket_event_notifications_enabled",
|
||||
"trustedadvisor_errors_and_warnings"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. 보호대책 요구사항",
|
||||
@@ -3930,14 +3826,6 @@
|
||||
"s3_bucket_object_lock",
|
||||
"s3_bucket_object_versioning"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. 보호대책 요구사항",
|
||||
@@ -3975,14 +3863,6 @@
|
||||
"Checks": [
|
||||
"drs_job_exist"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Domain": "2. 보호대책 요구사항",
|
||||
|
||||
@@ -35,32 +35,6 @@
|
||||
"awslambda_function_not_publicly_accessible",
|
||||
"ec2_instance_public_ip"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS CloudEndure Disaster Recovery",
|
||||
@@ -226,26 +200,6 @@
|
||||
"organizations_scp_check_deny_regions",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "Amazon GuardDuty",
|
||||
@@ -394,14 +348,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Config",
|
||||
@@ -447,26 +393,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Config",
|
||||
@@ -518,14 +444,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Config",
|
||||
@@ -639,14 +557,6 @@
|
||||
"Checks": [
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Config",
|
||||
@@ -724,26 +634,6 @@
|
||||
"inspector2_is_enabled",
|
||||
"inspector2_active_findings_exist"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Config",
|
||||
@@ -931,26 +821,6 @@
|
||||
"inspector2_is_enabled",
|
||||
"inspector2_active_findings_exist"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Config",
|
||||
@@ -1114,14 +984,6 @@
|
||||
"cloudfront_distributions_https_enabled",
|
||||
"s3_bucket_secure_transport_policy"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS CloudWatch",
|
||||
@@ -1195,14 +1057,6 @@
|
||||
"ssm_document_secrets",
|
||||
"secretsmanager_automatic_rotation_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS CloudHSM",
|
||||
@@ -1289,14 +1143,6 @@
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434",
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Network Firewall",
|
||||
@@ -1372,14 +1218,6 @@
|
||||
"s3_bucket_default_encryption",
|
||||
"rds_instance_storage_encrypted"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Config",
|
||||
@@ -1426,20 +1264,6 @@
|
||||
"securityhub_enabled",
|
||||
"macie_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Config",
|
||||
@@ -1617,20 +1441,6 @@
|
||||
"s3_bucket_object_versioning",
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS CloudEndure Disaster Recovery",
|
||||
@@ -1708,20 +1518,6 @@
|
||||
"efs_have_backup_enabled",
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS CloudEndure Disaster Recovery",
|
||||
@@ -1770,20 +1566,6 @@
|
||||
"drs_job_exist",
|
||||
"config_recorder_all_regions_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS CloudEndure Disaster Recovery",
|
||||
@@ -1857,14 +1639,6 @@
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434",
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Shield",
|
||||
@@ -1912,14 +1686,6 @@
|
||||
"drs_job_exist",
|
||||
"rds_instance_backup_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "drs_job_exist",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS CloudEndure Disaster Recovery",
|
||||
@@ -1977,20 +1743,6 @@
|
||||
"cloudwatch_log_metric_filter_sign_in_without_mfa",
|
||||
"cloudwatch_log_metric_filter_unauthorized_api_calls"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS CloudWatch",
|
||||
@@ -2067,20 +1819,6 @@
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434",
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "config_recorder_all_regions_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Config",
|
||||
@@ -2172,20 +1910,6 @@
|
||||
"iam_policy_no_full_access_to_cloudtrail",
|
||||
"iam_policy_no_full_access_to_kms"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS Organizations",
|
||||
@@ -2269,14 +1993,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "Amazon GuardDuty",
|
||||
@@ -2355,14 +2071,6 @@
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_sql_server_1433_1434",
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"AWSService": "AWS IoT Device Defender",
|
||||
|
||||
@@ -597,14 +597,6 @@
|
||||
"accessanalyzer_enabled",
|
||||
"cloudwatch_log_metric_filter_root_usage"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "3 INCIDENT HANDLING (ARTICLE 21(2), POINT (B), OF DIRECTIVE (EU) 2022/2555)",
|
||||
@@ -1519,17 +1511,6 @@
|
||||
"Checks": [
|
||||
"acm_certificates_with_secure_key_algorithms"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "9 CRYPTOGRAPHY (ARTICLE 21(2), POINT (H), OF DIRECTIVE (EU) 2022/2555)",
|
||||
@@ -1547,17 +1528,6 @@
|
||||
"route53_domains_privacy_protection_enabled",
|
||||
"iam_no_expired_server_certificates_stored"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "acm_certificates_with_secure_key_algorithms",
|
||||
"ConfigKey": "insecure_key_algorithms",
|
||||
"Operator": "superset",
|
||||
"Value": [
|
||||
"RSA-1024",
|
||||
"P-192"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "9 CRYPTOGRAPHY (ARTICLE 21(2), POINT (H), OF DIRECTIVE (EU) 2022/2555)",
|
||||
@@ -1675,14 +1645,6 @@
|
||||
"efs_access_point_enforce_user_identity",
|
||||
"efs_not_publicly_accessible"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "11 ACCESS CONTROL (ARTICLE 21(2), POINTS (I) AND (J), OF DIRECTIVE (EU) 2022/2555)",
|
||||
@@ -1714,14 +1676,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "11 ACCESS CONTROL (ARTICLE 21(2), POINTS (I) AND (J), OF DIRECTIVE (EU) 2022/2555)",
|
||||
@@ -1772,14 +1726,6 @@
|
||||
"Checks": [
|
||||
"accessanalyzer_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "accessanalyzer_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
],
|
||||
"Attributes": [
|
||||
{
|
||||
"Section": "11 ACCESS CONTROL (ARTICLE 21(2), POINTS (I) AND (J), OF DIRECTIVE (EU) 2022/2555)",
|
||||
|
||||
@@ -230,20 +230,6 @@
|
||||
"rds_instance_integration_cloudwatch_logs",
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -335,20 +321,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -372,14 +344,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"rds_instance_integration_cloudwatch_logs",
|
||||
"s3_bucket_server_access_logging_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -419,20 +383,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -450,20 +400,6 @@
|
||||
"cloudtrail_cloudwatch_logging_enabled",
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -717,9 +653,6 @@
|
||||
"apigateway_restapi_client_certificate_enabled",
|
||||
"ec2_ebs_volume_encryption",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"cloudfront_distributions_pqc_tls_enabled",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"opensearch_service_domains_node_to_node_encryption_enabled",
|
||||
"s3_bucket_default_encryption",
|
||||
"s3_bucket_secure_transport_policy"
|
||||
@@ -751,20 +684,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -793,20 +712,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -824,20 +729,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -855,20 +746,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"guardduty_no_high_severity_findings",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -892,20 +769,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"rds_instance_enhanced_monitoring_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -943,20 +806,6 @@
|
||||
"ec2_networkacl_allow_ingress_any_port",
|
||||
"ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22",
|
||||
"ec2_networkacl_allow_ingress_any_port"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1176,20 +1025,6 @@
|
||||
"Checks": [
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1209,20 +1044,6 @@
|
||||
"securityhub_enabled",
|
||||
"ssm_managed_compliant_patching",
|
||||
"ssm_managed_compliant_patching"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1240,20 +1061,6 @@
|
||||
"guardduty_is_enabled",
|
||||
"securityhub_enabled",
|
||||
"ssm_managed_compliant_patching"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1269,14 +1076,6 @@
|
||||
],
|
||||
"Checks": [
|
||||
"guardduty_is_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1303,20 +1102,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1343,20 +1128,6 @@
|
||||
"s3_bucket_server_access_logging_enabled",
|
||||
"securityhub_enabled",
|
||||
"vpc_flow_logs_enabled"
|
||||
],
|
||||
"ConfigRequirements": [
|
||||
{
|
||||
"Check": "guardduty_is_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
},
|
||||
{
|
||||
"Check": "securityhub_enabled",
|
||||
"ConfigKey": "mute_non_default_regions",
|
||||
"Operator": "eq",
|
||||
"Value": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||