Back to blog
Best PracticesCloud SecurityGCPNetworkingOperations & Compliance

Load Balancer SSL Policy Allows Weak Ciphers on GCP

Learn why GCP load balancer SSL policies allowing weak ciphers or old TLS versions are a risk, and how to enforce TLS 1.2 with gcloud, Terraform, and policy-as-code.

TL;DR

This check flags GCP load balancer SSL policies that permit outdated TLS versions (1.0/1.1) or weak cipher suites, leaving HTTPS traffic open to downgrade and decryption attacks. Fix it by attaching a MODERN or RESTRICTED SSL policy with a minimum TLS version of 1.2 to your target HTTPS proxy.

HTTPS in front of your application is only as strong as the cipher suites and TLS versions it accepts. A load balancer that still negotiates TLS 1.0 or offers RC4 and 3DES gives an attacker the room they need to force a weaker connection and chip away at the encryption protecting your users. The lb_insecureciphers check looks at the SSL policies attached to your GCP load balancers and reports any that allow insecure protocol versions or weak ciphers.

This post walks through what the check inspects, why a weak SSL policy is a real liability, and exactly how to bring your load balancers up to a modern TLS baseline.


What this check detects

In Google Cloud, external HTTPS and SSL proxy load balancers use SSL policies to control two things:

  • The minimum TLS version the load balancer will negotiate (1.0, 1.1, or 1.2).
  • The profile, which determines the set of cipher suites on offer (COMPATIBLE, MODERN, RESTRICTED, or CUSTOM).

If you never attach an SSL policy, the load balancer falls back to a default that allows TLS 1.0 and a broad COMPATIBLE cipher set for maximum client reach. The Lensix check flags a target proxy as insecure when either of the following is true:

  • The effective minimum TLS version is below 1.2.
  • The profile (or a CUSTOM policy's explicit cipher list) includes ciphers considered weak, such as those using CBC mode with SHA-1, 3DES, or RC4.

Note: SSL policies are separate resources from the load balancer itself. You create a policy once, then attach it to one or more target HTTPS or SSL proxies. A proxy with no attached policy uses Google's permissive default, which is exactly the case this check is designed to catch.


Why it matters

Weak TLS is not a theoretical concern. The protocol versions and ciphers this check flags have well-documented, named attacks behind them.

Downgrade and protocol attacks

TLS 1.0 and 1.1 are vulnerable to attacks like BEAST and POODLE, and they rely on cryptographic primitives (MD5, SHA-1) that no longer hold up. An attacker positioned on the network path can attempt to force a client and your load balancer to negotiate down to one of these versions, then exploit the weaknesses to recover plaintext from the session.

Weak ciphers leak data over time

Cipher suites using RC4 or 3DES have practical weaknesses. The SWEET32 attack, for example, targets 64-bit block ciphers like 3DES and can recover session cookies given enough captured traffic. Ciphers without forward secrecy mean that a single compromise of your private key retroactively exposes every session ever recorded.

Compliance failures

PCI DSS has required disabling TLS 1.0 since 2018. SOC 2, HIPAA, and most internal security baselines expect TLS 1.2 or higher with strong ciphers. An auditor running a scan against your public endpoint will find a permissive SSL policy quickly, and it is the kind of finding that turns a clean report into a remediation cycle.

Warning: Tightening TLS can break very old clients. RESTRICTED with a 1.2 minimum drops support for clients that cannot do modern ciphers, which in practice means devices and browsers from before roughly 2014. Check your access logs for legacy user agents before enforcing the strictest profile on a consumer-facing endpoint.


How to fix it

The fix is two steps: create an SSL policy with a sane baseline, then attach it to the affected target proxy.

Step 1: Choose a profile

  • MODERN — TLS 1.2 minimum, strong ciphers, still supports a reasonable range of clients. A good default for public web traffic.
  • RESTRICTED — TLS 1.2 minimum, only the strongest ciphers with forward secrecy. Use this where compliance demands it and you control the clients.
  • CUSTOM — You pick the exact cipher list. Only reach for this if you have a specific requirement.

Step 2: Create the SSL policy

gcloud compute ssl-policies create lensix-modern-policy \
  --profile MODERN \
  --min-tls-version 1.2 \
  --global

Step 3: Attach it to your target proxy

First, find the target HTTPS proxy in front of your load balancer:

gcloud compute target-https-proxies list

Then attach the policy:

Warning: Attaching a stricter SSL policy changes which clients can connect. This takes effect on new connections within a minute or two. Roll it out during a low-traffic window for production endpoints and watch your TLS handshake error rate.

gcloud compute target-https-proxies update my-https-proxy \
  --ssl-policy lensix-modern-policy \
  --global

For an SSL proxy load balancer, the command is the equivalent target-ssl-proxies update.

Verify the change

gcloud compute ssl-policies describe lensix-modern-policy --global

You should see minTlsVersion: TLS_1_2 and profile: MODERN. To confirm from the outside, run a quick scan against your endpoint:

nmap --script ssl-enum-ciphers -p 443 your-domain.example.com

The output should list only TLSv1.2 and TLSv1.3 with no ciphers graded below A.

Tip: One SSL policy can be attached to many proxies. Create a single organization-standard policy named something obvious like org-tls-baseline and reuse it everywhere instead of letting each team invent their own.


Fixing it with Terraform

If your load balancers are managed as code, bake the policy into the module so the secure baseline is the default and not an afterthought.

resource "google_compute_ssl_policy" "modern" {
  name            = "lensix-modern-policy"
  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.id
}

The key line is ssl_policy on the proxy. Without it, Terraform happily creates a proxy that uses Google's permissive default, and the check will fire on your next scan.


How to prevent it from happening again

Remediating once is fine. Making it impossible to ship an insecure proxy again is better.

Require an SSL policy in your IaC review

Use a policy-as-code tool to reject any google_compute_target_https_proxy that does not reference an SSL policy. Here is the idea expressed as an OPA/Rego rule against a Terraform plan:

package terraform.tls

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 this into a conftest step in CI so a missing or weak policy fails the pull request before it ever reaches Google Cloud.

Add an organization policy constraint

GCP supports a built-in organization policy constraint, constraints/compute.requireSslPolicy, that prevents creating HTTPS or SSL proxies without an attached SSL policy. Enforce it at the org or folder level so new projects inherit the guardrail automatically.

Note: The org policy constraint enforces that a policy is attached, not that the policy is strong. Pair it with a CI check or a Lensix scan that validates the minimum TLS version and profile so a weak custom policy cannot slip through.

Schedule continuous scanning

Drift happens. Someone creates a new proxy by hand during an incident, or a custom policy gets edited. Keep lb_insecureciphers running on a schedule in Lensix so any new weak policy surfaces within hours rather than at the next audit.


Best practices

  • Default to TLS 1.2 minimum everywhere. There is no good reason to negotiate 1.0 or 1.1 in 2024. Most clients you care about already support 1.2 and 1.3.
  • Prefer forward-secret ciphers. ECDHE-based suites mean a stolen private key cannot decrypt past traffic. MODERN and RESTRICTED profiles handle this for you.
  • Standardize on one or two named policies. Fewer policies means fewer places for a weak setting to hide and a much easier story to tell an auditor.
  • Test before you tighten. Move from COMPATIBLE to MODERN first, watch handshake errors, then go to RESTRICTED only if your client base supports it.
  • Treat the SSL policy as part of the load balancer, not an add-on. If it lives in your Terraform module by default, nobody has to remember to attach it.

A secure SSL policy costs nothing to run and takes about five minutes to apply. Attach a MODERN policy with a 1.2 minimum, gate it in CI, and this check stays green from then on.