Question

What is wrong with this code?

http://godoc.org/github.com/lib/pq

* dbname - The name of the database to connect to
* user - The user to sign in as
* password - The user's password
* host - The host to connect to. Values that start with / are for unix domain sockets. (default is localhost)
* port - The port to bind to. (default is 5432)
* sslmode - Whether or not to use SSL (default is require, this is not the default for libpq)
* fallback_application_name - An application_name to fall back to if one isn't provided.
* connect_timeout - Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely.

So I just type the following and expected to see the successful connection with the PostgreSQL connection but seems to not work. Is there anything wrong with the syntax, since the syntax for sql.Open is different than the one that I used for MySQL.

"dbname=%s user=%s password=%s host=%s port=%s sslmode=%s connect_timeout=%s"

And the error message from this code is x509: certificate signed by unknown authority

package main

import (
  "database/sql"
  "fmt"
  "log"
  "os"

  _ "github.com/lib/pq"
)

func main() {
  db := Get()
  defer db.Close()
  err := db.Ping()
  if err == nil {
    log.Fatalln("db.Ping is successful!")
  } else {
    log.Fatalln(err)
  }
}

func Get() *sql.DB {
  const (
    AWS_DB         = "mydb"
    AWS_USER       = "rootuser"
    AWS_PASS       = "1234"
    AWS_HOST       = "redshift.amazonaws.com"
    AWS_PORT       = "5439"
    AWS_SSL        = "verify-full"
    AWS_TIME       = "2"
    AWS_ACCESS_KEY = "abcd"
    AWS_SECRET_KEY = "efgh"
  )
  db, err := sql.Open("postgres",
    fmt.Sprintf("dbname=%s user=%s password=%s host=%s port=%s sslmode=%s connect_timeout=%s",
      AWS_DB,
      AWS_USER,
      AWS_PASS,
      AWS_HOST,
      AWS_PORT,
      AWS_SSL,
      AWS_TIME,
    ))
  if err != nil {
    log.Fatalln("Error:")
    log.Fatalln(err)
    os.Exit(1)
  }
  return db
}
Was it helpful?

Solution

As the error message tells your host is not trusting the certificate authority (CA) which signed the certificate of your database server.

If you can afford to enable InsecureSkipVerify then set sslmode=require. This will prevent the client to verify the server's certificate chain and host name (but SSL will still be used).

If this is not an option you need to add the CA to your hosts trusted CAs. This depends on your OS. On Linux you have good chances when you add it to /etc/ssl/cert.pem.

Obviously the PostgreSQL driver does not allow to specify a custom tls.Config which would make things more flexible. In the source code you can see that it always uses tls.Config{}. It does not provide an option to set custom RootCAs.

OTHER TIPS

You need to pass sslrootcert parameter. Your code will become

db, err := sql.Open("postgres",
fmt.Sprintf("dbname=%s user=%s password=%s host=%s port=%s sslmode=%s sslrootcert=%s connect_timeout=%s",
  AWS_DB,
  AWS_USER,
  AWS_PASS,
  AWS_HOST,
  AWS_PORT,
  AWS_SSL,
  AWS_SSL_CERT_PATH,
  AWS_TIME,
))

where AWS_SSL_CERT_PATH="/path/to/the/certificate"

You can find more information and the link to download the certificate here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top