linode / linode/linode-cloud-controller-manager

Set LoadBalancer ingress IPMode to prevent kube-proxy from short-circuiting LoadBalancer traffic

Open
#533 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
94
Forks
75
Avg merge
11h 19m
Merged PRs (30d)
20

Description

## Problem

The CCM does not set the `ipMode` field on `LoadBalancerIngress` entries. Without this, kube-proxy binds the LoadBalancer IP to every node and intercepts traffic destined for it, bypassing the NodeBalancer entirely for
cluster-internal requests.

This causes a well-known class of failures when proxy protocol is enabled on the NodeBalancer: internal traffic (e.g. cert-manager HTTP01 validation, in-cluster requests to LoadBalancer IPs) reaches the ingress controller
without the expected PROXY protocol header, resulting in `broken header` errors and failed requests.

See: [cert-manager/cert-manager#466](https://github.com/cert-manager/cert-manager/issues/466)

The current workaround is deploying [hairpin-proxy](https://github.com/compumike/hairpin-proxy), which intercepts DNS and injects PROXY protocol headers for internal traffic. This shouldn't be necessary.

## Solution

[KEP-1860](https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/1860-kube-proxy-IP-node-binding) added an `ipMode` field to `LoadBalancerIngress` with two values:

- **`VIP`**: kube-proxy binds the LB IP to nodes (current default behavior)
- **`Proxy`**: kube-proxy does not intercept LB traffic, forcing it through the actual LoadBalancer

The CCM should set this field based on proxy protocol configuration. When all ports on a service use proxy protocol, `ipMode` should be `Proxy` so that kube-proxy doesn't short-circuit traffic around the NodeBalancer.
Otherwise it should be `VIP`.

A manual override annotation (`service.beta.kubernetes.io/linode-loadbalancer-ip-mode`) would also be useful for edge cases.

## Reference implementation

I've put together an implementation in [this commit](https://github.com/marvin-w/linode-cloud-controller-manager/commit/ca6880225a01753321017b95024d8b5bc4daa28d) that:

1. Adds a `getIPMode()` helper that auto-detects from proxy protocol config or reads an annotation override
2. Sets `IPMode` on all `LoadBalancerIngress` entries in `makeLoadBalancerStatus()` (all three return paths: hostname-only, IPv6, default)
3. Includes tests and documentation

The Kubernetes API types (`LoadBalancerIPModeVIP`, `LoadBalancerIPModeProxy`) are already available in the k8s.io/api version used by this project.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at makeLoadBalancerStatus() and inspect the referenced implementation's getIPMode() helper, proxy protocol configuration, and annotation handling. Review the linked commit and its tests and documentation; done means all LoadBalancerIngress return paths set Proxy or VIP correctly, including the manual override behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, kubernetes
Domain
cloud, infrastructure
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.