Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSH tunnel to Sequelize PostgreSQL database

I am trying to access one of our remote databases (AWS RDS) that is hidden behind a bastion EC2 instance. I can access the database easily through my SQL client, but cannot access it through the CLI tool I am building (using Sequelize and tunnel-ssh). I was following this GitHub Gist but it uses the same values everywhere and is quite confusing unfortunately.

I will admit to having a poor understanding of SSH tunnelling in general, which may be apparent in the examples below. Is there something wrong with my configuration?


Database Config

Host:     wdXXXXXXXXXXXX.XXXXXXXXX.XX-XXXXX-X.rds.amazonaws.com
Port:     5432
User:     [DB_USER]
Password: [DB_PASSWORD]
Database: [DB_NAME]

Bastion Config

Server:   35.183.XX.XXX
Port:     22
Password:
SSH Key:  ~/.ssh/id_rsa.aws
const config = {
  // I don't need to specify any local values, do I?
  // localHost: "127.0.0.1",
  // localPort: 5432,

  // This should be bastion config, correct?
  username: "ec2-user",
  host: 35.183.XX.XXX,
  port: 22,
  privateKey: require("fsf").readFileSync("/path/to/ssh/key"),

  // This should be destination (database) config, correct?
  dstHost: wdXXXXXXXXXXXX.XXXXXXXXX.XX-XXXXX-X.rds.amazonaws.com,
  dstPort: 5432
};

// NOTE: If I don't have an "await" here, nothing seems to run inside the function itself (no consoles, etc)
const server = await tunnel(config, async (error, server) => {
  if (error) return console.error(error);

  const db = new Sequelize(DB_NAME, DB_USER, DB_PASSWORD, {
    dialect: "postgres",
    // NOTE: If this is already the destination in the SSH tunnel, should I use it again vs localhost?
    host: "wdXXXXXXXXXXXX.XXXXXXXXX.XX-XXXXX-X.rds.amazonaws.com",
    port: 5432
  });

  db.authenticate().then(async () => {
    const orgs = await db.organization.findAll();

    console.log("Successful query", orgs);
  }).catch(err => {
    console.error("DB auth error": err);
  });
});

Is there something wrong with my configuration above? Is my understanding of tunnels flawed by the values I've used in the tunnel config?

Also, why doesn't the tunnel callback appear to be called unless I await the function (which doesn't seem to be a Promise at all)?

P.S. There's also this Sequelize GitHub issue that mentions connecting with Sequelize via an SSH tunnel, but gives no examples.

like image 576
Kendall Avatar asked Aug 10 '26 20:08

Kendall


1 Answers

I eventually got this figured out and was able to resolve the problem (12 hours after it started)... The database and bastion configurations were technically correct, but I was passing some values incorrectly (due to a flawed understanding of SSH tunneling).

Database Config

Host:     wdXXXXXXXXXXXX.XXXXXXXXX.XX-XXXXX-X.rds.amazonaws.com
Port:     5432
User:     [DB_USER]
Password: [DB_PASSWORD]
Database: [DB_NAME]

Bastion Config

Server:   35.183.XX.XXX
Port:     22
Password:
SSH Key:  ~/.ssh/id_rsa.aws
const config = {
  // I have confirmed that the local values are unnecessary (defaults work)

  // Configuration for SSH bastion
  username: "ec2-user",
  host: 35.183.XX.XXX,
  port: 22,
  privateKey: require("fs").readFileSync("/path/to/ssh/key"),

  // Configuration for destination (database)
  dstHost: wdXXXXXXXXXXXX.XXXXXXXXX.XX-XXXXX-X.rds.amazonaws.com,
  dstPort: 5432
};

// NOTE: Moved to its own function, refactor likely fixed a few issues along the way
const getDB = () => new Promise((resolve, reject) => {
  const tnl = await tunnel(config, async error => {
    if (error) return reject(error);

    const db = new Sequelize(DB_NAME, DB_USER, DB_PASSWORD, {
      dialect: "postgres",
      // NOTE: This is super important as the tunnel has essentially moved code execution to the database server already...
      host: "localhost",
      port: 5432
    });

    return resolve(db);
  });
});

In the end, the major change was using localhost in the Sequelize configuration as the SSH tunnel "emerges" on the database instance, hence it should reference itself. There were likely a few other tweaks that were necessary (as I know I tried that at one point), but eventually I emerged intact.

like image 70
Kendall Avatar answered Aug 13 '26 11:08

Kendall



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!