PostgreSQL error when trying to connect from node application - node.js

FATAL: no PostgreSQL user name specified in startup packet
Logs from my postgreSQL instance in my kubernetes cluster when trying to connect to it by doing the following:
const { POSTGRES_DATABASE, POSTGRES_USERNAME, POSTGRES_PASSWORD } = require('../config/config');
const Sequelize = require('sequelize');
const conn = new Sequelize(POSTGRES_DATABASE, {
username: POSTGRES_USERNAME,
password: POSTGRES_PASSWORD
});
config/config.js
const config = {
POSTGRES_DATABASE: 'postgres://postgres/postgresdb',
POSTGRES_USERNAME: 'postgresadmin',
POSTGRES_PASSWORD: 'admin123',
SERVER_PORT: '5000'
}
module.exports = config;
I am using SequelizeJS in nodeJS.
http://docs.sequelizejs.com/
It seems like the requests are connecting alright due to seeing the attempts in the postgreSQL logs. However something goes wrong and I wonder if it's wrong with permissions in postgres or the node service.
Appreciate some help or ideas

According to the Sequelize documentation that you linked, the args to creating a new connection are db, username, password. Your code did db, and then an object with username and password keys. This object is not correct and caused it to not find the username or password. Try this instead:
const { POSTGRES_DATABASE, POSTGRES_USERNAME, POSTGRES_PASSWORD } = require('../config/config');
const Sequelize = require('sequelize');
const conn = new Sequelize(POSTGRES_DATABASE, POSTGRES_USERNAME, POSTGRES_PASSWORD);
Sequelize does allow for an optional options object as the last argument, but the username and password are not expected to be in there.
This page of the documentation feels confusing to me.
http://docs.sequelizejs.com/manual/installation/usage.html
I believe what it says is that you either need to define everything in the object, or do the database, username, and password as separate arguments, but I don’t see it supporting database in the arguments and username / password in the object.
It seems like this should work as well:
const conn = new Sequelize({
database: POSTGRES_DATABASE,
username: POSTGRES_USERNAME,
password: POSTGRES_PASSWORD
});

Related

Can Sequelize be used to connect to a new database?

In designing a simple node.js project, I tried using Sequelize to connect to a mysql server using the following configuration parameters:
{ dbname: users
username: jimmy
password: users
params:
host: localhost
port: 3306
dialect: mysql }
though the 'users' database didn't exist yet.
I got a server error:
InternalServerError: {"name":"SequelizeConnectionError","parent":{"code":"ER_BAD_DB_ERROR","errno":1049,"sqlState":"42000","sqlMessage":"Unknown database 'users'"},"original":{"code":"ER_BAD_DB_ERROR","errno":1049,"sqlState":"42000","sqlMessage":"Unknown database 'users'"}}
But the Sequelize docs: Manual | Sequelize indicate that Sequelize can connect to a new database. Please, how can Sequelize be used to connect to a
new(non-existing) database?
You should read the documentation again carefully (because the wording is indeed confusing!).
New databases versus existing databases
If you are starting a project from scratch, and your database does not exist yet, Sequelize
can be used since the beginning in order to automate the creation of
every table in your database.
Also, if you want to use Sequelize to connect to a database that is
already filled with tables and data, that works as well! Sequelize has
got you covered in both cases.
It will connect only to an existing DB, it can help you by creating the tables if they do not exist yet but the DB has to be there in order for sequelize to connect with it.
Following this question, I wrote this PR to update the documentation to be less confusing. Hope it help!
Found a similar problem on SO, and an answer by osifo:
//create the sequelize instance omitting the database-name arg
const sequelize = new Sequelize("", "<db_user>", "<db_password>", {
dialect: "<dialect>"
});
return sequelize.query("CREATE DATABASE `<database_name>`;").then(data
=> {
// code to run after successful creation.
});
So, I was able to implement it in my own code:
var SQUser;
var sequlz;
async function connectDB() {
sequlz =
new Sequelize("", "jimmy", "users", {host: "localhost", port: 3306, dialect: "mysql"});
await sequlz.query("CREATE DATABASE users;");
await sequlz.query("Use users;");
SQUser = sequlz.define('Table',
{
// define table schema
});
return SQUser.sync();
};
//use sequelize to populate the table
async function create() {
const SQUser = await connectDB();
return SQUser.create(
//values
);
}

