Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
reverse_proxy: Implement remaining TLS config for proxy to backend
Matthew Holt committed
Sep 3, 2019 at 15:26 UTC
4a1e1649bc985e9658d326ed433a101d7d79ae30
1 file changed
+81
-5
modules/caddyhttp/reverseproxy/httptransport.go
+81
-5
@@ -15,8 +15,13 @@
15
package reverseproxy
16
17
import (
18
+ "crypto/tls"
19
+ "crypto/x509"
20
+ "encoding/base64"
21
+ "fmt"
22
"net"
23
"net/http"
24
+ "reflect"
25
"time"
26
27
"github.com/caddyserver/caddy/v2"
@@ -76,7 +81,12 @@ func (h *HTTPTransport) Provision(ctx caddy.Context) error {
81
82
if h.TLS != nil {
83
rt.TLSHandshakeTimeout = time.Duration(h.TLS.HandshakeTimeout)
79
- // TODO: rest of TLS config
84
+
85
+ var err error
86
+ rt.TLSClientConfig, err = h.TLS.MakeTLSClientConfig()
87
+ if err != nil {
88
+ return fmt.Errorf("making TLS client config: %v", err)
89
+ }
90
}
91
92
if h.KeepAlive != nil {
@@ -103,11 +113,77 @@ func (h HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
113
return h.RoundTripper.RoundTrip(req)
114
}
115
116
+func defaultTLSConfig() *tls.Config {
117
+ return &tls.Config{
118
+ NextProtos: []string{"h2", "http/1.1"}, // TODO: ensure this makes HTTP/2 work
119
+ }
120
+}
121
+
122
type TLSConfig struct {
107
- CAPool []string `json:"ca_pool,omitempty"`
108
- ClientCertificate string `json:"client_certificate,omitempty"`
109
- InsecureSkipVerify bool `json:"insecure_skip_verify,omitempty"`
110
- HandshakeTimeout caddy.Duration `json:"handshake_timeout,omitempty"`
123
+ RootCAPool []string `json:"root_ca_pool,omitempty"`
124
+ // TODO: Should the client cert+key config use caddytls.CertificateLoader modules?
125
+ ClientCertificateFile string `json:"client_certificate_file,omitempty"`
126
+ ClientCertificateKeyFile string `json:"client_certificate_key_file,omitempty"`
127
+ InsecureSkipVerify bool `json:"insecure_skip_verify,omitempty"`
128
+ HandshakeTimeout caddy.Duration `json:"handshake_timeout,omitempty"`
129
+}
130
+
131
+// MakeTLSClientConfig returns a tls.Config usable by a client to a backend.
132
+// If there is no custom TLS configuration, a nil config may be returned.
133
+func (t TLSConfig) MakeTLSClientConfig() (*tls.Config, error) {
134
+ cfg := new(tls.Config)
135
+
136
+ // client auth
137
+ if t.ClientCertificateFile != "" && t.ClientCertificateKeyFile == "" {
138
+ return nil, fmt.Errorf("client_certificate_file specified without client_certificate_key_file")
139
+ }
140
+ if t.ClientCertificateFile == "" && t.ClientCertificateKeyFile != "" {
141
+ return nil, fmt.Errorf("client_certificate_key_file specified without client_certificate_file")
142
+ }
143
+ if t.ClientCertificateFile != "" && t.ClientCertificateKeyFile != "" {
144
+ cert, err := tls.LoadX509KeyPair(t.ClientCertificateFile, t.ClientCertificateKeyFile)
145
+ if err != nil {
146
+ return nil, fmt.Errorf("loading client certificate key pair: %v", err)
147
+ }
148
+ cfg.Certificates = []tls.Certificate{cert}
149
+ }
150
+
151
+ // trusted root CAs
152
+ if len(t.RootCAPool) > 0 {
153
+ rootPool := x509.NewCertPool()
154
+ for _, encodedCACert := range t.RootCAPool {
155
+ caCert, err := decodeBase64DERCert(encodedCACert)
156
+ if err != nil {
157
+ return nil, fmt.Errorf("parsing CA certificate: %v", err)
158
+ }
159
+ rootPool.AddCert(caCert)
160
+ }
161
+ cfg.RootCAs = rootPool
162
+ }
163
+
164
+ // throw all security out the window
165
+ cfg.InsecureSkipVerify = t.InsecureSkipVerify
166
+
167
+ // only return a config if it's not empty
168
+ if reflect.DeepEqual(cfg, new(tls.Config)) {
169
+ return nil, nil
170
+ }
171
+
172
+ cfg.NextProtos = []string{"h2", "http/1.1"} // TODO: ensure that this actually enables HTTP/2
173
+
174
+ return cfg, nil
175
+}
176
+
177
+// decodeBase64DERCert base64-decodes, then DER-decodes, certStr.
178
+func decodeBase64DERCert(certStr string) (*x509.Certificate, error) {
179
+ // decode base64
180
+ derBytes, err := base64.StdEncoding.DecodeString(certStr)
181
+ if err != nil {
182
+ return nil, err
183
+ }
184
+
185
+ // parse the DER-encoded certificate
186
+ return x509.ParseCertificate(derBytes)
187
}
188
189
type KeepAlive struct {