-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
tls.go
107 lines (88 loc) · 2.94 KB
/
tls.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package types
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"os"
"github.com/traefik/traefik/v2/pkg/log"
)
// +k8s:deepcopy-gen=true
// ClientTLS holds TLS specific configurations as client
// CA, Cert and Key can be either path or file contents.
type ClientTLS struct {
CA string `description:"TLS CA" json:"ca,omitempty" toml:"ca,omitempty" yaml:"ca,omitempty"`
// Deprecated: TLS client authentication is a server side option (see https://github.com/golang/go/blob/740a490f71d026bb7d2d13cb8fa2d6d6e0572b70/src/crypto/tls/common.go#L634).
CAOptional bool `description:"TLS CA.Optional" json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty" export:"true"`
Cert string `description:"TLS cert" json:"cert,omitempty" toml:"cert,omitempty" yaml:"cert,omitempty"`
Key string `description:"TLS key" json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty" loggable:"false"`
InsecureSkipVerify bool `description:"TLS insecure skip verify" json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
}
// CreateTLSConfig creates a TLS config from ClientTLS structures.
func (c *ClientTLS) CreateTLSConfig(ctx context.Context) (*tls.Config, error) {
if c == nil {
log.FromContext(ctx).Warnf("clientTLS is nil")
return nil, nil
}
if c.CAOptional {
log.FromContext(ctx).Warn("CAOptional is deprecated, TLS client authentication is a server side option.")
}
// Not initialized, to rely on system bundle.
var caPool *x509.CertPool
if c.CA != "" {
var ca []byte
if _, errCA := os.Stat(c.CA); errCA == nil {
var err error
ca, err = os.ReadFile(c.CA)
if err != nil {
return nil, fmt.Errorf("failed to read CA. %w", err)
}
} else {
ca = []byte(c.CA)
}
caPool = x509.NewCertPool()
if !caPool.AppendCertsFromPEM(ca) {
return nil, errors.New("failed to parse CA")
}
}
hasCert := len(c.Cert) > 0
hasKey := len(c.Key) > 0
if hasCert != hasKey {
return nil, errors.New("both TLS cert and key must be defined")
}
if !hasCert || !hasKey {
return &tls.Config{
RootCAs: caPool,
InsecureSkipVerify: c.InsecureSkipVerify,
}, nil
}
cert, err := loadKeyPair(c.Cert, c.Key)
if err != nil {
return nil, err
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caPool,
InsecureSkipVerify: c.InsecureSkipVerify,
}, nil
}
func loadKeyPair(cert, key string) (tls.Certificate, error) {
keyPair, err := tls.X509KeyPair([]byte(cert), []byte(key))
if err == nil {
return keyPair, nil
}
_, err = os.Stat(cert)
if err != nil {
return tls.Certificate{}, errors.New("cert file does not exist")
}
_, err = os.Stat(key)
if err != nil {
return tls.Certificate{}, errors.New("key file does not exist")
}
keyPair, err = tls.LoadX509KeyPair(cert, key)
if err != nil {
return tls.Certificate{}, err
}
return keyPair, nil
}