AWS Lambda - Error: unable to get local issuer certificate

I am trying to connect to an amazon postgreSQL RDS using a NodeJS lambda.
The lambda is in the same VPC as the RDS instance and as far as I can tell the security groups are set up to give the lambda access to the RDS. The lambda is called through API gateway and I'm using knex js as a query builder. When the lambda attempts to connect to the database it throws an "unable to get local issuer certificate" error, but the connection parameters are what I expect them to be.
I know this connection is possible as I've already implemented it in a different environment, without receiving the certificate issue. I've compared the two environments but cannot find any immediate differences.
The connection code looks like this:
import AWS from 'aws-sdk';
import { types } from 'pg';
import { Moment } from 'moment';
import knex from 'knex';
const TIMESTAMP_OID = 1114;
// Example value string: "2018-10-04 12:30:21.199"
types.setTypeParser(TIMESTAMP_OID, (value) => value && new Date(`${value}+00`));
export default class Database {
/**
* Gets the connection information through AWS Secrets Manager
*/
static getConnection = async () => {
const client = new AWS.SecretsManager({
region: '<region>',
});
if (process.env.databaseSecret == null) {
throw 'Database secret not defined';
}
const response = await client
.getSecretValue({ SecretId: process.env.databaseSecret })
.promise();
if (response.SecretString == undefined) {
throw 'Cannot find secret string';
}
return JSON.parse(response.SecretString);
};
static knexConnection = knex({
client: 'postgres',
connection: async () => {
const secret = await Database.getConnection();
return {
host: secret.host,
port: secret.port,
user: secret.username,
password: secret.password,
database: secret.dbname,
ssl: true,
};
},
});
}
Any guidance on how to solve this issue or even where to start looking would be greatly appreciated.
First of all, it is not a good idea to bypass ssl verification, and doing so can make you vulnerable to various exploits and skips a critical step in the TLS handshake.
What you can do is programmatically download the ca certificate chain bundle from Amazon and place it in the root directory of the lambda along side the handler.
wget https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem -P path/to/handler
Note: you can do this in your buildspec.yaml or in your script that packages the zip file that gets uploaded to aws
Then set the ssl configuration option to the contents of the pem file in your code postgres client configuration, like this:
let pgClient = new postgres.Client({
user: 'postgres',
host: 'rds-cluster.cluster-abc.us-west-2.rds.amazonaws.com',
database: 'mydatabase',
password: 'postgres',
port: 5432,
ssl: {
ca: fs.readFileSync(path.resolve('rds-combined-ca-bundle.pem'), "utf-8")
}
})
I know this is old, but just ran into this today. Running with node 10 and an older version of the pg library worked just fine. Updating to node 16 with pg version 8.x caused this error (simplified):
UNABLE_TO_GET_ISSUER_CERT_LOCALLY
In the past, you could indeed just set the ssl parameter to true or 'true' and it would work with the default AWS RDS certificate. Now, it seems we need to at least tell node/pg to ignore the cert verification (since it's self generated).
Using ssl: 'no-verify' works, enabling ssl and telling pg to ignore the verification of the cert chain.
source
UPDATE
For clarity, here's what the connection string would look like. With Knex, the same client info is passed to pg, so it should look similar to a pg client connection.
static knexConnection = knex({
client: 'postgres',
connection: async () => {
const secret = await Database.getConnection();
return {
host: secret.host,
port: secret.port,
user: secret.username,
password: secret.password,
database: secret.dbname,
ssl: 'no-verify',
};
}

How to check that mysql connection is valid

I'm using node, with 'mysql2' module, how can I check that the config settings are correct and connecting to the database correctly?
These are my connection settings, however I want to check that the database connection is valid before any queries are done, such as allowing the user to login.
const mysql = require('mysql2');
const conn = mysql.createPool({
host: 'hostname',
port: port,
database: 'db',
user: 'root',
password: 'password',
dateStrings: 'date'
});
const pool = conn.promise();
module.exports = pool;
I added this code (before the module.exports line) to throw an error, but is there a better way of doing this? The error code -3008 relates to the 'ENOTFOUND' code, which is what I receive when the host name was incorrect and the connection failed.
pool.execute('SELECT * FROM table LIMIT 1')
.catch(err => {
if (err.errno === -3008) {
throw new Error('Can\'t connect to database please check connection settings.');
}
});
are you able to connect via command line in your mysql?
mysql -h localhost -u myname -ppassword mydb
Also, to test the connection before execute the query, I suggest you to use .getConnection

JS postgres - wrong username connection

So im trying to connect my local postgres DB to my node.js server.
But im facing the ennoying issue of wrong username.
error: password authentication failed for user "Yoav Genish"
error log:
name: 'error',
length: 169,
severity: 'FATAL',
code: '28P01',
The Yoav Genish is my win10 user name and postgres just default it as the superadmin.
I have a user with premission for the DB called me and i specified it in a .env file.
Here's the .env file:
HOST='localhost'
USER = 'me'
DATABASE= 'api'
PASSWORD= 'password'
PORT=5432 '
and here's the code:
require('dotenv').config();
const Pool= require('pg').Pool;
const ENVDATA = {
HOST: process.env.HOST,
USER: process.env.USER,
DATABSE: process.env.DATABASE,
PORT: process.env.PORT,
PASSWORD: process.env.PASSWORD
}
var pool = new Pool(ENVDATA);
Also i verified the the ENVDATA is indeed the data in the .env file.
again, the issue is that i want to log into the local DB with the me username, but i keep getting the above error.
thanks in advance!
It appears to be a syntax problem. One should use Lower Case properties when passing data to the Pool meaning
const ENVDATA = {
host : process.env.HOST,
user: process.env.USER,
.
.
.
But i found an even "clener" solution and it's using the URI String instead:
const PGURI = `postgres://${process.env.USER}:${process.env.PASSWORD}#$
{process.env.HOST}:${process.env.PORT}/${process.env.DATABASE}`;
var pool = new Pool({
connectionString: PGURI
});

Is it possible to "CREATE DATABASE ..." with pg-promise and PostgreSQL (9.5)?

Question is:
1) Can pg-promise be used to create a new database (schemas, et. al.)?
Using node package 'pg-promise' I can't seem to figure out if it's possible to create a new database. I can connect to an existing database and have no issue there. However, when I run without a database name I get an error:
This is what I am trying:
host = host || '127.0.0.1'
port = port || '5432'
const pgp = require('pg-promise')(pgpInitOptions)
// database connection details
const pgConnectionOptions = {
host: host,
port: port,
user: user,
password: pass
}
// database instance
const localDB = pgp(pgConnectionOptions)
let escapedDbName = dbName.replace(/\"/g, '""');
let sql = 'CREATE DATABASE "' + escapedDbName + '"';
localDB
.any(sql)
.then((results) => {
console.log('creation of database successful', results)
})
.catch((error) => {
console.error('creation of database failed', error)
})
Then, I get this error:
creation of database failed
Error: database "jeff" does not exist
"jeff" is my ubuntu login name.
First, you need to connect to an existing database, using an admin account which has the right to create new databases.
Then you can create new databases via a regular query...
const pgp = require('pg-promise')(/* initialization options */);
const db = pgp({
database: 'any-existing-db',
port: 5432,
user: 'postgres', // any admin user
password: 'admin-password'
});
await db.none('CREATE DATABASE $1:name', ['my_database']);
I am running such code locally, and it works fine.

Resources