This check flags GCP Cloud Functions configured to accept ingress from all sources, meaning anyone on the public internet can reach the function endpoint. Lock it down by setting ingress settings to internal-only or internal-and-gclb, and put authentication or a load balancer in front of anything that genuinely needs public access.
Cloud Functions are easy to deploy and easy to forget about. A few clicks or a single gcloud command later, you have a live HTTPS endpoint running your code. The default ingress setting on many functions is allow all, which means the function is reachable from the entire internet. That is convenient during development and risky in production, especially when the function talks to internal services, databases, or sensitive data.
This Lensix check, functions_ingressall, identifies any GCP Cloud Function whose ingress settings permit traffic from all sources. Below we cover what that actually means, why it deserves your attention, and how to fix it without breaking the things that depend on the function.
What this check detects
Every Cloud Function has an ingress settings property that controls where inbound traffic can originate. GCP offers three values:
- ALLOW_ALL — the function accepts requests from the public internet.
- ALLOW_INTERNAL_ONLY — only traffic from within the same VPC network, or from resources that share the project's VPC Service Controls perimeter, can reach the function.
- ALLOW_INTERNAL_AND_GCLB — internal traffic plus traffic that arrives through a Google Cloud external HTTP(S) Load Balancer.
The check raises a finding whenever a function is set to ALLOW_ALL. It does not assume the function is automatically vulnerable, but it flags it as an exposed surface that needs a deliberate decision behind it.
Note: Ingress settings are separate from authentication. A function can have ALLOW_ALL ingress but still require an authenticated IAM identity to invoke it. Both layers matter, and a function that is both publicly reachable and allows unauthenticated invocation is the worst case.
Why it matters
An open ingress setting turns your function into a publicly addressable target. The risk depends on what the function does, but the patterns below show up repeatedly in real incidents.
Unauthenticated functions become open APIs
If the function permits unauthenticated invocation (allUsers has the cloudfunctions.invoker role) and ingress is open, anyone who finds the URL can run it. Function URLs are not secret. They follow predictable patterns and show up in logs, browser history, client-side code, and crawler datasets. Attackers scan for them.
Data exposure and abuse
A function that queries a database, reads from Cloud Storage, or returns customer records can leak that data straight to the internet if access control is weak. Even read-only functions can be scraped at scale.
Cost and denial-of-wallet
Cloud Functions bill per invocation and per compute-second. A publicly reachable function with no rate limiting can be hammered, and you pay for every request. This is the serverless version of a denial-of-wallet attack.
Warning: Functions that call paid third-party APIs (payment processors, SMS gateways, LLM providers) amplify this. An attacker triggering thousands of invocations can run up real charges on services you do not control, not just your GCP bill.
Pivot into internal systems
Functions often have a service account with permissions to reach other GCP resources. A function exposed to the internet that also has a Serverless VPC Access connector becomes a bridge between the public internet and your private network. If the function has an injection flaw or weak input validation, that bridge can be abused to reach internal services that were never meant to be public.
How to fix it
The fix is to restrict ingress to the narrowest setting that still meets the function's real requirements. Work through this in order.
Step 1: Identify the exposed functions
List functions and check their ingress settings across your project:
gcloud functions list --format="table(name, httpsTrigger.url, ingressSettings)"
For a single function, inspect it in detail:
gcloud functions describe MY_FUNCTION \
--region=us-central1 \
--format="value(ingressSettings)"
Step 2: Decide what the function actually needs
Ask one question: does anything outside Google Cloud need to call this function directly?
- No, only other GCP services call it → use
internal-only. - Yes, but it should sit behind a load balancer (for WAF, Cloud Armor, custom domain) → use
internal-and-gclb. - Yes, it is a genuinely public endpoint (webhook receiver, public API) → keep it open, but harden it (see Step 4).
Step 3: Restrict ingress
For a 1st gen Cloud Function:
gcloud functions deploy MY_FUNCTION \
--region=us-central1 \
--ingress-settings=internal-only \
--trigger-http
For a 2nd gen Cloud Function (or Cloud Run functions), the flag is the same on deploy:
gcloud functions deploy MY_FUNCTION \
--gen2 \
--region=us-central1 \
--ingress-settings=internal-and-gclb
Danger: Changing ingress to internal-only will immediately cut off any external caller, including third-party webhooks, CI/CD pipelines, or front-end apps. Confirm the full list of callers before you flip this on a production function, or you will cause an outage.
Step 4: Lock down authentication too
Ingress controls where traffic comes from. IAM controls who can invoke. Remove unauthenticated access if the function does not need it:
gcloud functions remove-invoker-policy-binding MY_FUNCTION \
--region=us-central1 \
--member="allUsers"
Then grant the invoker role only to the specific identities that should call it:
gcloud functions add-invoker-policy-binding MY_FUNCTION \
--region=us-central1 \
--member="serviceAccount:[email protected]"
Step 5: Fix it in the console (alternative)
- Open Cloud Functions in the GCP console and select the function.
- Click Edit.
- Expand Runtime, build, connections and security settings.
- Under the Connections tab, set Ingress settings to Allow internal traffic only or Allow internal traffic and traffic from Cloud Load Balancing.
- Click Next, then Deploy.
Fixing it in infrastructure as code
If you manage functions with Terraform, set ingress explicitly so it never drifts back to the default. For a 2nd gen function:
resource "google_cloudfunctions2_function" "api" {
name = "internal-api"
location = "us-central1"
build_config {
runtime = "nodejs20"
entry_point = "handler"
source {
storage_source {
bucket = google_storage_bucket.source.name
object = google_storage_bucket_object.source.name
}
}
}
service_config {
ingress_settings = "ALLOW_INTERNAL_ONLY"
all_traffic_on_latest_revision = true
service_account_email = google_service_account.fn.email
}
}
For a 1st gen function:
resource "google_cloudfunctions_function" "api" {
name = "internal-api"
runtime = "nodejs20"
ingress_settings = "ALLOW_INTERNAL_ONLY"
trigger_http = true
# ...
}
Tip: Make ingress_settings a required module variable with no default in your shared Terraform module. That forces every team deploying a function to make a conscious choice instead of silently inheriting ALLOW_ALL.
How to prevent it from happening again
Manual fixes do not scale. Stop open ingress before it ships.
Enforce with Organization Policy
GCP provides a managed constraint that restricts allowed ingress settings for Cloud Functions and Cloud Run. Apply it at the org or folder level so no project can deploy a publicly reachable function:
gcloud resource-manager org-policies allow \
cloudfunctions.allowedIngressSettings \
ALLOW_INTERNAL_ONLY ALLOW_INTERNAL_AND_GCLB \
--project=my-project
With this in place, any deploy attempting ALLOW_ALL is rejected by the platform itself, which is far stronger than a downstream scan.
Gate it in CI/CD with policy as code
Catch the misconfiguration in pull requests before anything reaches GCP. With Conftest and OPA, a policy like this blocks a Terraform plan that allows all ingress:
package main
deny[msg] {
resource := input.resource_changes[_]
resource.type == "google_cloudfunctions2_function"
ingress := resource.change.after.service_config[_].ingress_settings
ingress == "ALLOW_ALL"
msg := sprintf("Function '%s' allows all ingress. Use ALLOW_INTERNAL_ONLY or ALLOW_INTERNAL_AND_GCLB.", [resource.address])
}
Wire it into your pipeline:
terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > tfplan.json
conftest test tfplan.json --policy policy/
Continuously monitor with Lensix
Org policy and CI gates cover new and managed resources. Lensix runs the functions_ingressall check across your accounts on an ongoing basis, so functions created out-of-band (console clicks, scripts, legacy deployments) still get caught and surfaced with the remediation steps above.
Best practices
- Default to internal. Treat
ALLOW_INTERNAL_ONLYas the starting point and open up only when there is a clear external caller. - Put public functions behind a load balancer. Use
ALLOW_INTERNAL_AND_GCLBwith an external HTTPS load balancer and Cloud Armor for WAF rules, rate limiting, and geo restrictions. - Layer ingress with IAM. Restrict where traffic comes from and who is allowed to invoke. Never leave
allUsersas an invoker unless the function is intentionally public. - Scope the service account. Give each function a dedicated service account with only the permissions it needs, so an exposed function cannot pivot widely.
- Watch the VPC connector. A function with both open ingress and a Serverless VPC Access connector is a public-to-private bridge. Review these pairings carefully.
- Log and alert. Enable Cloud Audit Logs for function invocations and set alerts on unusual invocation spikes to catch abuse and denial-of-wallet attempts early.
Restricting ingress is one of the cheapest, highest-impact controls you can apply to serverless workloads. It costs nothing, takes one flag, and removes an entire class of internet-facing exposure.

