gosslreverse-proxyclient-certificateshttprouter

Using TLS/SSL Client Authentication for specific hosts


How can I use TLS/SSL Client Authentication for specific Hosts when using a reverse proxy like httprouter by julienschmidt?

I could set a Client Certificate in a global matter with http.DefaultTransport.

transport := &http.Transport{
    TLSClientConfig: &tls.Config{
        Certificates: []tls.Certificate{cert},
    },
}

http.DefaultTransport = transport

But want to use Client Certificate only for specific hosts, like:

  1. cert1 for host1
  2. cert2 for host2
  3. everything else with no Client Certificate

Update

I expected that the callback GetConfigForClientHandler or GetCertificateHandler would be called. At this point I could react on the info.ServerName. But only GetClientCertificate get called with no information about the target info.ServerName.

func main() {
    transport := &http.Transport{
        TLSClientConfig: &tls.Config{
            GetConfigForClient:   GetConfigForClientHandler,
            GetClientCertificate: GetClientCertificateHandler,
            GetCertificate:       GetCertificateHandler,
        },
    }

    http.DefaultTransport = transport

    // Host which enforce client certificate authentication
    resp, err := http.Get("https://example.com")
    if err != nil {
        fmt.Println("Error", err)
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

func GetClientCertificateHandler(info *tls.CertificateRequestInfo) (*tls.Certificate, error) {
    fmt.Println("GetClientCertificateHandler")
    panic("GetClientCertificateHandler")
}

func GetConfigForClientHandler(info *tls.ClientHelloInfo) (*tls.Config, error) {
    fmt.Println("GetConfigForClientHandler for:", info.ServerName)
    panic("GetConfigForClientHandler")
}

func GetCertificateHandler(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
    fmt.Println("GetCertificateHandler for:", info.ServerName)
    panic("GetCertificateHandler")
}

Solution

    1. Create a TLS config which is shared for all hosts. Probably you don't need to set much there. But you want to set a Config.GetConfigForClient handler.
    2. In that handler, you check the ClientHelloInfo.ServerName. That is the requested host. You then modify the TLS config to require client auth there (Config.ClientAuth).
    3. Wrap your net.Listener with tls.NewListener
    4. Use your TLS net.Listener in http.Serve (here is where you could then use httprouter)