Skip to content

Commit c4bbfc3

Browse files
committed
Fix local password validation when bind-address is set
Signed-off-by: Brad Davidson <[email protected]> (cherry picked from commit d0ea741) Signed-off-by: Brad Davidson <[email protected]>
1 parent ed9df16 commit c4bbfc3

File tree

2 files changed

+255
-11
lines changed

2 files changed

+255
-11
lines changed

pkg/nodepassword/validate.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func GetNodeAuthValidator(ctx context.Context, control *config.Control) NodeAuth
6666
// get client address, to see if deferred node password validation should be allowed when the apiserver
6767
// is not available. Deferred password validation is only allowed for requests from the local client.
6868
client, _, _ := net.SplitHostPort(req.RemoteAddr)
69-
isLocal := client == "127.0.0.1" || client == "::1"
69+
isLocal := client == "127.0.0.1" || client == "::1" || client == control.BindAddress
7070

7171
if secretClient == nil || nodeClient == nil {
7272
if runtime.Core != nil {

pkg/server/handlers/handlers_test.go

+254-10
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"crypto/tls"
1111
"crypto/x509"
1212
"io"
13+
"net"
1314
"net/http"
1415
"net/http/httptest"
1516
"os"
@@ -189,7 +190,7 @@ func Test_UnitHandlers(t *testing.T) {
189190
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
190191
req.Header.Add("k3s-Node-Password", "password")
191192
req.SetBasicAuth("node", control.AgentToken)
192-
withLocalClient(req)
193+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
193194
},
194195
match: func(_ *config.Control) types.GomegaMatcher {
195196
return And(
@@ -208,7 +209,7 @@ func Test_UnitHandlers(t *testing.T) {
208209
Organization: []string{user.NodesGroup},
209210
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
210211
})
211-
withLocalClient(req)
212+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
212213
},
213214
match: func(_ *config.Control) types.GomegaMatcher {
214215
return And(
@@ -305,7 +306,7 @@ func Test_UnitHandlers(t *testing.T) {
305306
prepare: func(control *config.Control, req *http.Request) {
306307
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
307308
req.Header.Add("k3s-Node-Password", "invalid-password")
308-
withLocalClient(req)
309+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
309310
withCertificateRequest(req)
310311
req.SetBasicAuth("node", control.AgentToken)
311312
},
@@ -318,7 +319,250 @@ func Test_UnitHandlers(t *testing.T) {
318319
prepare: func(control *config.Control, req *http.Request) {
319320
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
320321
req.Header.Add("k3s-Node-Password", "invalid-password")
321-
withLocalClient(req)
322+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
323+
withCertificateRequest(req)
324+
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
325+
CommonName: "system:node:" + control.ServerNodeName,
326+
Organization: []string{user.NodesGroup},
327+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
328+
})
329+
},
330+
match: func(_ *config.Control) types.GomegaMatcher {
331+
return HaveHTTPStatus(http.StatusForbidden)
332+
},
333+
},
334+
),
335+
},
336+
},
337+
},
338+
{
339+
//*** tests with runtime core not ready and bind address set ***
340+
name: "no runtime core with bind-address",
341+
controlFunc: func(t *testing.T) (*config.Control, context.CancelFunc) {
342+
control, cancel := getCorelessControl(t)
343+
control.BindAddress = "192.0.2.100"
344+
return control, cancel
345+
},
346+
paths: []pathTest{
347+
//** paths accessible with node cert or agent token, and specific headers **
348+
{
349+
method: http.MethodGet,
350+
path: "/v1-k3s/serving-kubelet.crt",
351+
subs: append(genericFailures,
352+
sub{
353+
name: "valid basic but missing headers",
354+
prepare: func(control *config.Control, req *http.Request) {
355+
req.SetBasicAuth("node", control.AgentToken)
356+
},
357+
match: func(_ *config.Control) types.GomegaMatcher {
358+
return HaveHTTPStatus(http.StatusBadRequest)
359+
},
360+
},
361+
sub{
362+
name: "valid cert but missing headers",
363+
prepare: func(control *config.Control, req *http.Request) {
364+
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
365+
CommonName: "system:node:" + control.ServerNodeName,
366+
Organization: []string{user.NodesGroup},
367+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
368+
})
369+
},
370+
match: func(_ *config.Control) types.GomegaMatcher {
371+
return HaveHTTPStatus(http.StatusBadRequest)
372+
},
373+
},
374+
sub{
375+
name: "valid cert but wrong node name",
376+
prepare: func(control *config.Control, req *http.Request) {
377+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
378+
req.Header.Add("k3s-Node-Password", "password")
379+
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
380+
CommonName: "system:node:k3s-agent-1",
381+
Organization: []string{user.NodesGroup},
382+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
383+
})
384+
},
385+
match: func(_ *config.Control) types.GomegaMatcher {
386+
return HaveHTTPStatus(http.StatusBadRequest)
387+
},
388+
},
389+
sub{
390+
name: "valid cert but nonexistent node",
391+
prepare: func(control *config.Control, req *http.Request) {
392+
req.Header.Add("k3s-Node-Name", "nonexistent")
393+
req.Header.Add("k3s-Node-Password", "password")
394+
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
395+
CommonName: "system:node:nonexistent",
396+
Organization: []string{user.NodesGroup},
397+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
398+
})
399+
},
400+
match: func(_ *config.Control) types.GomegaMatcher {
401+
return HaveHTTPStatus(http.StatusServiceUnavailable)
402+
},
403+
},
404+
sub{
405+
name: "valid basic legacy key",
406+
prepare: func(control *config.Control, req *http.Request) {
407+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
408+
req.Header.Add("k3s-Node-Password", "password")
409+
req.SetBasicAuth("node", control.AgentToken)
410+
},
411+
match: func(_ *config.Control) types.GomegaMatcher {
412+
return HaveHTTPStatus(http.StatusServiceUnavailable)
413+
},
414+
},
415+
sub{
416+
name: "valid cert legacy key",
417+
prepare: func(control *config.Control, req *http.Request) {
418+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
419+
req.Header.Add("k3s-Node-Password", "password")
420+
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
421+
CommonName: "system:node:" + control.ServerNodeName,
422+
Organization: []string{user.NodesGroup},
423+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
424+
})
425+
},
426+
match: func(_ *config.Control) types.GomegaMatcher {
427+
return HaveHTTPStatus(http.StatusServiceUnavailable)
428+
},
429+
},
430+
sub{
431+
name: "valid basic legacy key deferred local password",
432+
prepare: func(control *config.Control, req *http.Request) {
433+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
434+
req.Header.Add("k3s-Node-Password", "password")
435+
req.SetBasicAuth("node", control.AgentToken)
436+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
437+
},
438+
match: func(_ *config.Control) types.GomegaMatcher {
439+
return And(
440+
HaveHTTPStatus(http.StatusOK),
441+
HaveHTTPBody(ContainSubstring("PRIVATE KEY")),
442+
)
443+
},
444+
},
445+
sub{
446+
name: "valid cert legacy key deferred local password",
447+
prepare: func(control *config.Control, req *http.Request) {
448+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
449+
req.Header.Add("k3s-Node-Password", "password")
450+
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
451+
CommonName: "system:node:" + control.ServerNodeName,
452+
Organization: []string{user.NodesGroup},
453+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
454+
})
455+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
456+
},
457+
match: func(_ *config.Control) types.GomegaMatcher {
458+
return And(
459+
HaveHTTPStatus(http.StatusOK),
460+
HaveHTTPBody(ContainSubstring("PRIVATE KEY")),
461+
)
462+
},
463+
},
464+
sub{
465+
name: "valid basic different node",
466+
prepare: func(control *config.Control, req *http.Request) {
467+
req.Header.Add("k3s-Node-Name", "k3s-agent-1")
468+
req.Header.Add("k3s-Node-Password", "password")
469+
req.SetBasicAuth("node", control.AgentToken)
470+
},
471+
match: func(_ *config.Control) types.GomegaMatcher {
472+
return HaveHTTPStatus(http.StatusServiceUnavailable)
473+
},
474+
},
475+
sub{
476+
name: "valid basic bad node password",
477+
prepare: func(control *config.Control, req *http.Request) {
478+
req.Header.Add("k3s-Node-Name", "k3s-agent-1")
479+
req.Header.Add("k3s-Node-Password", "invalid-password")
480+
req.SetBasicAuth("node", control.AgentToken)
481+
},
482+
match: func(_ *config.Control) types.GomegaMatcher {
483+
return HaveHTTPStatus(http.StatusServiceUnavailable)
484+
},
485+
},
486+
),
487+
}, {
488+
method: http.MethodPost,
489+
path: "/v1-k3s/serving-kubelet.crt",
490+
subs: append(genericFailures,
491+
sub{
492+
name: "valid basic client key but bad password",
493+
prepare: func(control *config.Control, req *http.Request) {
494+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
495+
req.Header.Add("k3s-Node-Password", "password")
496+
withCertificateRequest(req)
497+
req.SetBasicAuth("node", control.AgentToken)
498+
},
499+
match: func(_ *config.Control) types.GomegaMatcher {
500+
return HaveHTTPStatus(http.StatusServiceUnavailable)
501+
},
502+
},
503+
sub{
504+
name: "valid cert client key",
505+
prepare: func(control *config.Control, req *http.Request) {
506+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
507+
req.Header.Add("k3s-Node-Password", "password")
508+
withCertificateRequest(req)
509+
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
510+
CommonName: "system:node:" + control.ServerNodeName,
511+
Organization: []string{user.NodesGroup},
512+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
513+
})
514+
},
515+
match: func(_ *config.Control) types.GomegaMatcher {
516+
return HaveHTTPStatus(http.StatusServiceUnavailable)
517+
},
518+
},
519+
sub{
520+
name: "valid basic client key but bad password",
521+
prepare: func(control *config.Control, req *http.Request) {
522+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
523+
req.Header.Add("k3s-Node-Password", "invalid-password")
524+
withCertificateRequest(req)
525+
req.SetBasicAuth("node", control.AgentToken)
526+
},
527+
match: func(_ *config.Control) types.GomegaMatcher {
528+
return HaveHTTPStatus(http.StatusServiceUnavailable)
529+
},
530+
},
531+
sub{
532+
name: "valid cert client key but bad password",
533+
prepare: func(control *config.Control, req *http.Request) {
534+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
535+
req.Header.Add("k3s-Node-Password", "invalid-password")
536+
withCertificateRequest(req)
537+
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
538+
CommonName: "system:node:" + control.ServerNodeName,
539+
Organization: []string{user.NodesGroup},
540+
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
541+
})
542+
},
543+
match: func(_ *config.Control) types.GomegaMatcher {
544+
return HaveHTTPStatus(http.StatusServiceUnavailable)
545+
},
546+
},
547+
sub{
548+
name: "valid basic client key but bad deferred local password",
549+
prepare: func(control *config.Control, req *http.Request) {
550+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
551+
req.Header.Add("k3s-Node-Password", "invalid-password")
552+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
553+
withCertificateRequest(req)
554+
req.SetBasicAuth("node", control.AgentToken)
555+
},
556+
match: func(_ *config.Control) types.GomegaMatcher {
557+
return HaveHTTPStatus(http.StatusForbidden)
558+
},
559+
},
560+
sub{
561+
name: "valid cert client key but bad deferred local password",
562+
prepare: func(control *config.Control, req *http.Request) {
563+
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
564+
req.Header.Add("k3s-Node-Password", "invalid-password")
565+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
322566
withCertificateRequest(req)
323567
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
324568
CommonName: "system:node:" + control.ServerNodeName,
@@ -428,7 +672,7 @@ func Test_UnitHandlers(t *testing.T) {
428672
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
429673
req.Header.Add("k3s-Node-Password", "password")
430674
req.SetBasicAuth("node", control.AgentToken)
431-
withLocalClient(req)
675+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
432676
},
433677
match: func(_ *config.Control) types.GomegaMatcher {
434678
return And(
@@ -447,7 +691,7 @@ func Test_UnitHandlers(t *testing.T) {
447691
Organization: []string{user.NodesGroup},
448692
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
449693
})
450-
withLocalClient(req)
694+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
451695
},
452696
match: func(_ *config.Control) types.GomegaMatcher {
453697
return And(
@@ -544,7 +788,7 @@ func Test_UnitHandlers(t *testing.T) {
544788
prepare: func(control *config.Control, req *http.Request) {
545789
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
546790
req.Header.Add("k3s-Node-Password", "invalid-password")
547-
withLocalClient(req)
791+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
548792
withCertificateRequest(req)
549793
req.SetBasicAuth("node", control.AgentToken)
550794
},
@@ -560,7 +804,7 @@ func Test_UnitHandlers(t *testing.T) {
560804
prepare: func(control *config.Control, req *http.Request) {
561805
req.Header.Add("k3s-Node-Name", control.ServerNodeName)
562806
req.Header.Add("k3s-Node-Password", "invalid-password")
563-
withLocalClient(req)
807+
withClientAddress(req, control.BindAddressOrLoopback(false, false))
564808
withCertificateRequest(req)
565809
withNewClientCert(req, control.Runtime.ClientCA, control.Runtime.ClientCAKey, control.Runtime.ClientKubeletKey, certutil.Config{
566810
CommonName: "system:node:" + control.ServerNodeName,
@@ -1493,6 +1737,6 @@ func withCertificateRequest(req *http.Request) {
14931737
req.Body = io.NopCloser(bytes.NewReader(csr))
14941738
}
14951739

1496-
func withLocalClient(req *http.Request) {
1497-
req.RemoteAddr = "127.0.0.1:0"
1740+
func withClientAddress(req *http.Request, address string) {
1741+
req.RemoteAddr = net.JoinHostPort(address, "1234")
14981742
}

0 commit comments

Comments
 (0)