diff --git a/cmd/requestreply/main.go b/cmd/requestreply/main.go index fa491d0927e..5d00e310dac 100644 --- a/cmd/requestreply/main.go +++ b/cmd/requestreply/main.go @@ -18,12 +18,14 @@ package main import ( "context" + "crypto/tls" "log" "github.com/kelseyhightower/envconfig" "go.uber.org/zap" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "knative.dev/eventing/pkg/eventingtls" "knative.dev/eventing/pkg/kncloudevents" @@ -34,6 +36,7 @@ import ( configmap "knative.dev/pkg/configmap/informer" "knative.dev/pkg/controller" "knative.dev/pkg/injection" + secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret" "knative.dev/pkg/logging" "knative.dev/pkg/signals" "knative.dev/pkg/system" @@ -109,9 +112,15 @@ func main() { env.PodIdx, ) + tlsConfig, err := getServerTLSConfig(ctx) + if err != nil { + logger.Fatal("failed to get TLS server config", zap.Error(err)) + } + sm, err := eventingtls.NewServerManager(ctx, kncloudevents.NewHTTPEventReceiver(env.HttpPort), - kncloudevents.NewHTTPEventReceiver(env.HttpsPort), // TODO: add tls config when we have it + kncloudevents.NewHTTPEventReceiver(env.HttpsPort, + kncloudevents.WithTLSConfig(tlsConfig)), handler, configMapWatcher, ) @@ -135,6 +144,17 @@ func flush(sl *zap.SugaredLogger) { _ = sl.Sync() } +func getServerTLSConfig(ctx context.Context) (*tls.Config, error) { + secret := types.NamespacedName{ + Namespace: system.Namespace(), + Name: eventingtls.RequestReplyServerTLSSecretName, + } + + serverTLSConfig := eventingtls.NewDefaultServerConfig() + serverTLSConfig.GetCertificate = eventingtls.GetCertificateFromSecret(ctx, secretinformer.Get(ctx), kubeclient.Get(ctx), secret) + return eventingtls.GetTLSServerConfig(serverTLSConfig) +} + func getLoggingConfig(ctx context.Context, namespace, loggingConfigMapName string) (*logging.Config, error) { loggingConfigMap, err := kubeclient.Get(ctx).CoreV1().ConfigMaps(namespace).Get(ctx, loggingConfigMapName, metav1.GetOptions{}) if apierrs.IsNotFound(err) { diff --git a/cmd/requestreply/main_test.go b/cmd/requestreply/main_test.go new file mode 100644 index 00000000000..45ef331fb0f --- /dev/null +++ b/cmd/requestreply/main_test.go @@ -0,0 +1,51 @@ +/* +Copyright 2026 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "testing" + + reconcilertesting "knative.dev/pkg/reconciler/testing" + + // Fake injection informers and clients + _ "knative.dev/pkg/client/injection/kube/client/fake" + _ "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret/fake" +) + +func TestGetServerTLSConfig(t *testing.T) { + t.Setenv("SYSTEM_NAMESPACE", "knative-eventing") + + ctx, _ := reconcilertesting.SetupFakeContext(t) + + tlsConfig, err := getServerTLSConfig(ctx) + if err != nil { + t.Fatal("unexpected error:", err) + } + + if tlsConfig == nil { + t.Fatal("expected non-nil TLS config") + } + + if tlsConfig.MinVersion != tls.VersionTLS12 { + t.Fatalf("want MinVersion TLS 1.2 (%d), got %d", tls.VersionTLS12, tlsConfig.MinVersion) + } + + if tlsConfig.GetCertificate == nil { + t.Fatal("expected GetCertificate to be set") + } +} diff --git a/go.mod b/go.mod index a3634bf2b03..6508c6dd04f 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 knative.dev/hack v0.0.0-20260120115810-bf6758cba446 knative.dev/hack/schema v0.0.0-20260120115810-bf6758cba446 - knative.dev/pkg v0.0.0-20260120122510-4a022ed9999a + knative.dev/pkg v0.0.0-20260319144603-18c5d580ae64 knative.dev/reconciler-test v0.0.0-20260120140419-4301404c03ce sigs.k8s.io/randfill v1.0.0 sigs.k8s.io/yaml v1.6.0 diff --git a/go.sum b/go.sum index 831c847d14a..841dffa55e8 100644 --- a/go.sum +++ b/go.sum @@ -1096,8 +1096,8 @@ knative.dev/hack v0.0.0-20260120115810-bf6758cba446 h1:Y8raYHIuAL9/gUKGYD9/dD+Eq knative.dev/hack v0.0.0-20260120115810-bf6758cba446/go.mod h1:L5RzHgbvam0u8QFHfzCX6MKxu/a/gIGEdaRBqNiVbl0= knative.dev/hack/schema v0.0.0-20260120115810-bf6758cba446 h1:V7TW1ZOZObhVcDuN04tYvCfCjvvikv1qZR/6lcp6g4Q= knative.dev/hack/schema v0.0.0-20260120115810-bf6758cba446/go.mod h1:KkibP1IazICP5ClxwN5D26LDSygsqbYnVGuGFTsHNOQ= -knative.dev/pkg v0.0.0-20260120122510-4a022ed9999a h1:9f29OTA7w/iVIX6PS6yveVVzNbcUS74eQfchVe8o2/4= -knative.dev/pkg v0.0.0-20260120122510-4a022ed9999a/go.mod h1:Tz3GoxcNC5vH3Zo//cW3mnHL474u+Y1wbsUIZ11p8No= +knative.dev/pkg v0.0.0-20260319144603-18c5d580ae64 h1:TiwrcgUKNePfdAbaJT9W4P57lsKjiZnjJ0wVC6XrL0U= +knative.dev/pkg v0.0.0-20260319144603-18c5d580ae64/go.mod h1:Tz3GoxcNC5vH3Zo//cW3mnHL474u+Y1wbsUIZ11p8No= knative.dev/reconciler-test v0.0.0-20260120140419-4301404c03ce h1:pIQCFDsDTRkzrJZDTs2laryYOI6VpcnGF5zezL0NXOw= knative.dev/reconciler-test v0.0.0-20260120140419-4301404c03ce/go.mod h1:FUaadFiniAaqqBp/D2g2cO/FUABVR8W4yZd2azDzp7I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/pkg/eventingtls/eventingtls.go b/pkg/eventingtls/eventingtls.go index 6e5cd4de16c..93ed18152c4 100644 --- a/pkg/eventingtls/eventingtls.go +++ b/pkg/eventingtls/eventingtls.go @@ -39,6 +39,7 @@ import ( duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/controller" "knative.dev/pkg/logging" + pkgtls "knative.dev/pkg/network/tls" ) const ( @@ -58,6 +59,8 @@ const ( BrokerFilterServerTLSSecretName = "mt-broker-filter-server-tls" //nolint:gosec // This is not a hardcoded credential // BrokerIngressServerTLSSecretName is the name of the tls secret for the broker ingress server BrokerIngressServerTLSSecretName = "mt-broker-ingress-server-tls" //nolint:gosec // This is not a hardcoded credential + // RequestReplyServerTLSSecretName is the name of the tls secret for the request reply server + RequestReplyServerTLSSecretName = "request-reply-server-tls" //nolint:gosec // This is not a hardcoded credential ) type ClientConfig struct { @@ -170,10 +173,13 @@ func GetTLSClientConfig(config ClientConfig) (*tls.Config, error) { return nil, err } - return &tls.Config{ - RootCAs: pool, - MinVersion: DefaultMinTLSVersion, - }, nil + cfg, err := defaultTLSConfigFromEnv() + if err != nil { + return nil, err + } + + cfg.RootCAs = pool + return cfg, nil } func NewDefaultServerConfig() ServerConfig { @@ -181,10 +187,31 @@ func NewDefaultServerConfig() ServerConfig { } func GetTLSServerConfig(config ServerConfig) (*tls.Config, error) { - return &tls.Config{ - MinVersion: DefaultMinTLSVersion, - GetCertificate: config.GetCertificate, - }, nil + cfg, err := defaultTLSConfigFromEnv() + if err != nil { + return nil, err + } + + cfg.GetCertificate = config.GetCertificate + return cfg, nil +} + +// defaultTLSConfigFromEnv loads TLS configuration from environment variables +// using the shared knative/pkg/tls utility. DefaultConfigFromEnv defaults to +// TLS 1.3, but eventing historically defaults to TLS 1.2, so we fall back to +// 1.2 unless TLS_MIN_VERSION is explicitly set. +// TODO: switch to TLS 1.3 to align with the rest of the system. +func defaultTLSConfigFromEnv() (*tls.Config, error) { + cfg, err := pkgtls.DefaultConfigFromEnv("") + if err != nil { + return nil, fmt.Errorf("failed to load TLS config from env: %w", err) + } + + if os.Getenv(pkgtls.MinVersionEnvKey) == "" { + cfg.MinVersion = DefaultMinTLSVersion + } + + return cfg, nil } // IsHttpsSink returns true if the sink has scheme equal to https. diff --git a/pkg/eventingtls/eventingtls_test.go b/pkg/eventingtls/eventingtls_test.go index dc6d5cc88c6..690277f3d96 100644 --- a/pkg/eventingtls/eventingtls_test.go +++ b/pkg/eventingtls/eventingtls_test.go @@ -17,11 +17,19 @@ limitations under the License. package eventingtls import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" "crypto/tls" "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" "testing" + "time" "k8s.io/utils/pointer" + pkgtls "knative.dev/pkg/network/tls" ) func TestGetClientConfig(t *testing.T) { @@ -32,27 +40,7 @@ func TestGetClientConfig(t *testing.T) { t.Fatal(err) } sysCertPool = sysCertPool.Clone() - pemCaCert := ` ------BEGIN CERTIFICATE----- -MIIDPzCCAiegAwIBAgIUOF3U5UMwffSmdo24IVU1k+qix3YwDQYJKoZIhvcNAQEL -BQAwLzELMAkGA1UEBhMCVVMxIDAeBgNVBAMMF0tuYXRpdmUtRXhhbXBsZS1Sb290 -LUNBMB4XDTIzMDYwNjE0MDY1NFoXDTI2MDMyNjE0MDY1NFowLzELMAkGA1UEBhMC -VVMxIDAeBgNVBAMMF0tuYXRpdmUtRXhhbXBsZS1Sb290LUNBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsJEA/+FW8e/ChmpseeH+UMtpP3PIq4VO26yh -fg3RSWKRbEnpkusWX6tM5NIZ9HqZOhB9dvb0OAC+YBM5ce8eA1/5tIUcxOzvMo5S -Oe+5cOgzZPLNesPBD+vteFXeD/9Hg75KfxctgyYfKqAE4Q8afaxs29/9K4wZkdE7 -Fs4ED8r6hxf+7wgVSurnHiQnupHOb3BCQEGFm4w5/YJMhJFM29+LtIa5iZvQdlIC -zrIiLSckaRCiuJH2U5HCxk6WpodyoD5ffqzX7/+xismUwsX9opnMfdz7vT4ZYvKc -5O0u6/mx9fvhCL7hVwz8/FKvd1+Z4WnGoL/Iz3g+T/qdMbA+1wIDAQABo1MwUTAd -BgNVHQ4EFgQU51Q84l/eECxUhLRPhlcoLougg0owHwYDVR0jBBgwFoAU51Q84l/e -ECxUhLRPhlcoLougg0owDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC -AQEAZVXtix62c6VVAEZHsSTPwlMwGjZ67UCd6NxeY5IgXdT/vmorlrsoZa0FYYkU -TdWOHt7Q1C48W+tA2yMTPGs240Zradam2CXAxEvL7/aC6GEFs7vhkq6riwJ/erR3 -ZAZjcWi5Qk03q7eS61JJvaV9+fKg+F2BB2EqaCPo7HMMSXO81aeHEMl/AQsNPnur -2VG1tchMQvfakRf53H1hWu5h4APuZo1MTkPmBOTLZG7eAJTtfVWz1aPwB1rUMCyP -wSdZWoEx7ye2kUHEyRKdRGbHyJtY9YYvaROznzxqVpIqHxnRQnE/If7kcN4t/7vi -28zWIDKzJ8je40SPcLSfplRvBQ== ------END CERTIFICATE-----` + pemCaCert := generateTestCACertPEM() tt := []struct { name string @@ -122,6 +110,30 @@ wSdZWoEx7ye2kUHEyRKdRGbHyJtY9YYvaROznzxqVpIqHxnRQnE/If7kcN4t/7vi } } +func generateTestCACertPEM() string { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic("failed to generate CA key: " + err.Error()) + } + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Country: []string{"US"}, + CommonName: "Knative-Example-Root-CA", + }, + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(10 * 365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, + BasicConstraintsValid: true, + IsCA: true, + } + der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key) + if err != nil { + panic("failed to create CA certificate: " + err.Error()) + } + return string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})) +} + func WithCerts(pool *x509.CertPool, caCerts string) *x509.CertPool { pool = pool.Clone() if ok := pool.AppendCertsFromPEM([]byte(caCerts)); !ok { @@ -129,3 +141,184 @@ func WithCerts(pool *x509.CertPool, caCerts string) *x509.CertPool { } return pool } + +func TestGetTLSClientConfigEnv(t *testing.T) { + t.Run("defaults to TLS 1.2 when env not set", func(t *testing.T) { + t.Setenv(pkgtls.MinVersionEnvKey, "") + + cfg, err := GetTLSClientConfig(NewDefaultClientConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if cfg.MinVersion != tls.VersionTLS12 { + t.Fatalf("want MinVersion TLS 1.2 (%d), got %d", tls.VersionTLS12, cfg.MinVersion) + } + }) + + t.Run("uses TLS 1.3 when explicitly set via env", func(t *testing.T) { + t.Setenv(pkgtls.MinVersionEnvKey, "1.3") + + cfg, err := GetTLSClientConfig(NewDefaultClientConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if cfg.MinVersion != tls.VersionTLS13 { + t.Fatalf("want MinVersion TLS 1.3 (%d), got %d", tls.VersionTLS13, cfg.MinVersion) + } + }) + + t.Run("reads MaxVersion from env", func(t *testing.T) { + t.Setenv(pkgtls.MaxVersionEnvKey, "1.3") + + cfg, err := GetTLSClientConfig(NewDefaultClientConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if cfg.MaxVersion != tls.VersionTLS13 { + t.Fatalf("want MaxVersion TLS 1.3 (%d), got %d", tls.VersionTLS13, cfg.MaxVersion) + } + }) + + t.Run("reads CipherSuites from env", func(t *testing.T) { + t.Setenv(pkgtls.CipherSuitesEnvKey, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256") + + cfg, err := GetTLSClientConfig(NewDefaultClientConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if len(cfg.CipherSuites) != 1 || cfg.CipherSuites[0] != tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 { + t.Fatalf("want CipherSuites [%d], got %v", tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cfg.CipherSuites) + } + }) + + t.Run("reads CurvePreferences from env", func(t *testing.T) { + t.Setenv(pkgtls.CurvePreferencesEnvKey, "X25519,CurveP256") + + cfg, err := GetTLSClientConfig(NewDefaultClientConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if len(cfg.CurvePreferences) != 2 { + t.Fatalf("want 2 CurvePreferences, got %d", len(cfg.CurvePreferences)) + } + if cfg.CurvePreferences[0] != tls.X25519 || cfg.CurvePreferences[1] != tls.CurveP256 { + t.Fatalf("want CurvePreferences [X25519, CurveP256], got %v", cfg.CurvePreferences) + } + }) + + t.Run("returns error on invalid env value", func(t *testing.T) { + t.Setenv(pkgtls.MinVersionEnvKey, "invalid") + + _, err := GetTLSClientConfig(NewDefaultClientConfig()) + if err == nil { + t.Fatal("expected error for invalid TLS_MIN_VERSION, got nil") + } + }) +} + +func TestGetTLSServerConfig(t *testing.T) { + t.Run("defaults to TLS 1.2 when env not set", func(t *testing.T) { + t.Setenv(pkgtls.MinVersionEnvKey, "") + + cfg, err := GetTLSServerConfig(NewDefaultServerConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if cfg.MinVersion != tls.VersionTLS12 { + t.Fatalf("want MinVersion TLS 1.2 (%d), got %d", tls.VersionTLS12, cfg.MinVersion) + } + }) + + t.Run("uses TLS 1.3 when explicitly set via env", func(t *testing.T) { + t.Setenv(pkgtls.MinVersionEnvKey, "1.3") + + cfg, err := GetTLSServerConfig(NewDefaultServerConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if cfg.MinVersion != tls.VersionTLS13 { + t.Fatalf("want MinVersion TLS 1.3 (%d), got %d", tls.VersionTLS13, cfg.MinVersion) + } + }) + + t.Run("uses TLS 1.2 when explicitly set via env", func(t *testing.T) { + t.Setenv(pkgtls.MinVersionEnvKey, "1.2") + + cfg, err := GetTLSServerConfig(NewDefaultServerConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if cfg.MinVersion != tls.VersionTLS12 { + t.Fatalf("want MinVersion TLS 1.2 (%d), got %d", tls.VersionTLS12, cfg.MinVersion) + } + }) + + t.Run("reads MaxVersion from env", func(t *testing.T) { + t.Setenv(pkgtls.MaxVersionEnvKey, "1.3") + + cfg, err := GetTLSServerConfig(NewDefaultServerConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if cfg.MaxVersion != tls.VersionTLS13 { + t.Fatalf("want MaxVersion TLS 1.3 (%d), got %d", tls.VersionTLS13, cfg.MaxVersion) + } + }) + + t.Run("reads CipherSuites from env", func(t *testing.T) { + t.Setenv(pkgtls.CipherSuitesEnvKey, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256") + + cfg, err := GetTLSServerConfig(NewDefaultServerConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if len(cfg.CipherSuites) != 1 || cfg.CipherSuites[0] != tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 { + t.Fatalf("want CipherSuites [%d], got %v", tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cfg.CipherSuites) + } + }) + + t.Run("reads CurvePreferences from env", func(t *testing.T) { + t.Setenv(pkgtls.CurvePreferencesEnvKey, "X25519,CurveP256") + + cfg, err := GetTLSServerConfig(NewDefaultServerConfig()) + if err != nil { + t.Fatal("unexpected error:", err) + } + if len(cfg.CurvePreferences) != 2 { + t.Fatalf("want 2 CurvePreferences, got %d", len(cfg.CurvePreferences)) + } + if cfg.CurvePreferences[0] != tls.X25519 || cfg.CurvePreferences[1] != tls.CurveP256 { + t.Fatalf("want CurvePreferences [X25519, CurveP256], got %v", cfg.CurvePreferences) + } + }) + + t.Run("returns error on invalid env value", func(t *testing.T) { + t.Setenv(pkgtls.MinVersionEnvKey, "invalid") + + _, err := GetTLSServerConfig(NewDefaultServerConfig()) + if err == nil { + t.Fatal("expected error for invalid TLS_MIN_VERSION, got nil") + } + }) + + t.Run("preserves GetCertificate callback", func(t *testing.T) { + called := false + sc := ServerConfig{ + GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + called = true + return nil, nil + }, + } + cfg, err := GetTLSServerConfig(sc) + if err != nil { + t.Fatal("unexpected error:", err) + } + if cfg.GetCertificate == nil { + t.Fatal("GetCertificate should not be nil") + } + _, _ = cfg.GetCertificate(nil) + if !called { + t.Fatal("GetCertificate callback was not invoked") + } + }) +} diff --git a/pkg/eventingtls/eventingtlstesting/eventingtlstesting.go b/pkg/eventingtls/eventingtlstesting/eventingtlstesting.go index c4fe187a553..dc7355ce8e7 100644 --- a/pkg/eventingtls/eventingtlstesting/eventingtlstesting.go +++ b/pkg/eventingtls/eventingtlstesting/eventingtlstesting.go @@ -18,8 +18,17 @@ package eventingtlstesting import ( "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "net" "net/http" "testing" + "time" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" @@ -87,94 +96,68 @@ func StartServer(ctx context.Context, t *testing.T, port int, handler http.Handl } func loadCerts() ([]byte, []byte, []byte) { - /* - Provisioned using: - openssl req -x509 -nodes -new -sha256 -days 1024 -newkey rsa:2048 -keyout RootCA.key -out RootCA.pem -subj "/C=US/CN=Knative-Example-Root-CA" - openssl x509 -outform pem -in RootCA.pem -out RootCA.crt - openssl req -new -nodes -newkey rsa:2048 -keyout localhost.key -out localhost.csr -subj "/C=US/ST=YourState/L=YourCity/O=Example-Certificates/CN=localhost.local" - openssl x509 -req -sha256 -days 1024 -in localhost.csr -CA RootCA.pem -CAkey RootCA.key -CAcreateserial -extfile domains.ext -out localhost.crt - Copy: - - RootCA.crt for ca - - localhost.key for key - - localhost.crt for crt - domains.ext file: - authorityKeyIdentifier=keyid,issuer - basicConstraints=CA:FALSE - keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment - subjectAltName = @alt_names - [alt_names] - DNS.1 = localhost - IP.1 = 127.0.0.1 - */ - return []byte(` ------BEGIN CERTIFICATE----- -MIIDPzCCAiegAwIBAgIUOF3U5UMwffSmdo24IVU1k+qix3YwDQYJKoZIhvcNAQEL -BQAwLzELMAkGA1UEBhMCVVMxIDAeBgNVBAMMF0tuYXRpdmUtRXhhbXBsZS1Sb290 -LUNBMB4XDTIzMDYwNjE0MDY1NFoXDTI2MDMyNjE0MDY1NFowLzELMAkGA1UEBhMC -VVMxIDAeBgNVBAMMF0tuYXRpdmUtRXhhbXBsZS1Sb290LUNBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsJEA/+FW8e/ChmpseeH+UMtpP3PIq4VO26yh -fg3RSWKRbEnpkusWX6tM5NIZ9HqZOhB9dvb0OAC+YBM5ce8eA1/5tIUcxOzvMo5S -Oe+5cOgzZPLNesPBD+vteFXeD/9Hg75KfxctgyYfKqAE4Q8afaxs29/9K4wZkdE7 -Fs4ED8r6hxf+7wgVSurnHiQnupHOb3BCQEGFm4w5/YJMhJFM29+LtIa5iZvQdlIC -zrIiLSckaRCiuJH2U5HCxk6WpodyoD5ffqzX7/+xismUwsX9opnMfdz7vT4ZYvKc -5O0u6/mx9fvhCL7hVwz8/FKvd1+Z4WnGoL/Iz3g+T/qdMbA+1wIDAQABo1MwUTAd -BgNVHQ4EFgQU51Q84l/eECxUhLRPhlcoLougg0owHwYDVR0jBBgwFoAU51Q84l/e -ECxUhLRPhlcoLougg0owDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC -AQEAZVXtix62c6VVAEZHsSTPwlMwGjZ67UCd6NxeY5IgXdT/vmorlrsoZa0FYYkU -TdWOHt7Q1C48W+tA2yMTPGs240Zradam2CXAxEvL7/aC6GEFs7vhkq6riwJ/erR3 -ZAZjcWi5Qk03q7eS61JJvaV9+fKg+F2BB2EqaCPo7HMMSXO81aeHEMl/AQsNPnur -2VG1tchMQvfakRf53H1hWu5h4APuZo1MTkPmBOTLZG7eAJTtfVWz1aPwB1rUMCyP -wSdZWoEx7ye2kUHEyRKdRGbHyJtY9YYvaROznzxqVpIqHxnRQnE/If7kcN4t/7vi -28zWIDKzJ8je40SPcLSfplRvBQ== ------END CERTIFICATE-----`), []byte(` ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCodsq2l7lP1LMw -hh9j4FQvULIfvcwiz3WyBkeLvQPk044ZRX50bwm2llTKwEvWyqnmctjcS5RiKItw -9kg6eXA3Z9CBuPyJkrvH/4OO2wOBgyBD8k3LqNtaqN0Qq2Y3JbQ/PBf5btNMmYFB -gostqCBsiDIF1KqkpCHpvLBLPte9bLv4ZAxNecC6p/fXUbXTWJ4SFNhdZrw62Rs4 -boq8qTs0PceDJiLdvqwngGNneCdehFXR3citMCA8SxyD8E2qIIOLuOEf54s9zR7C -d+D0h+XQmHICAcz3Yo4a27dNFUc2LHcp9a2+ASHTnKsR6Xhndo/IcT7/qbYq7/kJ -lfN66ObzAgMBAAECggEADBYpyRvtobqi+JJG4kWQBK0HepuFb+Hukc09iNsQ0nQT -N+Dyh6wHyF/UyY8uYcS8l9oZkQSjKr+58WraF8fqsy7xmL0K8VvjuR+t8qvn/nzH -7dgOmNQOmNyQr8d8V+yOmBLZrX20D0TcLzUMg0QSv3auEBkH/TQBcuGkzGE/3Uk4 -DT/L//DREjVw+DAaFd53UWWhSnLOkQAsY+zR+HktQH0CEtwMjbkBWMgCkgX7/v9w -gBQLwR7uw5w0Kn8ArgqXj5b5naqHhNzMPj65kMHFjYejSDsjPntToz5YrDRsd4L3 -EYAcKcG4fYjJ8vYbRjG7SYCxX7HsvJUhqZT4ds/DsQKBgQDTrSN8m60ZPwmvAG+6 -Tpy3Hpf+klO/AE/FQ6WQ8K77McBoRA4awFcjqasqxkTHCl8FXXdWoEe+OIJ+MXzu -5zX5J1dAOl++sgdOvQFW4y4H+FOHD5q5SHFzdI8d65HJy6SI6BVJz4lR51bSU5CQ -qkdh0Sbh1hAACIsmZTApaXY03wKBgQDLvUShkRaJC/pzN7yCb0Cu4VxBV90IkE0n -INHNML8/KCbGJ5EmLk5uJt1sWb0e8PpUgoavnljfUUKyNfd/ltr9slE6uRhy9net -qg1A0CmArFJgOncA3bu92CvvzzcDPsnHCBnLKpTfUSThk8Sxftg0bqKEV3sy5Py1 -9x6Sp7QcbQKBgQCKRjDHRn6F3mr5+aQCpTW0XXTWpEm2nIJ/jxgJnWAA0VgqBELe -cMS7lCsvLwNgrkKyI4NAgEU9WnbL7pH5EeptDqjtWPSQgoVJhyfn1VGNfUc7FBNz -c4JA9GRFHExI8RFTKaA2bi765M8PZ+0ow0ML/++RWR9slign9bPHaZABKwKBgHz9 -unMcXaTqMlYpJX8n3ZjsLPrxemrcjFiq68tkUo/ehBsg/w1bb0ZolYL5curej9T0 -1sg67u7iHXbTYOlnlSX7FZZfI76zsixanRLcIfoMveTHOWbQoXMQgbP3fhqBlKyE -Lb7UesyeLXAuhYcW+HECRrXGLZDFprvDxX/XXsnpAoGBAJdaCxiy7ZXDrJHJDzGp -Ntxv2SbGghJwlmWYh7BP/+Cb6vUWG4MTzUBIzKfk4Z32xjFwDxKi3SW+34uZ6/fD -Ptt315Oq0odZvrdGtJoGud/p9nCHUiLGHwRH9NrDtTcO9zR55oYc0pJk0EfrXpsb -r5IiDpxJPL1q0JmKeA+Fr4wy ------END PRIVATE KEY-----`), []byte(` ------BEGIN CERTIFICATE----- -MIIDoDCCAoigAwIBAgIUSVuHbk6clsj/7Fe3Uc8mFwXU6kMwDQYJKoZIhvcNAQEL -BQAwLzELMAkGA1UEBhMCVVMxIDAeBgNVBAMMF0tuYXRpdmUtRXhhbXBsZS1Sb290 -LUNBMB4XDTIzMDYwNjE0MTEwNFoXDTI2MDMyNjE0MTEwNFowbTELMAkGA1UEBhMC -VVMxEjAQBgNVBAgMCVlvdXJTdGF0ZTERMA8GA1UEBwwIWW91ckNpdHkxHTAbBgNV -BAoMFEV4YW1wbGUtQ2VydGlmaWNhdGVzMRgwFgYDVQQDDA9sb2NhbGhvc3QubG9j -YWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCodsq2l7lP1LMwhh9j -4FQvULIfvcwiz3WyBkeLvQPk044ZRX50bwm2llTKwEvWyqnmctjcS5RiKItw9kg6 -eXA3Z9CBuPyJkrvH/4OO2wOBgyBD8k3LqNtaqN0Qq2Y3JbQ/PBf5btNMmYFBgost -qCBsiDIF1KqkpCHpvLBLPte9bLv4ZAxNecC6p/fXUbXTWJ4SFNhdZrw62Rs4boq8 -qTs0PceDJiLdvqwngGNneCdehFXR3citMCA8SxyD8E2qIIOLuOEf54s9zR7Cd+D0 -h+XQmHICAcz3Yo4a27dNFUc2LHcp9a2+ASHTnKsR6Xhndo/IcT7/qbYq7/kJlfN6 -6ObzAgMBAAGjdjB0MB8GA1UdIwQYMBaAFOdUPOJf3hAsVIS0T4ZXKC6LoINKMAkG -A1UdEwQCMAAwCwYDVR0PBAQDAgTwMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAA -ATAdBgNVHQ4EFgQUtxq3RVNeuFDQEu/I1Hn4u+aCKogwDQYJKoZIhvcNAQELBQAD -ggEBAIP9672LFvNaBWCvZybv62eUoALJzxGFtXTNa9YjkYHZLwJXBa/8cnCLfSiP -6uxUK3lDL4jF8I0VEWe2q3H2R8AllofFQbqeskD5qrrVjMdV/0tuUHI8RPCr9SPP -Y6wIq3dlk98ZlQEwhBz3M4SYpLKyKAn/E/2ScsW+9vcvAAAK32BO27Tk9Ca6ShtQ -p32q5PZOx9+eicXzW7qb4a26k1aFnnaDEUuSQsKXhzVVyt9Xmg14m8ETeEL5xPfI -PiUZitNmqpg2123YyPwE4NW8okkLO03UD3I0I/Bn0mS0sb8xMt/ncR4iWeJOvZSG -0YhYDYdUoSliRZYy5zTe7orFj7Q= ------END CERTIFICATE-----`) + caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic("failed to generate CA key: " + err.Error()) + } + + caTemplate := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Country: []string{"US"}, + CommonName: "Knative-Example-Root-CA", + }, + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(10 * 365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, + BasicConstraintsValid: true, + IsCA: true, + } + + caDER, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caKey.PublicKey, caKey) + if err != nil { + panic("failed to create CA certificate: " + err.Error()) + } + caPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caDER}) + + serverKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic("failed to generate server key: " + err.Error()) + } + + caCert, err := x509.ParseCertificate(caDER) + if err != nil { + panic("failed to parse CA certificate: " + err.Error()) + } + + serverTemplate := &x509.Certificate{ + SerialNumber: big.NewInt(2), + Subject: pkix.Name{ + Country: []string{"US"}, + Province: []string{"YourState"}, + Locality: []string{"YourCity"}, + Organization: []string{"Example-Certificates"}, + CommonName: "localhost.local", + }, + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(10 * 365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + DNSNames: []string{"localhost"}, + IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)}, + } + + serverDER, err := x509.CreateCertificate(rand.Reader, serverTemplate, caCert, &serverKey.PublicKey, caKey) + if err != nil { + panic("failed to create server certificate: " + err.Error()) + } + serverCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: serverDER}) + + serverKeyDER, err := x509.MarshalPKCS8PrivateKey(serverKey) + if err != nil { + panic("failed to marshal server key: " + err.Error()) + } + serverKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: serverKeyDER}) + + return caPEM, serverKeyPEM, serverCertPEM } diff --git a/vendor/knative.dev/pkg/network/tls/config.go b/vendor/knative.dev/pkg/network/tls/config.go new file mode 100644 index 00000000000..6cd205baeb2 --- /dev/null +++ b/vendor/knative.dev/pkg/network/tls/config.go @@ -0,0 +1,156 @@ +/* +Copyright 2026 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tls + +import ( + cryptotls "crypto/tls" + "fmt" + "os" + "strings" +) + +// Environment variable name suffixes for TLS configuration. +// Use with a prefix to namespace them, e.g. "WEBHOOK_" + MinVersionEnvKey +// reads the WEBHOOK_TLS_MIN_VERSION variable. +const ( + MinVersionEnvKey = "TLS_MIN_VERSION" + MaxVersionEnvKey = "TLS_MAX_VERSION" + CipherSuitesEnvKey = "TLS_CIPHER_SUITES" + CurvePreferencesEnvKey = "TLS_CURVE_PREFERENCES" +) + +// DefaultConfigFromEnv returns a tls.Config with secure defaults. +// The prefix is prepended to each standard env-var suffix; +// for example with prefix "WEBHOOK_" the function reads +// WEBHOOK_TLS_MIN_VERSION, WEBHOOK_TLS_MAX_VERSION, etc. +func DefaultConfigFromEnv(prefix string) (*cryptotls.Config, error) { + cfg := &cryptotls.Config{ + MinVersion: cryptotls.VersionTLS13, + } + + if v := os.Getenv(prefix + MinVersionEnvKey); v != "" { + ver, err := parseVersion(v) + if err != nil { + return nil, fmt.Errorf("invalid %s%s %q: %w", prefix, MinVersionEnvKey, v, err) + } + cfg.MinVersion = ver + } + + if v := os.Getenv(prefix + MaxVersionEnvKey); v != "" { + ver, err := parseVersion(v) + if err != nil { + return nil, fmt.Errorf("invalid %s%s %q: %w", prefix, MaxVersionEnvKey, v, err) + } + cfg.MaxVersion = ver + } + + if v := os.Getenv(prefix + CipherSuitesEnvKey); v != "" { + suites, err := parseCipherSuites(v) + if err != nil { + return nil, fmt.Errorf("invalid %s%s: %w", prefix, CipherSuitesEnvKey, err) + } + cfg.CipherSuites = suites + } + + if v := os.Getenv(prefix + CurvePreferencesEnvKey); v != "" { + curves, err := parseCurvePreferences(v) + if err != nil { + return nil, fmt.Errorf("invalid %s%s: %w", prefix, CurvePreferencesEnvKey, err) + } + cfg.CurvePreferences = curves + } + + return cfg, nil +} + +// parseVersion converts a TLS version string to the corresponding +// crypto/tls constant. Accepted values are "1.2" and "1.3". +func parseVersion(v string) (uint16, error) { + switch v { + case "1.2": + return cryptotls.VersionTLS12, nil + case "1.3": + return cryptotls.VersionTLS13, nil + default: + return 0, fmt.Errorf("unsupported TLS version %q: must be %q or %q", v, "1.2", "1.3") + } +} + +// parseCipherSuites parses a comma-separated list of TLS cipher-suite names +// (e.g. "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384") +// into a slice of cipher-suite IDs. Names must match those returned by +// crypto/tls.CipherSuiteName. +func parseCipherSuites(s string) ([]uint16, error) { + lookup := cipherSuiteLookup() + parts := strings.Split(s, ",") + suites := make([]uint16, 0, len(parts)) + + for _, name := range parts { + name = strings.TrimSpace(name) + if name == "" { + continue + } + id, ok := lookup[name] + if !ok { + return nil, fmt.Errorf("unknown cipher suite %q", name) + } + suites = append(suites, id) + } + + return suites, nil +} + +// parseCurvePreferences parses a comma-separated list of elliptic-curve names +// (e.g. "X25519,CurveP256") into a slice of crypto/tls.CurveID values. +// Both Go constant names (CurveP256) and standard names (P-256) are accepted. +func parseCurvePreferences(s string) ([]cryptotls.CurveID, error) { + parts := strings.Split(s, ",") + curves := make([]cryptotls.CurveID, 0, len(parts)) + + for _, name := range parts { + name = strings.TrimSpace(name) + if name == "" { + continue + } + id, ok := curvesByName[name] + if !ok { + return nil, fmt.Errorf("unknown curve %q", name) + } + curves = append(curves, id) + } + + return curves, nil +} + +func cipherSuiteLookup() map[string]uint16 { + m := make(map[string]uint16) + for _, cs := range cryptotls.CipherSuites() { + m[cs.Name] = cs.ID + } + return m +} + +var curvesByName = map[string]cryptotls.CurveID{ + "CurveP256": cryptotls.CurveP256, + "CurveP384": cryptotls.CurveP384, + "CurveP521": cryptotls.CurveP521, + "X25519": cryptotls.X25519, + "X25519MLKEM768": cryptotls.X25519MLKEM768, + "P-256": cryptotls.CurveP256, + "P-384": cryptotls.CurveP384, + "P-521": cryptotls.CurveP521, +} diff --git a/vendor/knative.dev/pkg/webhook/env.go b/vendor/knative.dev/pkg/webhook/env.go index e622f5f97b5..6d3d32203f4 100644 --- a/vendor/knative.dev/pkg/webhook/env.go +++ b/vendor/knative.dev/pkg/webhook/env.go @@ -72,6 +72,8 @@ func SecretNameFromEnv(defaultSecretName string) string { return secret } +// Deprecated: Use knative.dev/pkg/network/tls.DefaultConfigFromEnv instead. +// TLS configuration is now read automatically inside webhook.New via the shared tls package. func TLSMinVersionFromEnv(defaultTLSMinVersion uint16) uint16 { switch tlsMinVersion := os.Getenv(tlsMinVersionEnvKey); tlsMinVersion { case "1.2": diff --git a/vendor/knative.dev/pkg/webhook/webhook.go b/vendor/knative.dev/pkg/webhook/webhook.go index badc7fef834..e8895db75e5 100644 --- a/vendor/knative.dev/pkg/webhook/webhook.go +++ b/vendor/knative.dev/pkg/webhook/webhook.go @@ -33,6 +33,7 @@ import ( kubeinformerfactory "knative.dev/pkg/injection/clients/namespacedkube/informers/factory" "knative.dev/pkg/network" "knative.dev/pkg/network/handlers" + knativetls "knative.dev/pkg/network/tls" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel/metric" @@ -46,7 +47,15 @@ import ( "knative.dev/pkg/system" ) -// Options contains the configuration for the webhook +// Options contains the configuration for the webhook. +// +// TLS fields (TLSMinVersion, TLSMaxVersion, TLSCipherSuites, TLSCurvePreferences) +// are resolved with the following precedence: +// 1. Values set explicitly in Options (programmatic). +// 2. WEBHOOK_TLS_* environment variables (WEBHOOK_TLS_MIN_VERSION, +// WEBHOOK_TLS_MAX_VERSION, WEBHOOK_TLS_CIPHER_SUITES, WEBHOOK_TLS_CURVE_PREFERENCES). +// 3. Defaults (TLS 1.3 minimum version; zero values for the rest, meaning the +// Go standard library picks its defaults). type Options struct { // TLSMinVersion contains the minimum TLS version that is acceptable to communicate with the API server. // TLS 1.3 is the minimum version if not specified otherwise. @@ -180,11 +189,29 @@ func New( logger := logging.FromContext(ctx) - defaultTLSMinVersion := uint16(tls.VersionTLS13) - if opts.TLSMinVersion == 0 { - opts.TLSMinVersion = TLSMinVersionFromEnv(defaultTLSMinVersion) - } else if opts.TLSMinVersion != tls.VersionTLS12 && opts.TLSMinVersion != tls.VersionTLS13 { - return nil, fmt.Errorf("unsupported TLS version: %d", opts.TLSMinVersion) + tlsCfg, err := knativetls.DefaultConfigFromEnv("WEBHOOK_") + if err != nil { + return nil, fmt.Errorf("reading TLS configuration from environment: %w", err) + } + + if opts.TLSMinVersion != 0 { + tlsCfg.MinVersion = opts.TLSMinVersion + } + if opts.TLSMaxVersion != 0 { + tlsCfg.MaxVersion = opts.TLSMaxVersion + } + if opts.TLSCipherSuites != nil { + tlsCfg.CipherSuites = opts.TLSCipherSuites + } + if opts.TLSCurvePreferences != nil { + tlsCfg.CurvePreferences = opts.TLSCurvePreferences + } + + if tlsCfg.MinVersion != tls.VersionTLS12 && tlsCfg.MinVersion != tls.VersionTLS13 { + return nil, fmt.Errorf("unsupported TLS minimum version %d: must be TLS 1.2 or TLS 1.3", tlsCfg.MinVersion) + } + if tlsCfg.MaxVersion != 0 && tlsCfg.MinVersion > tlsCfg.MaxVersion { + return nil, fmt.Errorf("TLS minimum version (%#x) is greater than maximum version (%#x)", tlsCfg.MinVersion, tlsCfg.MaxVersion) } syncCtx, cancel := context.WithCancel(context.Background()) @@ -204,42 +231,35 @@ func New( // a new secret informer from it. secretInformer := kubeinformerfactory.Get(ctx).Core().V1().Secrets() - //nolint:gosec // operator configures TLS min version (default is 1.3) - webhook.tlsConfig = &tls.Config{ - MinVersion: opts.TLSMinVersion, - MaxVersion: opts.TLSMaxVersion, - CipherSuites: opts.TLSCipherSuites, - CurvePreferences: opts.TLSCurvePreferences, - - // If we return (nil, error) the client sees - 'tls: internal error" - // If we return (nil, nil) the client sees - 'tls: no certificates configured' - // - // We'll return (nil, nil) when we don't find a certificate - GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) { - secret, err := secretInformer.Lister().Secrets(system.Namespace()).Get(opts.SecretName) - if err != nil { - logger.Errorw("failed to fetch secret", zap.Error(err)) - return nil, nil - } - webOpts := GetOptions(ctx) - sKey, sCert := getSecretDataKeyNamesOrDefault(webOpts.ServerPrivateKeyName, webOpts.ServerCertificateName) - serverKey, ok := secret.Data[sKey] - if !ok { - logger.Warn("server key missing") - return nil, nil - } - serverCert, ok := secret.Data[sCert] - if !ok { - logger.Warn("server cert missing") - return nil, nil - } - cert, err := tls.X509KeyPair(serverCert, serverKey) - if err != nil { - return nil, err - } - return &cert, nil - }, + // If we return (nil, error) the client sees - 'tls: internal error' + // If we return (nil, nil) the client sees - 'tls: no certificates configured' + // + // We'll return (nil, nil) when we don't find a certificate + tlsCfg.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + secret, err := secretInformer.Lister().Secrets(system.Namespace()).Get(opts.SecretName) + if err != nil { + logger.Errorw("failed to fetch secret", zap.Error(err)) + return nil, nil + } + webOpts := GetOptions(ctx) + sKey, sCert := getSecretDataKeyNamesOrDefault(webOpts.ServerPrivateKeyName, webOpts.ServerCertificateName) + serverKey, ok := secret.Data[sKey] + if !ok { + logger.Warn("server key missing") + return nil, nil + } + serverCert, ok := secret.Data[sCert] + if !ok { + logger.Warn("server cert missing") + return nil, nil + } + cert, err := tls.X509KeyPair(serverCert, serverKey) + if err != nil { + return nil, err + } + return &cert, nil } + webhook.tlsConfig = tlsCfg } webhook.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { diff --git a/vendor/modules.txt b/vendor/modules.txt index a20a77d351a..9d4a4d0260d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1237,7 +1237,7 @@ knative.dev/hack/schema/commands knative.dev/hack/schema/docs knative.dev/hack/schema/registry knative.dev/hack/schema/schema -# knative.dev/pkg v0.0.0-20260120122510-4a022ed9999a +# knative.dev/pkg v0.0.0-20260319144603-18c5d580ae64 ## explicit; go 1.24.0 knative.dev/pkg/apiextensions/storageversion knative.dev/pkg/apiextensions/storageversion/cmd/migrate @@ -1348,6 +1348,7 @@ knative.dev/pkg/logging/logkey knative.dev/pkg/logging/testing knative.dev/pkg/network knative.dev/pkg/network/handlers +knative.dev/pkg/network/tls knative.dev/pkg/observability knative.dev/pkg/observability/attributekey knative.dev/pkg/observability/configmap