A GCP HTTPS target proxy without a custom SSL policy falls back to Google's default, which still permits TLS 1.0 and weak ciphers. Attach a custom SSL policy with a minimum TLS version of 1.2 (or use the RESTRICTED profile) to close the gap.
When you put an HTTPS load balancer in front of your application on Google Cloud, the target HTTPS proxy is the component that terminates TLS. It decides which protocol versions and cipher suites clients are allowed to negotiate. If you never attach a custom SSL policy to that proxy, GCP uses its default policy, and the default still accepts TLS 1.0.
That is the gap this check flags. The lb_nosslpolicy check looks at every HTTPS target proxy in your project and reports any that have no SSL policy attached, meaning they are running on Google's permissive defaults.
What this check detects
The check inspects each targetHttpsProxy resource and looks at its sslPolicy field. If that field is empty, the proxy has no custom policy and inherits the default GCP behavior.
Here is what the default policy permits:
- Minimum TLS version: TLS 1.0
- Profile: COMPATIBLE, which enables the broadest set of cipher suites for older clients
Note: An SSL policy in GCP is a separate, reusable resource. You create it once, then attach it to one or more target HTTPS proxies (and target SSL proxies). A single policy can govern many load balancers, which makes standardizing minimum TLS versions across a project straightforward.
A clean result means every HTTPS proxy points to a policy you control. A failing result means at least one proxy is silently accepting connections you probably do not want.
Why it matters
TLS 1.0 was deprecated in 2018. It is vulnerable to known attacks like BEAST and POODLE (via downgrade), and it relies on cipher suites and hashing that are no longer considered safe. TLS 1.1 is in the same boat. The major browsers removed support for both years ago, but an attacker or an automated scanner does not use a browser. They use whatever protocol your endpoint is willing to negotiate.
The practical risks fall into a few buckets:
- Downgrade attacks. A man-in-the-middle can attempt to force a client and server down to the weakest mutually supported protocol. If your proxy still speaks TLS 1.0, that floor is much lower than it should be.
- Compliance failures. PCI DSS has required TLS 1.1 or higher (with TLS 1.2 strongly recommended) since 2018. HIPAA, SOC 2, and most internal security baselines expect TLS 1.2 as a minimum. An external scan that finds TLS 1.0 enabled is a common audit finding.
- Weak cipher exposure. The COMPATIBLE profile includes cipher suites kept around for legacy interoperability. Some use older key exchange or no forward secrecy, which weakens the confidentiality of recorded traffic.
The frustrating part is that none of this shows up in normal traffic. Your application works fine for modern clients, so the misconfiguration sits quietly until a penetration test or a compliance scan surfaces it. By then it is a finding with a deadline attached.
Warning: Before you raise the minimum TLS version, check whether any real clients still need older protocols. IoT devices, embedded systems, and old API integrations sometimes only support TLS 1.0 or 1.1. Tightening the policy will break those connections. Review your load balancer logs for negotiated TLS versions first.
How to fix it
The fix has two steps: create an SSL policy with a sane minimum TLS version, then attach it to the affected proxy.
Step 1: Create an SSL policy
You have two reasonable starting points. Use the MODERN profile with a minimum of TLS 1.2 for broad compatibility, or the RESTRICTED profile if you want to enforce only the strongest cipher suites.
gcloud compute ssl-policies create lensix-modern-tls12 \
--profile MODERN \
--min-tls-version 1.2 \
--description "Minimum TLS 1.2, modern cipher suites"
If your compliance posture demands it, the RESTRICTED profile drops everything except cipher suites with forward secrecy and authenticated encryption:
gcloud compute ssl-policies create lensix-restricted-tls12 \
--profile RESTRICTED \
--min-tls-version 1.2 \
--description "TLS 1.2 minimum, restricted cipher set"
Note: The three Google-managed profiles are COMPATIBLE, MODERN, and RESTRICTED, in increasing order of strictness. There is also a CUSTOM profile that lets you pick individual cipher suites by name if you need surgical control.
Step 2: Attach the policy to the target proxy
First find the proxy name that the check flagged:
gcloud compute target-https-proxies list
Then attach the policy:
gcloud compute target-https-proxies update my-https-proxy \
--ssl-policy lensix-modern-tls12
Danger: This change takes effect on new connections almost immediately. If any active client only supports TLS 1.0 or 1.1, its next handshake will fail. Roll this out during a maintenance window for customer-facing load balancers, and confirm your client base from access logs before applying it to production.
Verify the change
Confirm the policy is attached:
gcloud compute target-https-proxies describe my-https-proxy \
--format="value(sslPolicy)"
Then test the endpoint directly. A TLS 1.0 handshake should now be refused:
# Should fail after the fix
openssl s_client -connect your-domain.com:443 -tls1
# Should succeed
openssl s_client -connect your-domain.com:443 -tls1_2
Fixing it as code
If you manage your load balancers with Terraform, define the policy once and reference it from every proxy. This is the durable fix, because it stops new proxies from shipping without a policy.
resource "google_compute_ssl_policy" "modern_tls12" {
name = "lensix-modern-tls12"
profile = "MODERN"
min_tls_version = "TLS_1_2"
}
resource "google_compute_target_https_proxy" "default" {
name = "my-https-proxy"
url_map = google_compute_url_map.default.id
ssl_certificates = [google_compute_ssl_certificate.default.id]
ssl_policy = google_compute_ssl_policy.modern_tls12.id
}
The key line is ssl_policy. Without it, Terraform creates the proxy and the default policy applies, which is exactly the state this check fails on.
Tip: Make the SSL policy a shared module output and pass it into every load balancer module in your organization. That way teams cannot forget to attach one, because there is no code path that builds a proxy without it.
How to prevent it from happening again
One-time remediation does not stick if the next proxy gets created the same way. Build a guardrail.
Catch it in CI with policy-as-code
If you use Terraform, an OPA or Conftest policy can fail the plan when a proxy has no SSL policy. A minimal Rego rule:
package terraform.gcp.ssl
deny[msg] {
resource := input.resource_changes[_]
resource.type == "google_compute_target_https_proxy"
not resource.change.after.ssl_policy
msg := sprintf("HTTPS proxy '%s' has no SSL policy attached", [resource.address])
}
Wire that into your pipeline so a pull request that adds an unprotected proxy never merges.
Enforce a minimum TLS version organization-wide
GCP has an organization policy constraint, compute.requireSslPolicy, that you can apply at the org or folder level to require every applicable proxy to use an SSL policy. Pair it with a baseline policy your teams reference and you have a hard floor rather than a convention.
Monitor continuously
New regions, new teams, and quick fixes during incidents all introduce drift. Lensix runs lb_nosslpolicy on a schedule, so a proxy that ships without a policy gets flagged within the next scan instead of waiting for the annual pen test.
Best practices
- Standardize on TLS 1.2 as the absolute minimum, and plan to move to TLS 1.3 where your clients support it. New deployments should not start below 1.2.
- Use one or two shared SSL policies per organization, not a bespoke policy per load balancer. Fewer policies means consistent enforcement and a single place to raise the bar later.
- Prefer the RESTRICTED profile for internal and high-sensitivity endpoints, where you control the clients and do not need legacy cipher support.
- Check negotiated TLS versions in your logs before tightening, so you know exactly which clients a change will affect.
- Apply the same discipline to target SSL proxies, not just HTTPS proxies. The SSL policy resource attaches to both.
- Revisit your policy yearly. Cipher recommendations move. A policy set to "modern" in 2021 is not the modern baseline today.
The whole problem here is one empty field on a proxy. Fixing it is a two-command change, and preventing it is a single line in your Terraform plus a CI check. The cost of leaving it is a recurring audit finding and a real downgrade risk, so it is worth closing out properly the first time.

