|  | 
|  | 1 | +/* | 
|  | 2 | +Copyright 2025 The llm-d-inference-sim Authors. | 
|  | 3 | +
 | 
|  | 4 | +Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | +you may not use this file except in compliance with the License. | 
|  | 6 | +You may obtain a copy of the License at | 
|  | 7 | +
 | 
|  | 8 | +	http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | +
 | 
|  | 10 | +Unless required by applicable law or agreed to in writing, software | 
|  | 11 | +distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | +See the License for the specific language governing permissions and | 
|  | 14 | +limitations under the License. | 
|  | 15 | +*/ | 
|  | 16 | + | 
|  | 17 | +package llmdinferencesim | 
|  | 18 | + | 
|  | 19 | +import ( | 
|  | 20 | +	"crypto/rand" | 
|  | 21 | +	"crypto/rsa" | 
|  | 22 | +	"crypto/tls" | 
|  | 23 | +	"crypto/x509" | 
|  | 24 | +	"crypto/x509/pkix" | 
|  | 25 | +	"encoding/pem" | 
|  | 26 | +	"fmt" | 
|  | 27 | +	"math/big" | 
|  | 28 | +	"net" | 
|  | 29 | +	"time" | 
|  | 30 | + | 
|  | 31 | +	"github.com/valyala/fasthttp" | 
|  | 32 | +) | 
|  | 33 | + | 
|  | 34 | +// Based on: https://github.com/kubernetes-sigs/gateway-api-inference-extension/blob/8d01161ec48d6b49cd371f179551b35da46e6fd6/internal/tls/tls.go | 
|  | 35 | +func (s *VllmSimulator) configureSSL(server *fasthttp.Server) error { | 
|  | 36 | +	if !s.config.SSLEnabled() { | 
|  | 37 | +		return nil | 
|  | 38 | +	} | 
|  | 39 | + | 
|  | 40 | +	var cert tls.Certificate | 
|  | 41 | +	var err error | 
|  | 42 | + | 
|  | 43 | +	if s.config.SSLCertFile != "" && s.config.SSLKeyFile != "" { | 
|  | 44 | +		s.logger.Info("HTTPS server starting with certificate files", "cert", s.config.SSLCertFile, "key", s.config.SSLKeyFile) | 
|  | 45 | +		cert, err = tls.LoadX509KeyPair(s.config.SSLCertFile, s.config.SSLKeyFile) | 
|  | 46 | +		if err == nil { | 
|  | 47 | +			s.logger.Info("Certificate loaded successfully from files") | 
|  | 48 | +		} | 
|  | 49 | +	} else if s.config.SelfSignedCerts { | 
|  | 50 | +		s.logger.Info("HTTPS server starting with self-signed certificate") | 
|  | 51 | +		cert, err = CreateSelfSignedTLSCertificate() | 
|  | 52 | +		if err == nil { | 
|  | 53 | +			s.logger.Info("Self-signed certificate generated successfully") | 
|  | 54 | +		} | 
|  | 55 | +	} | 
|  | 56 | + | 
|  | 57 | +	if err != nil { | 
|  | 58 | +		s.logger.Error(err, "failed to create TLS certificate") | 
|  | 59 | +		return err | 
|  | 60 | +	} | 
|  | 61 | + | 
|  | 62 | +	server.TLSConfig = &tls.Config{ | 
|  | 63 | +		Certificates: []tls.Certificate{cert}, | 
|  | 64 | +		MinVersion:   tls.VersionTLS12, | 
|  | 65 | +		CipherSuites: []uint16{ | 
|  | 66 | +			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | 
|  | 67 | +			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, | 
|  | 68 | +			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | 
|  | 69 | +			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, | 
|  | 70 | +			tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, | 
|  | 71 | +			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, | 
|  | 72 | +		}, | 
|  | 73 | +	} | 
|  | 74 | + | 
|  | 75 | +	return nil | 
|  | 76 | +} | 
|  | 77 | + | 
|  | 78 | +// CreateSelfSignedTLSCertificatePEM creates a self-signed cert and returns the PEM-encoded certificate and key bytes | 
|  | 79 | +func CreateSelfSignedTLSCertificatePEM() (certPEM, keyPEM []byte, err error) { | 
|  | 80 | +	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) | 
|  | 81 | +	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | 
|  | 82 | +	if err != nil { | 
|  | 83 | +		return nil, nil, fmt.Errorf("error creating serial number: %v", err) | 
|  | 84 | +	} | 
|  | 85 | +	now := time.Now() | 
|  | 86 | +	notBefore := now.UTC() | 
|  | 87 | +	template := x509.Certificate{ | 
|  | 88 | +		SerialNumber: serialNumber, | 
|  | 89 | +		Subject: pkix.Name{ | 
|  | 90 | +			Organization: []string{"llm-d Inference Simulator"}, | 
|  | 91 | +		}, | 
|  | 92 | +		NotBefore:             notBefore, | 
|  | 93 | +		NotAfter:              now.Add(time.Hour * 24 * 365 * 10).UTC(), // 10 years | 
|  | 94 | +		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, | 
|  | 95 | +		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, | 
|  | 96 | +		BasicConstraintsValid: true, | 
|  | 97 | +		IPAddresses:           []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}, | 
|  | 98 | +		DNSNames:              []string{"localhost"}, | 
|  | 99 | +	} | 
|  | 100 | + | 
|  | 101 | +	priv, err := rsa.GenerateKey(rand.Reader, 4096) | 
|  | 102 | +	if err != nil { | 
|  | 103 | +		return nil, nil, fmt.Errorf("error generating key: %v", err) | 
|  | 104 | +	} | 
|  | 105 | + | 
|  | 106 | +	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) | 
|  | 107 | +	if err != nil { | 
|  | 108 | +		return nil, nil, fmt.Errorf("error creating certificate: %v", err) | 
|  | 109 | +	} | 
|  | 110 | + | 
|  | 111 | +	certBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) | 
|  | 112 | + | 
|  | 113 | +	privBytes, err := x509.MarshalPKCS8PrivateKey(priv) | 
|  | 114 | +	if err != nil { | 
|  | 115 | +		return nil, nil, fmt.Errorf("error marshalling private key: %v", err) | 
|  | 116 | +	} | 
|  | 117 | +	keyBytes := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}) | 
|  | 118 | + | 
|  | 119 | +	return certBytes, keyBytes, nil | 
|  | 120 | +} | 
|  | 121 | + | 
|  | 122 | +// CreateSelfSignedTLSCertificate creates a self-signed cert the server can use to serve TLS. | 
|  | 123 | +// Original code: https://github.com/kubernetes-sigs/gateway-api-inference-extension/blob/8d01161ec48d6b49cd371f179551b35da46e6fd6/internal/tls/tls.go | 
|  | 124 | +func CreateSelfSignedTLSCertificate() (tls.Certificate, error) { | 
|  | 125 | +	certPEM, keyPEM, err := CreateSelfSignedTLSCertificatePEM() | 
|  | 126 | +	if err != nil { | 
|  | 127 | +		return tls.Certificate{}, err | 
|  | 128 | +	} | 
|  | 129 | +	return tls.X509KeyPair(certPEM, keyPEM) | 
|  | 130 | +} | 
0 commit comments