TUN-10725: Remove unused certificate configuration

This commit is contained in:
Devin Carr
2026-08-26 12:08:44 +01:00
committed by João "Pisco" Fernandes
parent a9c0d487b9
commit 001e9aa9cf
3 changed files with 22 additions and 232 deletions
@@ -1,3 +1,4 @@
// Package tlsconfig builds base TLS configuration for edge and origin connections.
package tlsconfig
import (
@@ -6,9 +7,7 @@ import (
"fmt"
"os"
"runtime"
"sync"
"github.com/getsentry/sentry-go"
"github.com/pkg/errors"
"github.com/rs/zerolog"
)
@@ -17,59 +16,6 @@ const (
OriginCAPoolFlag = "origin-ca-pool"
)
// CertReloader can load and reload a TLS certificate from a particular filepath.
// Hooks into tls.Config's GetCertificate to allow a TLS server to update its certificate without restarting.
type CertReloader struct {
sync.Mutex
certificate *tls.Certificate
certPath string
keyPath string
}
// NewCertReloader makes a CertReloader. It loads the cert during initialization to make sure certPath and keyPath are valid
func NewCertReloader(certPath, keyPath string) (*CertReloader, error) {
cr := new(CertReloader)
cr.certPath = certPath
cr.keyPath = keyPath
if err := cr.LoadCert(); err != nil {
return nil, err
}
return cr, nil
}
// Cert returns the TLS certificate most recently read by the CertReloader.
// This method works as a direct utility method for tls.Config#Cert.
func (cr *CertReloader) Cert(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
cr.Lock()
defer cr.Unlock()
return cr.certificate, nil
}
// ClientCert returns the TLS certificate most recently read by the CertReloader.
// This method works as a direct utility method for tls.Config#ClientCert.
func (cr *CertReloader) ClientCert(certRequestInfo *tls.CertificateRequestInfo) (*tls.Certificate, error) {
cr.Lock()
defer cr.Unlock()
return cr.certificate, nil
}
// LoadCert loads a TLS certificate from the CertReloader's specified filepath.
// Call this after writing a new certificate to the disk (e.g. after renewing a certificate)
func (cr *CertReloader) LoadCert() error {
cr.Lock()
defer cr.Unlock()
cert, err := tls.LoadX509KeyPair(cr.certPath, cr.keyPath)
// Keep the old certificate if there's a problem reading the new one.
if err != nil {
sentry.CaptureException(fmt.Errorf("error parsing X509 key pair: %v", err))
return err
}
cr.certificate = &cert
return nil
}
func LoadOriginCA(originCAPoolFilename string, log *zerolog.Logger) (*x509.CertPool, error) {
var originCustomCAPool []byte
@@ -128,15 +74,18 @@ func LoadCustomOriginCA(originCAFilename string) (*x509.CertPool, error) {
}
func CreateTunnelConfig(caCert string, serverName string) (*tls.Config, error) {
var rootCAs []string
tlsConfig := &tls.Config{ServerName: serverName}
if caCert != "" {
rootCAs = append(rootCAs, caCert)
}
caCertPEM, err := os.ReadFile(caCert) //nolint:gosec
if err != nil {
return nil, fmt.Errorf("read CA certificate %s: %w", caCert, err)
}
userConfig := &TLSParameters{RootCAs: rootCAs, ServerName: serverName}
tlsConfig, err := GetConfig(userConfig)
if err != nil {
return nil, err
rootCAPool := x509.NewCertPool()
if !rootCAPool.AppendCertsFromPEM(caCertPEM) {
return nil, fmt.Errorf("parse CA certificate %s", caCert)
}
tlsConfig.RootCAs = rootCAPool
}
if tlsConfig.RootCAs == nil {
-102
View File
@@ -1,102 +0,0 @@
// Package tlsconfig provides convenience functions for configuring TLS connections from the
// command line.
package tlsconfig
import (
"crypto/tls"
"crypto/x509"
"os"
"github.com/pkg/errors"
)
// Config is the user provided parameters to create a tls.Config
type TLSParameters struct {
Cert string
Key string
GetCertificate *CertReloader
GetClientCertificate *CertReloader
ClientCAs []string
RootCAs []string
ServerName string
CurvePreferences []tls.CurveID
MinVersion uint16 // min tls version. If zero, TLS1.0 is defined as minimum.
MaxVersion uint16 // max tls version. If zero, last TLS version is used defined as limit (currently TLS1.3)
}
// GetConfig returns a TLS configuration according to the Config set by the user.
func GetConfig(p *TLSParameters) (*tls.Config, error) {
tlsconfig := &tls.Config{}
if p.Cert != "" && p.Key != "" {
cert, err := tls.LoadX509KeyPair(p.Cert, p.Key)
if err != nil {
return nil, errors.Wrap(err, "Error parsing X509 key pair")
}
tlsconfig.Certificates = []tls.Certificate{cert}
// BuildNameToCertificate parses Certificates and builds NameToCertificate from common name
// and SAN fields of leaf certificates
tlsconfig.BuildNameToCertificate()
}
if p.GetCertificate != nil {
// GetCertificate is called when client supplies SNI info or Certificates is empty.
// Order of retrieving certificate is GetCertificate, NameToCertificate and lastly first element of Certificates
tlsconfig.GetCertificate = p.GetCertificate.Cert
}
if p.GetClientCertificate != nil {
// GetClientCertificate is called when using an HTTP client library and mTLS is required.
tlsconfig.GetClientCertificate = p.GetClientCertificate.ClientCert
}
if len(p.ClientCAs) > 0 {
// set of root certificate authorities that servers use if required to verify a client certificate
// by the policy in ClientAuth
clientCAs, err := LoadCert(p.ClientCAs)
if err != nil {
return nil, errors.Wrap(err, "Error loading client CAs")
}
tlsconfig.ClientCAs = clientCAs
// server's policy for TLS Client Authentication. Default is no client cert
tlsconfig.ClientAuth = tls.RequireAndVerifyClientCert
}
if len(p.RootCAs) > 0 {
rootCAs, err := LoadCert(p.RootCAs)
if err != nil {
return nil, errors.Wrap(err, "Error loading root CAs")
}
tlsconfig.RootCAs = rootCAs
}
if p.ServerName != "" {
tlsconfig.ServerName = p.ServerName
}
if len(p.CurvePreferences) > 0 {
tlsconfig.CurvePreferences = p.CurvePreferences
} else {
// Cloudflare optimize CurveP256
tlsconfig.CurvePreferences = []tls.CurveID{tls.CurveP256}
}
tlsconfig.MinVersion = p.MinVersion
tlsconfig.MaxVersion = p.MaxVersion
return tlsconfig, nil
}
// LoadCert creates a CertPool containing all certificates in a PEM-format file.
func LoadCert(certPaths []string) (*x509.CertPool, error) {
ca := x509.NewCertPool()
for _, certPath := range certPaths {
caCert, err := os.ReadFile(certPath)
if err != nil {
return nil, errors.Wrapf(err, "Error reading certificate %s", certPath)
}
if !ca.AppendCertsFromPEM(caCert) {
return nil, errors.Wrapf(err, "Error parsing certificate %s", certPath)
}
}
return ca, nil
}
+11 -68
View File
@@ -1,82 +1,25 @@
package tlsconfig
import (
"crypto/tls"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// testcert.pem and testcert2.pem are Generated using `openssl req -newkey rsa:512 -nodes -x509 -days 3650`
const (
testcertCommonName = "localhost"
)
func TestGetFromEmptyConfig(t *testing.T) {
c := &TLSParameters{}
tlsConfig, err := GetConfig(c)
assert.NoError(t, err)
assert.Empty(t, tlsConfig.Certificates)
assert.Empty(t, tlsConfig.NameToCertificate)
assert.Nil(t, tlsConfig.ClientCAs)
assert.Equal(t, tls.NoClientCert, tlsConfig.ClientAuth)
assert.Nil(t, tlsConfig.RootCAs)
assert.Len(t, tlsConfig.CurvePreferences, 1)
assert.Equal(t, tls.CurveP256, tlsConfig.CurvePreferences[0])
}
func TestGetConfig(t *testing.T) {
cert, err := tls.LoadX509KeyPair("testcert.pem", "testkey.pem")
assert.NoError(t, err)
c := &TLSParameters{
Cert: "testcert.pem",
Key: "testkey.pem",
ClientCAs: []string{"testcert.pem", "testcert2.pem"},
RootCAs: []string{"testcert.pem", "testcert2.pem"},
ServerName: "test",
CurvePreferences: []tls.CurveID{tls.CurveP384},
}
tlsConfig, err := GetConfig(c)
assert.NoError(t, err)
assert.Len(t, tlsConfig.Certificates, 1)
assert.Equal(t, cert, tlsConfig.Certificates[0])
assert.Equal(t, cert, *tlsConfig.NameToCertificate[testcertCommonName])
assert.NotNil(t, tlsConfig.ClientCAs)
assert.Equal(t, tls.RequireAndVerifyClientCert, tlsConfig.ClientAuth)
func TestCreateTunnelConfig(t *testing.T) {
t.Parallel()
tlsConfig, err := CreateTunnelConfig("testcert.pem", "edge.example.com")
require.NoError(t, err)
assert.Equal(t, "edge.example.com", tlsConfig.ServerName)
assert.NotNil(t, tlsConfig.RootCAs)
assert.Len(t, tlsConfig.CurvePreferences, 1)
assert.Equal(t, tls.CurveP384, tlsConfig.CurvePreferences[0])
assert.Empty(t, tlsConfig.CurvePreferences)
}
func TestCertReloader(t *testing.T) {
expectedCert, err := tls.LoadX509KeyPair("testcert.pem", "testkey.pem")
assert.NoError(t, err)
func TestCreateTunnelConfigRequiresServerName(t *testing.T) {
t.Parallel()
certReloader, err := NewCertReloader("testcert.pem", "testkey.pem")
assert.NoError(t, err)
chi := &tls.ClientHelloInfo{ServerName: testcertCommonName}
cert, err := certReloader.Cert(chi)
assert.NoError(t, err)
assert.Equal(t, expectedCert, *cert)
c := &TLSParameters{
GetCertificate: certReloader,
}
tlsConfig, err := GetConfig(c)
assert.NoError(t, err)
cert, err = tlsConfig.GetCertificate(chi)
assert.NoError(t, err)
assert.Equal(t, expectedCert, *cert)
_, err := CreateTunnelConfig("testcert.pem", "")
assert.EqualError(t, err, "either ServerName or InsecureSkipVerify must be specified in the tls.Config")
}