Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS using Cloud SQL cannot verify server certificate. #908

Closed
roudy16 opened this issue Dec 12, 2018 · 4 comments
Closed

TLS using Cloud SQL cannot verify server certificate. #908

roudy16 opened this issue Dec 12, 2018 · 4 comments

Comments

@roudy16
Copy link

roudy16 commented Dec 12, 2018

Issue description

I'm trying to connect to a Cloud SQL instance using a TLS connection. I've created certificates in the Cloud SQL console and I'm setting them up using code that is similar to what's below. However the server certificate validation does not seem to work. The error is seen when I try to create a prepared statement using sql.DB.Prepare(...). The only way I can use TLS is if I add InsecureSkipVerify: true to my TLS config, the connection works fine if I do that. I've been able to use the same certificate/key files to connect with JDBC and mysql-client.

Example code

rootCertPool := x509.NewCertPool()
pem, err := ioutil.ReadFile("/path/server-ca.pem")
if err != nil {
    log.Fatal(err)
}
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
    log.Fatal("Failed to append PEM.")
}
clientCert := make([]tls.Certificate, 0, 1)
certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem")
if err != nil {
    log.Fatal(err)
}
clientCert = append(clientCert, certs)
mysql.RegisterTLSConfig("custom", &tls.Config{
    RootCAs: rootCertPool,
    Certificates: clientCert,
})
db, err := sql.Open("mysql", "user@tcp(<cloud sql instance ip>:3306)/test?tls=custom")

Error log

x509: cannot validate certificate for <cloud sql instance ip> because it doesn't contain any IP SANs

Configuration

Driver version (or git SHA): Version 1.4 (2018-06-03)

Go version: go1.11 darwin/amd64

MySQL version: 5.7.14-google-log

Server OS: Whatever Cloud SQL is currently using.

@roudy16
Copy link
Author

roudy16 commented Dec 12, 2018

I also tried ServerName: "<gcp-project-id>:<sql-instance-name>" in my TLS config as I saw that was what the server certificate contained as the common name for the Subject when inspecting the TLS handshake. The Go TLS library is saying that is not a valid hostname. Is Cloud SQL using deprecated TLS certificates? Is the Go TLS library validating hostnames incorrectly?

@roudy16
Copy link
Author

roudy16 commented Dec 12, 2018

':' is not a vlid character in hostnames apparently. I see in the x509/verify.go code there is allowance for another non-standard character '_' in the follow code snippet from there:

if c == '_' {
	// _ is not a valid character in hostnames, but it's commonly
	// found in deployments outside the WebPKI.
	continue
}

So I guess I'll submit a PR there for Cloud SQL deployments...

if c == ':' {
	// : is not a valid character in hostnames, but it's commonly
	// found in Google Cloud SQL deployments.
	continue
}

@roudy16
Copy link
Author

roudy16 commented Dec 12, 2018

And that exact change is already in master there.

@roudy16 roudy16 closed this as completed Dec 12, 2018
@roudy16
Copy link
Author

roudy16 commented Dec 12, 2018

The correct way to connect to a Cloud SQL instance using TLS is to follow these steps:

  1. Update your Go so that you have the change that allows validation of Cloud SQL hostnames that are in the server certificate.

  2. Create client certificates using the Cloud SQL console.

  3. Setup your connection like so:

rootCertPool := x509.NewCertPool()
pem, err := ioutil.ReadFile("/path/server-ca.pem")
if err != nil {
    log.Fatal(err)
}
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
    log.Fatal("Failed to append PEM.")
}
clientCert := make([]tls.Certificate, 0, 1)
certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem")
if err != nil {
    log.Fatal(err)
}
clientCert = append(clientCert, certs)
mysql.RegisterTLSConfig("custom", &tls.Config{
    RootCAs: rootCertPool,
    Certificates: clientCert,
    ServerName: "<gcp-project-id>:<cloud-sql-instance>",
})
db, err := sql.Open("mysql",
        "<user>:<password>@tcp(<cloud sql instance ip>:3306)/<database>?tls=custom")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant