From 3c2c64a7f65d4956cfa32000e95353fb6e5c5cc0 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Mon, 13 Oct 2025 20:22:05 -0400 Subject: [PATCH] Add integration test for invalid SAN certificate handling --- test/integration/auth/auth_test.go | 49 +++++++++++- test/integration/auth/testdata/README.md | 1 + .../auth/testdata/sloppy-san-client-key.pem | 5 ++ .../auth/testdata/sloppy-san-client.pem | 65 ++++++++++++++++ .../auth/testdata/sloppy-san-root.pem | 78 +++++++++++++++++++ 5 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 test/integration/auth/testdata/README.md create mode 100644 test/integration/auth/testdata/sloppy-san-client-key.pem create mode 100644 test/integration/auth/testdata/sloppy-san-client.pem create mode 100644 test/integration/auth/testdata/sloppy-san-root.pem diff --git a/test/integration/auth/auth_test.go b/test/integration/auth/auth_test.go index 3641b7e4aef..d80b049d07e 100644 --- a/test/integration/auth/auth_test.go +++ b/test/integration/auth/auth_test.go @@ -41,10 +41,9 @@ import ( "testing" "time" - utiltesting "k8s.io/client-go/util/testing" - "github.com/google/go-cmp/cmp" + authenticationv1 "k8s.io/api/authentication/v1" authenticationv1beta1 "k8s.io/api/authentication/v1beta1" certificatesv1 "k8s.io/api/certificates/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -65,6 +64,7 @@ import ( "k8s.io/client-go/rest" v1 "k8s.io/client-go/tools/clientcmd/api/v1" resttransport "k8s.io/client-go/transport" + utiltesting "k8s.io/client-go/util/testing" "k8s.io/kubernetes/cmd/kube-apiserver/app/options" kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing" "k8s.io/kubernetes/pkg/apis/autoscaling" @@ -1567,3 +1567,48 @@ func newTestWebhookTokenAuthServer() *httptest.Server { server.Start() return server } + +func TestSloppySANCertificates(t *testing.T) { + tCtx := ktesting.Init(t) + _, kubeConfig, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{ + ModifyServerRunOptions: func(opts *options.ServerRunOptions) { + // append to opts.Authentication.ClientCert.ClientCA + fmt.Println(opts.Authentication.ClientCert.ClientCA) + caData, err := os.ReadFile(opts.Authentication.ClientCert.ClientCA) + if err != nil { + t.Fatal(err) + } + sloppyCAData, err := os.ReadFile("testdata/sloppy-san-root.pem") + if err != nil { + t.Fatal(err) + } + err = os.WriteFile(opts.Authentication.ClientCert.ClientCA, []byte(string(caData)+"\n"+string(sloppyCAData)), os.FileMode(0644)) + if err != nil { + t.Fatal(err) + } + }, + }) + defer tearDownFn() + + var err error + kubeConfig = rest.AnonymousClientConfig(kubeConfig) + kubeConfig.CertData, err = os.ReadFile("testdata/sloppy-san-client.pem") + if err != nil { + t.Fatal(err) + } + kubeConfig.KeyData, err = os.ReadFile("testdata/sloppy-san-client-key.pem") + if err != nil { + t.Fatal(err) + } + c, err := clientset.NewForConfig(kubeConfig) + if err != nil { + t.Fatal(err) + } + r, err := c.AuthenticationV1().SelfSubjectReviews().Create(tCtx, &authenticationv1.SelfSubjectReview{}, metav1.CreateOptions{}) + if err != nil { + t.Fatal(err) + } + if r.Status.UserInfo.Username != "sloppy-san-client" { + t.Fatalf("expected sloppy-san-client, got %#v", r.Status.UserInfo) + } +} diff --git a/test/integration/auth/testdata/README.md b/test/integration/auth/testdata/README.md new file mode 100644 index 00000000000..a78ddfbd05a --- /dev/null +++ b/test/integration/auth/testdata/README.md @@ -0,0 +1 @@ +Keys in this directory are generated for testing purposes only. diff --git a/test/integration/auth/testdata/sloppy-san-client-key.pem b/test/integration/auth/testdata/sloppy-san-client-key.pem new file mode 100644 index 00000000000..b6d0a3a7c89 --- /dev/null +++ b/test/integration/auth/testdata/sloppy-san-client-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEILndj5ixo79V24VqIlvSS0J5rwQyklP4+D+rAAjO763loAoGCCqGSM49 +AwEHoUQDQgAEXMW9sg8iyagwwhlJ94p0brB5NqSYIytoj18bs6xPZ3UqEZo5BhXi +2m2Cx8althrzoXbMIGr+ALUWDgKk7BVuSg== +-----END EC PRIVATE KEY----- diff --git a/test/integration/auth/testdata/sloppy-san-client.pem b/test/integration/auth/testdata/sloppy-san-client.pem new file mode 100644 index 00000000000..86275740551 --- /dev/null +++ b/test/integration/auth/testdata/sloppy-san-client.pem @@ -0,0 +1,65 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6084561304482469822 (0x5470b444dfc3d7be) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=sloppy-san-root + Validity + Not Before: Oct 14 00:20:19 2025 GMT + Not After : Sep 20 00:20:19 2125 GMT + Subject: CN=sloppy-san-client + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:5c:c5:bd:b2:0f:22:c9:a8:30:c2:19:49:f7:8a: + 74:6e:b0:79:36:a4:98:23:2b:68:8f:5f:1b:b3:ac: + 4f:67:75:2a:11:9a:39:06:15:e2:da:6d:82:c7:c6: + a5:b6:1a:f3:a1:76:cc:20:6a:fe:00:b5:16:0e:02: + a4:ec:15:6e:4a + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Authority Key Identifier: + 9A:A1:A8:3C:30:1B:EC:1F:B2:1F:10:0E:0C:42:A8:2A:B8:97:9A:8E + X509v3 Subject Alternative Name: + DNS:, DNS:example.com., email:not-an-email + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 96:bc:48:3c:aa:f6:8c:e4:a4:b5:40:6d:fe:20:1b:60:40:12: + e9:f5:58:94:0e:0d:dc:6d:a3:83:ae:3d:05:3b:64:1a:f4:c0: + 23:c9:0d:63:02:ea:c2:f4:e8:bc:88:20:8e:2e:bb:f0:79:32: + cc:0a:59:e2:17:6f:63:aa:5e:b8:0d:54:15:2f:5c:eb:08:7e: + eb:fe:31:62:b1:e5:da:88:dc:be:9e:20:01:f1:73:40:8d:13: + 55:36:aa:2e:58:13:b4:85:aa:63:30:2c:47:a4:95:61:33:f3: + 31:c7:f8:91:d1:18:3c:65:a8:fb:a4:8f:dc:51:8e:9a:d5:dc: + eb:04:b5:b1:f9:82:f5:ff:4a:7b:27:b3:3e:8e:59:30:93:57: + 7d:f2:b4:af:94:39:2b:b9:0d:c1:e5:94:0f:8d:83:03:74:e5: + 6f:38:cd:ee:df:1b:5d:64:48:b9:05:27:5f:09:12:c8:03:96: + 36:0d:d4:19:5b:be:76:ea:7d:f3:20:08:2a:b4:c6:92:63:41: + 44:d8:2c:b1:b8:71:7c:a9:1f:26:d7:99:04:d4:9b:a6:4b:a4: + fa:ef:b2:a9:f5:e7:af:53:4b:de:00:45:5c:5b:f0:2a:1a:bc: + 40:2f:97:ca:fb:9c:53:a8:16:46:89:a0:f9:43:45:47:de:3e: + 09:8e:a6:22 +-----BEGIN CERTIFICATE----- +MIICbjCCAVagAwIBAgIIVHC0RN/D174wDQYJKoZIhvcNAQELBQAwGjEYMBYGA1UE +AxMPc2xvcHB5LXNhbi1yb290MCAXDTI1MTAxNDAwMjAxOVoYDzIxMjUwOTIwMDAy +MDE5WjAcMRowGAYDVQQDExFzbG9wcHktc2FuLWNsaWVudDBZMBMGByqGSM49AgEG +CCqGSM49AwEHA0IABFzFvbIPIsmoMMIZSfeKdG6weTakmCMraI9fG7OsT2d1KhGa +OQYV4tptgsfGpbYa86F2zCBq/gC1Fg4CpOwVbkqjfzB9MA4GA1UdDwEB/wQEAwIF +oDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaA +FJqhqDwwG+wfsh8QDgxCqCq4l5qOMCcGA1UdEQQgMB6CAIIMZXhhbXBsZS5jb20u +gQxub3QtYW4tZW1haWwwDQYJKoZIhvcNAQELBQADggEBAJa8SDyq9ozkpLVAbf4g +G2BAEun1WJQODdxto4OuPQU7ZBr0wCPJDWMC6sL06LyIII4uu/B5MswKWeIXb2Oq +XrgNVBUvXOsIfuv+MWKx5dqI3L6eIAHxc0CNE1U2qi5YE7SFqmMwLEeklWEz8zHH ++JHRGDxlqPukj9xRjprV3OsEtbH5gvX/Snsnsz6OWTCTV33ytK+UOSu5DcHllA+N +gwN05W84ze7fG11kSLkFJ18JEsgDljYN1BlbvnbqffMgCCq0xpJjQUTYLLG4cXyp +HybXmQTUm6ZLpPrvsqn1569TS94ARVxb8CoavEAvl8r7nFOoFkaJoPlDRUfePgmO +piI= +-----END CERTIFICATE----- diff --git a/test/integration/auth/testdata/sloppy-san-root.pem b/test/integration/auth/testdata/sloppy-san-root.pem new file mode 100644 index 00000000000..54386e1487a --- /dev/null +++ b/test/integration/auth/testdata/sloppy-san-root.pem @@ -0,0 +1,78 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2937139693522916239 (0x28c2d0fd5822138f) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=sloppy-san-root + Validity + Not Before: Oct 14 00:20:19 2025 GMT + Not After : Sep 20 00:20:19 2125 GMT + Subject: CN=sloppy-san-root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:9e:00:38:70:8d:a7:9c:fd:89:e4:33:f9:7e:e3: + 99:1f:19:69:a9:a3:7c:ca:8e:f4:52:ef:c8:a8:3d: + fc:6c:08:95:8b:14:f9:d9:a2:2b:25:7c:15:8e:aa: + a9:ec:19:fe:62:9f:18:33:12:72:b0:2f:37:b6:de: + d0:24:fe:19:ef:78:93:b7:7d:7a:44:46:4c:14:bd: + d7:23:a7:fc:44:43:6d:f9:29:f8:79:2a:61:fc:1f: + d4:79:49:19:53:5b:6d:5a:66:cd:59:a9:2b:38:c7: + c5:38:96:b8:12:36:c5:60:d8:dc:ea:86:df:9a:cd: + 50:95:be:5f:1a:38:67:dc:bf:67:24:5e:ed:06:79: + 32:b5:19:bd:11:ec:ff:61:b7:e2:32:05:8d:b6:c9: + 12:ba:92:7c:2a:9e:26:71:b2:d0:85:95:9d:68:79: + d0:3e:e5:8b:ac:e8:e4:22:6d:79:a3:77:58:01:72: + f9:67:7d:d8:5e:7f:5c:56:45:31:36:8e:f5:be:48: + c4:66:f1:14:ed:38:43:ae:5f:cc:20:66:7b:48:df: + 78:d5:f4:4f:67:2a:d4:ee:7b:36:d2:c1:5f:d1:3b: + e4:bb:31:0f:94:0c:19:f7:17:99:99:04:eb:b7:b4: + 34:6c:f9:0b:8c:61:e9:a5:5b:50:62:f7:24:51:25: + 3d:43 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment, Certificate Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 9A:A1:A8:3C:30:1B:EC:1F:B2:1F:10:0E:0C:42:A8:2A:B8:97:9A:8E + X509v3 Subject Alternative Name: + DNS:, DNS:example.com. + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 4d:4f:ef:47:a0:41:96:9a:e0:98:e3:e6:5e:4f:70:6a:b1:16: + 3c:10:8b:f9:2b:12:57:58:28:88:a4:1a:e8:4c:a4:be:a0:c1: + ad:07:95:dd:d9:bc:db:a9:db:31:5f:42:30:60:19:e2:28:fb: + 72:78:91:a7:83:e7:bd:0f:52:b8:2b:fe:d0:0e:03:64:0e:08: + 8b:62:b9:bc:30:1d:76:86:42:a6:fe:f0:55:0d:3c:16:97:32: + 3a:9f:1a:0e:5b:01:68:9d:37:76:d5:ed:a8:e5:e6:1b:7d:ff: + b2:e3:c0:a0:8f:cb:2f:98:e5:6b:e5:b6:ef:fe:a4:c4:f8:33: + 6f:e1:90:89:16:69:58:c8:ca:95:99:d1:84:8e:0e:83:ed:a7: + ae:ac:4e:32:7e:72:95:fa:ce:3f:62:ae:06:57:40:b2:bf:79: + 8f:b2:f6:69:07:ee:d8:7c:70:b0:52:8d:f6:08:f9:de:a8:6a: + 90:77:6a:65:52:67:82:98:32:68:66:4d:8e:6b:a8:dd:b5:3c: + a7:fe:b4:98:d0:69:70:1b:60:60:1b:10:30:88:5c:9b:f0:6b: + 9e:52:47:2f:83:7d:77:e3:e2:af:a5:fb:de:65:91:51:0f:27: + b2:34:25:8f:97:55:ee:11:d0:d1:4e:8f:7a:cf:9f:7d:8e:e6: + 27:24:61:cf +-----BEGIN CERTIFICATE----- +MIIDFTCCAf2gAwIBAgIIKMLQ/VgiE48wDQYJKoZIhvcNAQELBQAwGjEYMBYGA1UE +AxMPc2xvcHB5LXNhbi1yb290MCAXDTI1MTAxNDAwMjAxOVoYDzIxMjUwOTIwMDAy +MDE5WjAaMRgwFgYDVQQDEw9zbG9wcHktc2FuLXJvb3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCeADhwjaec/YnkM/l+45kfGWmpo3zKjvRS78ioPfxs +CJWLFPnZoislfBWOqqnsGf5inxgzEnKwLze23tAk/hnveJO3fXpERkwUvdcjp/xE +Q235Kfh5KmH8H9R5SRlTW21aZs1ZqSs4x8U4lrgSNsVg2Nzqht+azVCVvl8aOGfc +v2ckXu0GeTK1Gb0R7P9ht+IyBY22yRK6knwqniZxstCFlZ1oedA+5Yus6OQibXmj +d1gBcvlnfdhef1xWRTE2jvW+SMRm8RTtOEOuX8wgZntI33jV9E9nKtTuezbSwV/R +O+S7MQ+UDBn3F5mZBOu3tDRs+QuMYemlW1Bi9yRRJT1DAgMBAAGjXTBbMA4GA1Ud +DwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSaoag8MBvsH7If +EA4MQqgquJeajjAZBgNVHREEEjAQggCCDGV4YW1wbGUuY29tLjANBgkqhkiG9w0B +AQsFAAOCAQEATU/vR6BBlprgmOPmXk9warEWPBCL+SsSV1goiKQa6EykvqDBrQeV +3dm826nbMV9CMGAZ4ij7cniRp4PnvQ9SuCv+0A4DZA4Ii2K5vDAddoZCpv7wVQ08 +FpcyOp8aDlsBaJ03dtXtqOXmG33/suPAoI/LL5jla+W27/6kxPgzb+GQiRZpWMjK +lZnRhI4Og+2nrqxOMn5ylfrOP2KuBldAsr95j7L2aQfu2HxwsFKN9gj53qhqkHdq +ZVJngpgyaGZNjmuo3bU8p/60mNBpcBtgYBsQMIhcm/BrnlJHL4N9d+Pir6X73mWR +UQ8nsjQlj5dV7hHQ0U6Pes+ffY7mJyRhzw== +-----END CERTIFICATE-----