# LoadBalancer Service Stuck Pending

> Flags LoadBalancer Services older than 10 minutes that still have no external IP or hostname assigned.

Source: https://zop.dev/integrations/kubernetes/recommendations/loadbalancer-service-stuck-pending

---

## What pending means for a LoadBalancer Service

Setting `type: LoadBalancer` asks the cloud to build a load balancer for the Service. The
[Service documentation](https://kubernetes.io/docs/concepts/services-networking/service/) notes
that the actual creation happens asynchronously, and that details of the provisioned balancer are
published in `.status.loadBalancer`. Until then, that status holds no address.

A few minutes of pending is normal. Much longer means the request is stuck, and ZopNight's finding
points at the usual suspects on the cloud side: the cloud controller lacking permissions, quota or
subnet capacity. There is also
a Kubernetes-side trap: if `.spec.loadBalancerClass` is set, the default cloud implementation
ignores the Service and a controller matching that class is assumed to be watching. If no such
controller exists, the Service waits forever.

## Listing stuck LoadBalancer Services

```bash
kubectl get services -A -o json | jq -r '
  .items[]
  | select(.spec.type == "LoadBalancer"
      and ((.status.loadBalancer.ingress // []) | length == 0))
  | "\(.metadata.namespace)/\(.metadata.name) class=\(.spec.loadBalancerClass // "default") created=\(.metadata.creationTimestamp)"'
```

Provisioning errors appear as events on the Service:

```bash
kubectl events --for service/<name> -n <namespace>
```

## Three conditions, all required

ZopNight fires only when the Service type is `LoadBalancer`, the Service reads as pending with no
external address, and the Service is at least 10 minutes old by its creation timestamp. Services
of other types are never considered, and a Service whose creation time is unknown is left alone.
The check has no longer window; an address appearing clears it at the next evaluation.

## Outside its scope

The rule does not diagnose why provisioning failed or look at the cloud account. Services that
did get an address are covered for exposure risk by
[Service type LoadBalancer](https://zop.dev/integrations/kubernetes/recommendations/service-type-loadbalancer),
and Ingresses with the equivalent symptom by
[Ingress has no address](https://zop.dev/integrations/kubernetes/recommendations/ingress-has-no-address).

## Unreachable service, no saving

This medium-severity reliability finding has no dollar figure. Clients outside the cluster cannot
reach the Service until an address is assigned.

## Unsticking the load balancer

1. Read the Service events for the error the cloud controller reported.
2. If `loadBalancerClass` is set, confirm a controller for that class is installed and running;
   otherwise remove the field so the default implementation handles it.
3. On EKS, check the subnets carry the tags in the
   [EKS load balancing guide](https://docs.aws.amazon.com/eks/latest/userguide/network-load-balancing.html),
   `kubernetes.io/role/elb` for internet-facing and `kubernetes.io/role/internal-elb` for
   internal load balancers.
4. Check the account's load balancer quotas in the cloud console.
5. If the Service no longer needs to be external, change it to `ClusterIP` or delete it.
