@marcel91200 / caddy Mirror · read-only / commits / 4a1e1649
Fork 0

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 {