I've been tasked with creating a reverse proxy that is required to make a TLS connection to the proxied service. The certificates I have are unique per request, and in-memory.
I haven't had much luck getting it right, and I've tried a number of things. Here's where I'm at now, hopefully someone can help:
func proxy(c *gin.Context) {
/* snip: magic here to get the x509 cert strings and remoteUrl */
proxy := httputil.NewSingleHostReverseProxy(remoteUrl)
cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: []byte(signedCertString)})
key:= pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: []byte(privateKeyString)})
certificate, err := tls.X509KeyPair(cert, key)
if err != nil {
c.JSON(400, gin.H{"message": "Invalid certificate"})
return
}
proxy.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{certificate},
InsecureSkipVerify: true,
}
}
c.Request.Host = remote.Host
c.Request.URL.Scheme = remote.Scheme
c.Request.URL.Host = remote.Host
c.Request.URL.Path = remote.Path
proxy.ServeHTTP(c.Writer, c.Request)
}
I've also tried setting RootCAs
(figuring maybe I'm just twisted about now TLS needs to work in this scenario):
func proxy(c *gin.Context) {
/* snip: magic here to get the x509 cert strings and remoteUrl */
proxy := httputil.NewSingleHostReverseProxy(remoteUrl)
cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: []byte(signedCertString)})
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(cert)
proxy.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
InsecureSkipVerify: true,
}
}
c.Request.Host = remote.Host
c.Request.URL.Scheme = remote.Scheme
c.Request.URL.Host = remote.Host
c.Request.URL.Path = remote.Path
proxy.ServeHTTP(c.Writer, c.Request)
}
In any case, the server I'm targeting doesn't seem to pick up that the proxied request was TLS, and I'm not really sure where to proceed with this.
I ended up switching to use ReverseProxy
directly. But the big problem is I was using RootCAs
and not ClientCAs
. Here is what I ended up with:
clientCAs := x509.NewCertPool()
clientCAs.AppendCertsFromPEM(signedCert)
certificate, err := tls.X509KeyPair(signedCert, privateKey)
proxy := &httputil.ReverseProxy({
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{certificate},
ClientCAs: clientCAs
},
Director: func (req *http.Request) {
// Alter request here
}
},
})
proxy.ServeHTTP(w, r)
After this, everything is working swimmingly. Thanks, all!