-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathclient_tls.go
139 lines (120 loc) · 4.28 KB
/
client_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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2021-2024 Nokia
// Licensed under the BSD 3-Clause License.
// SPDX-License-Identifier: BSD-3-Clause
package restful
import (
"crypto/tls"
"crypto/x509"
"net/http"
"os"
"path/filepath"
"strings"
log "github.com/sirupsen/logrus"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"golang.org/x/net/http2"
)
// TLS sets TLS setting for client. Returns object instance, just in case you need that.
// Use if specific config is needed, e.g. server cert or whether to accept untrusted certs.
// You may use it this way: client := New().TLS(...) or just client.TLS(...)
func (c *Client) TLS(tlsConfig *tls.Config) *Client {
if transport, ok := c.Client.Transport.(*http.Transport); ok {
transport.TLSClientConfig = tlsConfig
} else {
if isTraced {
c.Client.Transport = otelhttp.NewTransport(&http.Transport{TLSClientConfig: tlsConfig})
} else {
c.Client.Transport = &http.Transport{TLSClientConfig: tlsConfig}
}
}
return c
}
func appendCert(path string, pool *x509.CertPool) {
pem, err := os.ReadFile(path) // #nosec
if err != nil {
log.Errorf("Error reading CA from '%s': %v", path, err)
return
}
if !pool.AppendCertsFromPEM(pem) {
log.Errorf("Error parsing CA at '%s': %v", path, err)
}
log.Debugf("Appended cert from '%s'", path)
}
// NewCertPool adds PEM certificates from given path in a way that is usable at TLS() as RootCAs.
// If path is a directory then scans for files recursively. If path is not set then defaults to /etc.
// If loadSystemCerts is true, the given client certificates are complemented with system root certificates.
// File name should match *.crt or *.pem.
func NewCertPool(path string, loadSystemCerts bool) *x509.CertPool {
pool, err := initialCertPool(loadSystemCerts)
if err != nil {
log.Fatalf("Failed to init certificate pool: %v", err)
}
if path == "" {
path = "/etc"
}
walkFn := func(path string, info os.FileInfo, err error) error {
if err == nil && !info.IsDir() {
ext := strings.ToLower(filepath.Ext(info.Name()))
if ext == ".pem" || ext == ".crt" {
appendCert(path, pool)
}
}
return err
}
err = filepath.Walk(path, walkFn)
if err != nil {
log.Errorf("Error finding CA files at '%s': %v", path, err)
}
return pool
}
func initialCertPool(loadSystemCerts bool) (*x509.CertPool, error) {
if loadSystemCerts {
return x509.SystemCertPool()
}
return x509.NewCertPool(), nil
}
func (c *Client) haveTLSClientConfig() *tls.Config {
// HTTP2
if transport2, ok := c.Client.Transport.(*http2.Transport); ok {
if transport2.TLSClientConfig == nil {
transport2.TLSClientConfig = &tls.Config{MinVersion: tls.VersionTLS12}
}
return transport2.TLSClientConfig
}
// HTTP 1.x
transport, ok := c.Client.Transport.(*http.Transport)
if !ok {
transport = &http.Transport{}
c.Client.Transport = transport
}
if transport.TLSClientConfig == nil {
transport.TLSClientConfig = &tls.Config{} // #nosec G402 -- false positive, see below
}
transport.TLSClientConfig.MinVersion = tls.VersionTLS12 // TLS 1.2 is the minimum supported.
return transport.TLSClientConfig
}
// TLSRootCerts loads PEM certificates from given path and sets TLS config accordingly.
// Cert can be Root CA or self-signed server cert, so that client can authenticate servers.
// If loadSystemCerts is true, the client accepts server CAs from system settings, too.
// If path is a directory then scans for files recursively. If path is not set then defaults to /etc.
// File name should match *.crt or *.pem.
func (c *Client) TLSRootCerts(path string, loadSystemCerts bool) *Client {
c.haveTLSClientConfig().RootCAs = NewCertPool(path, loadSystemCerts)
return c
}
// TLSOwnCerts loads PEM certificate + key from given directory and sets TLS config accordingly.
// Cert + key is used at mutual TLS (mTLS) connection when client authenticates itself.
// File names should be tls.crt and tls.key (see `kubectl create secret tls`).
func (c *Client) TLSOwnCerts(dir string) *Client {
cert, err := tls.LoadX509KeyPair(dir+"/tls.crt", dir+"/tls.key")
if err != nil {
log.Errorf("Cannot load client cert+key: %v", err)
} else {
c.haveTLSClientConfig().Certificates = []tls.Certificate{cert}
}
return c
}
// Insecure makes client skip server name checking.
func (c *Client) Insecure() *Client {
c.haveTLSClientConfig().InsecureSkipVerify = true
return c
}