The most surprising thing about exposing GCP internal services with an Internal HTTPS Load Balancer is that you’re not actually "exposing" them in the traditional sense; you’re creating a tightly controlled ingress point within your VPC that looks like an external service to your internal clients.
Let’s see this in action. Imagine you have a microservice running on GKE, and you want your internal applications to access it securely, but only from within your VPC.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-internal-service
annotations:
kubernetes.io/ingress.class: "gce"
networking.gke.io/internal-load-balancer: "true" # This is the key
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-internal-service
port:
number: 80
When you apply this Ingress resource to your GKE cluster, GCP’s Ingress controller kicks in. It doesn’t provision a public IP. Instead, it creates a ForwardingRule with an INTERNAL load balancing scheme, a private IP address from your VPC’s subnet, and a Google-managed SSL certificate (or one you provide). This forwarding rule then directs traffic to a BackendService, which in turn points to your GKE service’s endpoints (your pods).
The problem this solves is providing secure, reliable, and scalable access to your internal applications without exposing them to the public internet. Think of internal APIs, microservices that shouldn’t be directly callable from the outside, or services that rely on private network connectivity. Traditional external load balancers would require complex firewall rules or VPNs to restrict access. The Internal HTTPS Load Balancer is the restriction, by design.
Internally, it works like this:
- Forwarding Rule: A private IP address is assigned to a forwarding rule in your VPC. This rule listens for incoming traffic on a specific port (usually 443 for HTTPS).
- SSL Policy: An SSL Policy is attached to the forwarding rule, enforcing TLS versions and cipher suites for secure communication.
- Backend Service: The forwarding rule directs traffic to a Backend Service. This service defines how to health check your backends and how to distribute traffic among them.
- Instance Group/NEG: The Backend Service points to a Network Endpoint Group (NEG), which for GKE Ingress, represents your service’s pods. The load balancer then routes traffic directly to these pods.
The exact levers you control are primarily through the Ingress resource and associated GCP resources:
networking.gke.io/internal-load-balancer: "true"annotation: This is the explicit switch to make it an internal load balancer.spec.rules: Defines the hostnames and paths to match.spec.tls: Configures SSL certificates. You can use Google-managed certificates (which GCP provisions and renews automatically for public domain names, but for internal, you’ll often use a self-managed certificate or a cert from a private CA) or provide your own.- Backend Service configuration (often managed by GKE Ingress): Health checks, connection draining, session affinity.
- Forwarding Rule IP Address: You can specify a static internal IP address for the load balancer to use.
When you use a Google-managed SSL certificate with an internal load balancer, it’s crucial to understand that GCP’s certificate manager needs to verify domain ownership. For internal services, this typically means your internal DNS must resolve correctly to the load balancer’s internal IP. If you’re using a custom domain name that’s only resolvable internally (e.g., myapp.internal.company.com), GCP’s automated provisioning might not work out-of-the-box without some DNS configuration pointing to your VPC.
The next concept you’ll run into is how to manage TLS certificates for internal domains, especially if you’re not using a publicly trusted CA.