Question

Can't connect to Managed Database ('SELF_SIGNED_CERT_IN_CHAIN' error)

Posted November 20, 2019 10k views
PostgreSQL

Hi!

I just created a new Managed Database with PostgreSQL at DigitalOcean.

Now, i’m trying to connect with node.js and i’m getting the following error:

(node:15100) UnhandledPromiseRejectionWarning: Error: self signed certificate in certificate chain
    at TLSSocket.onConnectSecure (_tls_wrap.js:1321:34)
    at TLSSocket.emit (events.js:210:5)
    at TLSSocket._finishInit (_tls_wrap.js:794:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:608:12)
(node:15100) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:15100) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Error: Connection terminated unexpectedly
    at Connection.<anonymous> (C:\Users\luizh\Documents\abacate\node_modules\pg\lib\client.js:252:9)
    at Object.onceWrapper (events.js:299:28)
    at Connection.emit (events.js:210:5)
    at Socket.<anonymous> (C:\Users\luizh\Documents\abacate\node_modules\pg\lib\connection.js:76:10)
    at Socket.emit (events.js:215:7)
    at TCP.<anonymous> (net.js:659:12) undefined
Error: self signed certificate in certificate chain
    at TLSSocket.onConnectSecure (_tls_wrap.js:1321:34)
    at TLSSocket.emit (events.js:210:5)
    at TLSSocket._finishInit (_tls_wrap.js:794:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:608:12) {
  code: 'SELF_SIGNED_CERT_IN_CHAIN'
} undefined

This is my code:

const connectionString = 'postgresql://doadmin:xxxx@db-cookify-do-user-6685692-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require&ssl=true'
const pool = new Pool({
  connectionString: connectionString,
  ssl: true,
})

If i run my script with NODE_TLS_REJECT_UNAUTHORIZED=0, it works well.

Anybody can help me with this?

2 comments
  • Hi,

    Just want to add, I’ve been having the exact same issue all day today but have yet to find a solution....

  • Make sure the connection string does not have sslmode=require nor ssl=true

    Then try:

    const pool = new Pool({
      connectionString: process.env.DATABASE_URL,
      ssl: {
        rejectUnauthorized: false,
      },
    });
    

    This is what worked for me.

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

×
Submit an Answer
4 answers

Seems to be an issue with the pg package. Rolling back to version 7.12.1 solves the issue for me.

You need to pass { rejectUnauthorized: false } as the ssl option.

I used the following script, but with sensitive values removed:

const { Sequelize } = require('sequelize');

const sequelize = new Sequelize({
  dialect: 'postgres',
  host: '',
  port: 0,
  username: '',
  password: '',
  database: '',
  dialectOptions: {
    ssl: { rejectUnauthorized: false },
  },
});

sequelize.authenticate().then(
  () => console.log('success'),
  (error) => console.error(error),
);

The simplest way to verify this is to run:

kubectl run -ti test-pg-connection --image node:12-slim -- bash

Then inside the container type:

mkdir app
cd app
yarn init
yarn add sequelize pg pg-hstore
node

Modify the script and paste it into the node console.

@luizhrqas

Thanks for posting a question here, I tried to reproduce your error but I failed to do so, I just created a new fresh PostgreSQL cluster and used this code to connect to it without any problems:

const connectionString = 'postgresql://doadmin:xxxx@db-postgresql-nyc1-57414-do-user-1548131-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require'

const { Pool } = require('pg')
const pool = new Pool({
  connectionString: connectionString,
  ssl: true
})

pool.connect()

If you use my code do you still get the same error?

Thanks a lot

I don’t think rejectUnauthorized: false is the right option. You typically want to reject unauthorized identities. Not verifying the identity of the server has the potential to leave you open to a man-in-the-middle attack.

Digital Ocean provides the CA certificate in the database connection details. Download the CA certificate and ensure you are connecting to the database using that certificate.

If you’re using knex, your knexfile would resemble the following:

const fs = require("fs");

module.exports = {

    development: {
        client: "pg",
        connection: {
            database: "<database name>",
            user: "<username>",
            password: "<password>",
            host: "<host>",
            port: "<port>",
            ssl: {
                // Ensure we *are* rejecting unauthorized identities 
                rejectUnauthorized: true, 

                // Path to the downloaded digital ocean cert
                ca: fs.readFileSync("ca-certificate.crt").toString()
            },
        },

        ... other knex settings such as pool
    }

}