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 ...@@ -28,6 +28,7 @@ package proxy
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"crypto/x509"
"fmt" "fmt"
"io" "io"
"net" "net"
...@@ -310,6 +311,25 @@ func (rp *ReverseProxy) UseInsecureTransport() { ...@@ -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. // ServeHTTP serves the proxied request to the upstream by performing a roundtrip.
// It is designed to handle websocket connection upgrades as well. // It is designed to handle websocket connection upgrades as well.
func (rp *ReverseProxy) ServeHTTP(rw http.ResponseWriter, outreq *http.Request, respUpdateFn respUpdateFn) error { func (rp *ReverseProxy) ServeHTTP(rw http.ResponseWriter, outreq *http.Request, respUpdateFn respUpdateFn) error {
......
...@@ -17,6 +17,7 @@ package proxy ...@@ -17,6 +17,7 @@ package proxy
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/x509"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
...@@ -73,6 +74,7 @@ type staticUpstream struct { ...@@ -73,6 +74,7 @@ type staticUpstream struct {
resolver srvResolver resolver srvResolver
upstreamHeaderReplacements headerReplacements upstreamHeaderReplacements headerReplacements
downstreamHeaderReplacements headerReplacements downstreamHeaderReplacements headerReplacements
CaCertPool *x509.CertPool
} }
type srvResolver interface { type srvResolver interface {
...@@ -259,6 +261,9 @@ func (u *staticUpstream) NewHost(host string) (*UpstreamHost, error) { ...@@ -259,6 +261,9 @@ func (u *staticUpstream) NewHost(host string) (*UpstreamHost, error) {
if u.insecureSkipVerify { if u.insecureSkipVerify {
uh.ReverseProxy.UseInsecureTransport() uh.ReverseProxy.UseInsecureTransport()
} }
if u.CaCertPool != nil {
uh.ReverseProxy.UseOwnCACertificates(u.CaCertPool)
}
return uh, nil return uh, nil
} }
...@@ -515,6 +520,32 @@ func parseBlock(c *caddyfile.Dispenser, u *staticUpstream, hasSrv bool) error { ...@@ -515,6 +520,32 @@ func parseBlock(c *caddyfile.Dispenser, u *staticUpstream, hasSrv bool) error {
u.IgnoredSubPaths = ignoredPaths u.IgnoredSubPaths = ignoredPaths
case "insecure_skip_verify": case "insecure_skip_verify":
u.insecureSkipVerify = true 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": case "keepalive":
if !c.NextArg() { if !c.NextArg() {
return c.ArgErr() 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