1
0
Fork 0

fix: do not require a TLS client cert when InsecureSkipVerify is false

Co-authored-by: Tom Moulard <tom.moulard@traefik.io>
This commit is contained in:
Kevin Pollet 2021-10-26 10:54:11 +02:00 committed by GitHub
parent 566b205758
commit d3ff0c2cd4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 273 additions and 184 deletions

View file

@ -1,14 +1,11 @@
package dynamic
import (
"crypto/tls"
"crypto/x509"
"fmt"
"os"
"time"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v2/pkg/ip"
"github.com/traefik/traefik/v2/pkg/types"
)
// +k8s:deepcopy-gen=true
@ -130,12 +127,12 @@ type ErrorPage struct {
// ForwardAuth holds the http forward authentication configuration.
type ForwardAuth struct {
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
TLS *ClientTLS `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
TrustForwardHeader bool `json:"trustForwardHeader,omitempty" toml:"trustForwardHeader,omitempty" yaml:"trustForwardHeader,omitempty" export:"true"`
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty" toml:"authResponseHeaders,omitempty" yaml:"authResponseHeaders,omitempty" export:"true"`
AuthResponseHeadersRegex string `json:"authResponseHeadersRegex,omitempty" toml:"authResponseHeadersRegex,omitempty" yaml:"authResponseHeadersRegex,omitempty" export:"true"`
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty" export:"true"`
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
TLS *types.ClientTLS `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
TrustForwardHeader bool `json:"trustForwardHeader,omitempty" toml:"trustForwardHeader,omitempty" yaml:"trustForwardHeader,omitempty" export:"true"`
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty" toml:"authResponseHeaders,omitempty" yaml:"authResponseHeaders,omitempty" export:"true"`
AuthResponseHeadersRegex string `json:"authResponseHeadersRegex,omitempty" toml:"authResponseHeadersRegex,omitempty" yaml:"authResponseHeadersRegex,omitempty" export:"true"`
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@ -402,16 +399,16 @@ type TLSClientCertificateInfo struct {
NotAfter bool `json:"notAfter,omitempty" toml:"notAfter,omitempty" yaml:"notAfter,omitempty" export:"true"`
NotBefore bool `json:"notBefore,omitempty" toml:"notBefore,omitempty" yaml:"notBefore,omitempty" export:"true"`
Sans bool `json:"sans,omitempty" toml:"sans,omitempty" yaml:"sans,omitempty" export:"true"`
Subject *TLSCLientCertificateDNInfo `json:"subject,omitempty" toml:"subject,omitempty" yaml:"subject,omitempty" export:"true"`
Issuer *TLSCLientCertificateDNInfo `json:"issuer,omitempty" toml:"issuer,omitempty" yaml:"issuer,omitempty" export:"true"`
Subject *TLSClientCertificateDNInfo `json:"subject,omitempty" toml:"subject,omitempty" yaml:"subject,omitempty" export:"true"`
Issuer *TLSClientCertificateDNInfo `json:"issuer,omitempty" toml:"issuer,omitempty" yaml:"issuer,omitempty" export:"true"`
SerialNumber bool `json:"serialNumber,omitempty" toml:"serialNumber,omitempty" yaml:"serialNumber,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
// TLSCLientCertificateDNInfo holds the client TLS certificate distinguished name info configuration.
// TLSClientCertificateDNInfo holds the client TLS certificate distinguished name info configuration.
// cf https://tools.ietf.org/html/rfc3739
type TLSCLientCertificateDNInfo struct {
type TLSClientCertificateDNInfo struct {
Country bool `json:"country,omitempty" toml:"country,omitempty" yaml:"country,omitempty" export:"true"`
Province bool `json:"province,omitempty" toml:"province,omitempty" yaml:"province,omitempty" export:"true"`
Locality bool `json:"locality,omitempty" toml:"locality,omitempty" yaml:"locality,omitempty" export:"true"`
@ -425,83 +422,3 @@ type TLSCLientCertificateDNInfo struct {
// Users holds a list of users.
type Users []string
// +k8s:deepcopy-gen=true
// ClientTLS holds the TLS specific configurations as client
// CA, Cert and Key can be either path or file contents.
type ClientTLS struct {
CA string `json:"ca,omitempty" toml:"ca,omitempty" yaml:"ca,omitempty"`
CAOptional bool `json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty" export:"true"`
Cert string `json:"cert,omitempty" toml:"cert,omitempty" yaml:"cert,omitempty"`
Key string `json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty"`
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
}
// CreateTLSConfig creates a TLS config from ClientTLS structures.
func (c *ClientTLS) CreateTLSConfig() (*tls.Config, error) {
if c == nil {
return nil, nil
}
var err error
caPool := x509.NewCertPool()
clientAuth := tls.NoClientCert
if c.CA != "" {
var ca []byte
if _, errCA := os.Stat(c.CA); errCA == nil {
ca, err = os.ReadFile(c.CA)
if err != nil {
return nil, fmt.Errorf("failed to read CA. %w", err)
}
} else {
ca = []byte(c.CA)
}
if !caPool.AppendCertsFromPEM(ca) {
return nil, fmt.Errorf("failed to parse CA")
}
if c.CAOptional {
clientAuth = tls.VerifyClientCertIfGiven
} else {
clientAuth = tls.RequireAndVerifyClientCert
}
}
cert := tls.Certificate{}
_, errKeyIsFile := os.Stat(c.Key)
if !c.InsecureSkipVerify && (len(c.Cert) == 0 || len(c.Key) == 0) {
return nil, fmt.Errorf("TLS Certificate or Key file must be set when TLS configuration is created")
}
if len(c.Cert) > 0 && len(c.Key) > 0 {
if _, errCertIsFile := os.Stat(c.Cert); errCertIsFile == nil {
if errKeyIsFile == nil {
cert, err = tls.LoadX509KeyPair(c.Cert, c.Key)
if err != nil {
return nil, fmt.Errorf("failed to load TLS keypair: %w", err)
}
} else {
return nil, fmt.Errorf("tls cert is a file, but tls key is not")
}
} else {
if errKeyIsFile != nil {
cert, err = tls.X509KeyPair([]byte(c.Cert), []byte(c.Key))
if err != nil {
return nil, fmt.Errorf("failed to load TLS keypair: %w", err)
}
} else {
return nil, fmt.Errorf("TLS key is a file, but tls cert is not")
}
}
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caPool,
InsecureSkipVerify: c.InsecureSkipVerify,
ClientAuth: clientAuth,
}, nil
}