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.
CodePudding user response:
For TLS (ie https, which is http with TLS) you must connect to the correct server port. It is usually port 43 or port 8443. It is never the same as the port used for http. So this means that to start, the server must provide a port for TLS, although most do.
The only code you've shared has nothing to do with the connection to the server.
Since you've not shared any of the code making the request to the server, it is not possible to show where it is wrong.
CodePudding user response:
I am unable to fully reproduce your setup right now, but in principle, you are supposed to alter the request inside ReverseProxy.Director
function:
Director must be a function which modifies the request into a new request to be sent using Transport.
So in short:
proxy.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{certificate},
RootCAs: certPool,
InsecureSkipVerify: true,
}
}
proxy.Director = func(req *http.Request) {
req.Host = remote.Host
req.URL.Scheme = remote.Scheme
req.URL.Host = remote.Host
req.URL.Path = remote.Path
}
proxy.ServeHTTP(c.Writer, c.Request)
Also you might need both the certificates and the rootCAs in the TLS config. The certificates are those you send to the server, and the rootCA is for verifying those presented by the server.