Consul Code Snippets

If verify_server_hostname is set, then outgoing connections perform hostname verification.

All servers must have a certificate valid for server.<datacenter>.<domain> or the client will reject the handshake.

This is accomlished in the tlsutil package in config.go L706-L727.

// Wrap a net.Conn into a client tls connection, performing any
// additional verification as needed.
//
// As of go 1.3, crypto/tls only supports either doing no certificate
// verification, or doing full verification including of the peer's
// DNS name. For consul, we want to validate that the certificate is
// signed by a known CA, but because consul doesn't use DNS names for
// node names, we don't verify the certificate DNS names. Since go 1.3
// no longer supports this mode of operation, we have to do it
// manually.
func (c *Configurator) wrapTLSClient(dc string, conn net.Conn) (net.Conn, error) {
config := c.OutgoingRPCConfig()
verifyServerHostname := c.VerifyServerHostname()
verifyOutgoing := c.verifyOutgoing()
domain := c.domain()
if verifyServerHostname {
// Strip the trailing '.' from the domain if any
domain = strings.TrimSuffix(domain, ".")
config.ServerName = "server." + dc + "." + domain
}
tlsConn := tls.Client(conn, config)

The if verifyServerHostname {} block is the part that forces the TLS configuration to have a specific server name, regardless of what else might have been provided. The tls.Client then uses a Verify function in the Standard Library to validate the TLS connection.