reverse_proxy: Add tls_trusted_ca_certs to Caddyfile (#2936)

Allows specifying ca certs with by filename in
`reverse_proxy.transport`.

Example
```
reverse_proxy /api api:443 {
    transport http {
        tls
        tls_trusted_ca_certs certs/rootCA.pem
    }
}
```
This commit is contained in:
Zaq? Wiedmann 2020-01-07 11:07:42 -08:00 committed by Matt Holt
parent 78e98c40d3
commit 21f1f95e7b
2 changed files with 27 additions and 1 deletions

View File

@ -425,6 +425,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// tls_client_auth <cert_file> <key_file> // tls_client_auth <cert_file> <key_file>
// tls_insecure_skip_verify // tls_insecure_skip_verify
// tls_timeout <duration> // tls_timeout <duration>
// tls_trusted_ca_certs <cert_files...>
// keepalive [off|<duration>] // keepalive [off|<duration>]
// keepalive_idle_conns <max_count> // keepalive_idle_conns <max_count>
// } // }
@ -501,6 +502,17 @@ func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
} }
h.TLS.HandshakeTimeout = caddy.Duration(dur) h.TLS.HandshakeTimeout = caddy.Duration(dur)
case "tls_trusted_ca_certs":
args := d.RemainingArgs()
if len(args) == 0 {
return d.ArgErr()
}
if h.TLS == nil {
h.TLS = new(TLSConfig)
}
h.TLS.RootCAPemFiles = args
case "keepalive": case "keepalive":
if !d.NextArg() { if !d.NextArg() {
return d.ArgErr() return d.ArgErr()

View File

@ -20,6 +20,7 @@ import (
"crypto/x509" "crypto/x509"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"net/http" "net/http"
"reflect" "reflect"
@ -166,6 +167,9 @@ func (h *HTTPTransport) setScheme(req *http.Request) {
// Cleanup implements caddy.CleanerUpper and closes any idle connections. // Cleanup implements caddy.CleanerUpper and closes any idle connections.
func (h HTTPTransport) Cleanup() error { func (h HTTPTransport) Cleanup() error {
if h.Transport == nil {
return nil
}
h.Transport.CloseIdleConnections() h.Transport.CloseIdleConnections()
return nil return nil
} }
@ -174,6 +178,8 @@ func (h HTTPTransport) Cleanup() error {
// TLS configuration for the transport/client. // TLS configuration for the transport/client.
type TLSConfig struct { type TLSConfig struct {
RootCAPool []string `json:"root_ca_pool,omitempty"` RootCAPool []string `json:"root_ca_pool,omitempty"`
// Added to the same pool as above, but brought in from files
RootCAPemFiles []string `json:"root_ca_pem_files,omitempty"`
// TODO: Should the client cert+key config use caddytls.CertificateLoader modules? // TODO: Should the client cert+key config use caddytls.CertificateLoader modules?
ClientCertificateFile string `json:"client_certificate_file,omitempty"` ClientCertificateFile string `json:"client_certificate_file,omitempty"`
ClientCertificateKeyFile string `json:"client_certificate_key_file,omitempty"` ClientCertificateKeyFile string `json:"client_certificate_key_file,omitempty"`
@ -203,7 +209,7 @@ func (t TLSConfig) MakeTLSClientConfig() (*tls.Config, error) {
} }
// trusted root CAs // trusted root CAs
if len(t.RootCAPool) > 0 { if len(t.RootCAPool) > 0 || len(t.RootCAPemFiles) > 0 {
rootPool := x509.NewCertPool() rootPool := x509.NewCertPool()
for _, encodedCACert := range t.RootCAPool { for _, encodedCACert := range t.RootCAPool {
caCert, err := decodeBase64DERCert(encodedCACert) caCert, err := decodeBase64DERCert(encodedCACert)
@ -212,6 +218,14 @@ func (t TLSConfig) MakeTLSClientConfig() (*tls.Config, error) {
} }
rootPool.AddCert(caCert) rootPool.AddCert(caCert)
} }
for _, pemFile := range t.RootCAPemFiles {
pemData, err := ioutil.ReadFile(pemFile)
if err != nil {
return nil, fmt.Errorf("failed reading ca cert: %v", err)
}
rootPool.AppendCertsFromPEM(pemData)
}
cfg.RootCAs = rootPool cfg.RootCAs = rootPool
} }