diff --git a/docs/user-guide/providers/iac/authentication.mdx b/docs/user-guide/providers/iac/authentication.mdx index cea25ec02f..8d1062a868 100644 --- a/docs/user-guide/providers/iac/authentication.mdx +++ b/docs/user-guide/providers/iac/authentication.mdx @@ -11,3 +11,28 @@ Prowler's Infrastructure as Code (IaC) provider enables you to scan local or rem - [**GitHub Username and Personal Access Token (PAT)**](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) - [**GitHub OAuth App Token**](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token) - [**Git URL**](https://git-scm.com/docs/git-clone#_git_urls) + +### Private Repository Hosts + +By default Prowler rejects a repository URL that resolves to a non-public address, as an SSRF defense. The check runs before the connection test and before the scan clones the repository, so a self-hosted GitLab, Gitea or Bitbucket on an internal network is rejected unless the trusted ranges are declared: + +```console +export PROWLER_ALLOWED_PRIVATE_NETWORKS="10.20.0.0/16,192.168.65.254/32" +prowler iac --scan-repository-url https://git.internal/team/infra.git +``` + +The value is a comma-separated list of IPs and CIDRs. A resolved address inside an allowlisted range is permitted; every other non-public address stays blocked, so link-local (`169.254.169.254`), loopback and the rest of the internal network remain protected. Malformed entries are rejected, and a non-empty allowlist is logged as a relaxed security control. When unset, only public addresses are reachable. + +The variable is read by the process that runs the scan: + +- **CLI**: export it in the shell running `prowler`. +- **Docker Compose**: set it in the root `.env`; it reaches the worker through the shared environment file. +- **Helm**: add it under `api.djangoConfig`, which is rendered into the API ConfigMap that the worker inherits through `envFrom`. + +```yaml +api: + djangoConfig: + PROWLER_ALLOWED_PRIVATE_NETWORKS: "10.20.0.0/16" +``` + +In Prowler App the scan runs in the worker, not the API, so setting the variable only on the API container has no effect. The same variable applies to the Kubernetes and OpenStack providers. The Image provider has its own, `PROWLER_IMAGE_PROVIDER_ALLOWED_PRIVATE_NETWORKS`. diff --git a/prowler/lib/network/ssrf.py b/prowler/lib/network/ssrf.py index 30f5e9b861..514c062995 100644 --- a/prowler/lib/network/ssrf.py +++ b/prowler/lib/network/ssrf.py @@ -126,7 +126,10 @@ def validate_outbound_host(host: str) -> None: for address in addresses: if _ip_is_non_public(address) and not _ip_is_allowlisted(address, networks): raise OutboundURLNotAllowedError( - f"Host {host!r} resolves to non-public address {address} and cannot be reached" + f"Host {host!r} resolves to non-public address {address} and cannot be " + f"reached. To scan a target on a private network, list the trusted " + f"ranges in the {ALLOWED_PRIVATE_NETWORKS_ENV} environment variable of " + f"the process running the scan" )