Skip to content

Commit 43bbcb7

Browse files
committed
improve proxy healthz checking
1 parent 155cd10 commit 43bbcb7

File tree

5 files changed

+90
-1
lines changed

5 files changed

+90
-1
lines changed

cmd/kube-rbac-proxy/app/kube-rbac-proxy.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ func Run(cfg *server.KubeRBACProxyConfig) error {
249249
return err
250250
}
251251

252+
var stoppedCh, listenerStoppedCh <-chan struct{}
252253
go func() {
253254
defer wg.Done()
254255
defer cancel()
@@ -263,11 +264,15 @@ func Run(cfg *server.KubeRBACProxyConfig) error {
263264
<-stoppedCh
264265
}()
265266

267+
cfg.SecureServing.Cert.CurrentCertKeyContent()
268+
266269
if cfg.KubeRBACProxyInfo.ProxyEndpointsSecureServing != nil {
267270
// we need a second listener in order to serve proxy-specific endpoints
268271
// on a different port (--proxy-endpoints-port)
269272
proxyEndpointsMux := http.NewServeMux()
270-
proxyEndpointsMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("ok")) })
273+
proxyEndpointsMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
274+
proxyHealtzCheck(w, cfg.SecureServing.Listener.Addr().String(), listenerStoppedCh, stoppedCh)
275+
})
271276

272277
if err := wg.Add(1); err != nil {
273278
return err
@@ -354,3 +359,31 @@ func setupAuthorizer(krbInfo *server.KubeRBACProxyInfo, delegatedAuthz *serverco
354359

355360
return rewritingAuthorizer, nil
356361
}
362+
363+
func proxyHealtzCheck(w http.ResponseWriter, localProxyAddr string, listenerStoppedChan, stoppedChan <-chan struct{}) {
364+
select {
365+
case <-stoppedChan:
366+
http.Error(w, "the proxying port serving logic has stopped", http.StatusServiceUnavailable)
367+
return
368+
case <-listenerStoppedChan:
369+
http.Error(w, "listener stopped", http.StatusServiceUnavailable)
370+
return
371+
default:
372+
}
373+
374+
// we need the tls.Dialer otherwise the server would log EOF for TLS handshakes
375+
// since the connection would be cut before that was ever attempted
376+
dialer := tls.Dialer{NetDialer: &net.Dialer{}, Config: &tls.Config{InsecureSkipVerify: true}}
377+
dialCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
378+
defer cancel()
379+
380+
// we just knock on the other listener as we don't want to trigger proxying to upstream
381+
conn, err := dialer.DialContext(dialCtx, "tcp", localProxyAddr)
382+
if err != nil {
383+
http.Error(w, "failed to connect to the proxying listener", http.StatusInternalServerError)
384+
klog.Errorf("failed to connect to the proxying listener: %v", err)
385+
return
386+
}
387+
_ = conn.Close()
388+
_, _ = w.Write([]byte("ok"))
389+
}

test/e2e/basics.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,3 +519,47 @@ func testIgnorePaths(client kubernetes.Interface) kubetest.TestSuite {
519519
}.Run(t)
520520
}
521521
}
522+
523+
func testHealthz(client kubernetes.Interface) kubetest.TestSuite {
524+
return func(t *testing.T) {
525+
command := `curl --connect-timeout 5 -v -s -k --fail https://kube-rbac-proxy.default.svc.cluster.local:8643/healthz`
526+
527+
kubetest.Scenario{
528+
Name: "healtz check",
529+
Description: "check that proxy /healthz works as expected",
530+
531+
Given: kubetest.Actions(
532+
kubetest.CreatedManifests(
533+
client,
534+
"basics/clusterRole.yaml",
535+
"basics/clusterRoleBinding.yaml",
536+
"basics/deployment.yaml",
537+
"basics/service.yaml",
538+
"basics/serviceAccount.yaml",
539+
),
540+
),
541+
When: kubetest.Actions(
542+
kubetest.PodsAreReady(
543+
client,
544+
1,
545+
"app=kube-rbac-proxy",
546+
),
547+
kubetest.ServiceIsReady(
548+
client,
549+
"kube-rbac-proxy",
550+
),
551+
),
552+
Then: kubetest.Actions(
553+
kubetest.ClientLogsContain(
554+
client,
555+
command,
556+
[]string{
557+
"{ [2 bytes data]",
558+
"ok",
559+
},
560+
nil,
561+
),
562+
),
563+
}.Run(t)
564+
}
565+
}

test/e2e/basics/deployment.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,20 @@ spec:
1919
image: quay.io/brancz/kube-rbac-proxy:local
2020
args:
2121
- "--secure-port=8443"
22+
- "--proxy-endpoints-port=8643"
2223
- "--upstream=http://127.0.0.1:8081/"
2324
- "--authentication-skip-lookup"
2425
- "--v=10"
2526
ports:
2627
- containerPort: 8443
2728
name: https
29+
- containerPort: 8643
30+
name: proxy
31+
readinessProbe:
32+
httpGet:
33+
scheme: HTTPS
34+
port: 8643
35+
path: healthz
2836
- name: prometheus-example-app
2937
image: quay.io/brancz/prometheus-example-app:v0.1.0
3038
args:

test/e2e/basics/service.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ spec:
1010
- name: https
1111
port: 8443
1212
targetPort: https
13+
- name: proxy
14+
port: 8643
15+
targetPort: proxy
1316
selector:
1417
app: kube-rbac-proxy

test/e2e/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func TestMain(m *testing.M) {
5252
func Test(t *testing.T) {
5353
tests := map[string]kubetest.TestSuite{
5454
"Basics": testBasics(client),
55+
"Healthz": testHealthz(client),
5556
"H2CUpstream": testH2CUpstream(client),
5657
"IdentityHeaders": testIdentityHeaders(client),
5758
"ClientCertificates": testClientCertificates(client),

0 commit comments

Comments
 (0)