Commit dd393ce3 authored by Łukasz Nowak's avatar Łukasz Nowak Committed by Łukasz Nowak

Implement own CA certificates of backends

/reviewed-on !1
parent 527de186
......@@ -28,6 +28,7 @@ package proxy
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"net"
......@@ -310,6 +311,25 @@ func (rp *ReverseProxy) UseInsecureTransport() {
}
}
// UseOwnCertificate is used to facilitate HTTPS proxying
// with locally provided certificate.
func (rp *ReverseProxy) UseOwnCACertificates(CaCertPool *x509.CertPool) {
if transport, ok := rp.Transport.(*http.Transport); ok {
if transport.TLSClientConfig == nil {
transport.TLSClientConfig = &tls.Config{}
}
transport.TLSClientConfig.RootCAs = CaCertPool
// No http2.ConfigureTransport() here.
// For now this is only added in places where
// an http.Transport is actually created.
} else if transport, ok := rp.Transport.(*h2quic.RoundTripper); ok {
if transport.TLSClientConfig == nil {
transport.TLSClientConfig = &tls.Config{}
}
transport.TLSClientConfig.RootCAs = CaCertPool
}
}
// ServeHTTP serves the proxied request to the upstream by performing a roundtrip.
// It is designed to handle websocket connection upgrades as well.
func (rp *ReverseProxy) ServeHTTP(rw http.ResponseWriter, outreq *http.Request, respUpdateFn respUpdateFn) error {
......
......@@ -17,6 +17,7 @@ package proxy
import (
"bytes"
"context"
"crypto/x509"
"fmt"
"io"
"io/ioutil"
......@@ -73,6 +74,7 @@ type staticUpstream struct {
resolver srvResolver
upstreamHeaderReplacements headerReplacements
downstreamHeaderReplacements headerReplacements
CaCertPool *x509.CertPool
}
type srvResolver interface {
......@@ -259,6 +261,9 @@ func (u *staticUpstream) NewHost(host string) (*UpstreamHost, error) {
if u.insecureSkipVerify {
uh.ReverseProxy.UseInsecureTransport()
}
if u.CaCertPool != nil {
uh.ReverseProxy.UseOwnCACertificates(u.CaCertPool)
}
return uh, nil
}
......@@ -515,6 +520,32 @@ func parseBlock(c *caddyfile.Dispenser, u *staticUpstream, hasSrv bool) error {
u.IgnoredSubPaths = ignoredPaths
case "insecure_skip_verify":
u.insecureSkipVerify = true
case "ca_certificates":
caCertificates := c.RemainingArgs()
if len(caCertificates) == 0 {
return c.ArgErr()
}
pool := x509.NewCertPool()
caCertificatesAdded := make(map[string]struct{})
for _, caFile := range caCertificates {
// don't add cert to pool more than once
if _, ok := caCertificatesAdded[caFile]; ok {
continue
}
caCertificatesAdded[caFile] = struct{}{}
// Any client with a certificate from this CA will be allowed to connect
caCrt, err := ioutil.ReadFile(caFile)
if err != nil {
return err
}
if !pool.AppendCertsFromPEM(caCrt) {
return fmt.Errorf("error loading CA certificate '%s': no certificates were successfully parsed", caFile)
}
}
u.CaCertPool = pool
case "keepalive":
if !c.NextArg() {
return c.ArgErr()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment