代码之家  ›  专栏  ›  技术社区  ›  Mauricio Vilar

尝试使用node.js创建SSH隧道不起作用

  •  0
  • Mauricio Vilar  · 技术社区  · 2 年前

    几天来,我一直在尝试在node.js中创建ssh隧道,但一直没有成功。

    我是个新手,所以我希望你能容忍我。

    我正试图访问aws中托管的数据库,制作该数据库的程序员给我发了一封电子邮件,其中包含以下数据以进行连接:

    SSH隧道 ssh-N-L 33306:justoaca-db-prod.ciengjumlrqb.us-east-1.rds.amazonaws.com:3306 [email protected] -i~/.ssh/Justoaa-db-bridge.pem

    用户数据库 Justoaarea/XXXXXXXXXX

    pem密钥附在带有密码的zip中,我将zip密码单独发送给Javier。

    问题是,只要我从vs终端或windows命令提示符创建隧道,ssh隧道就可以完美地工作(能够检索数据库的任何表)。

    但是,当我想从node.js创建它时,或者我一直在加载,直到它因超过连接尝试的时间限制而断开连接,或者它没有直接连接。

    我在代码下面留下(我一直在导入许多模块,并尝试不同的方法,但没有成功)。

    const mysql = require("mysql");
    const { exec } = require('child_process');
    const path = require('path');
    const os = require('os');
    var Client = require('ssh2').Client;
    const { readFileSync } = require('fs');
    
    class dbReadOnly {
      constructor() {
        this.dbConfig = {
          host: "127.0.0.1",
          port: 33306, // here I tried with port 22 and 3306
          user: "justoacaread",
          password: "XXXXXX",
          database: "justoaca",
        };
    
        this.tunnel = null;
      }
    
      connect(callback) {
        let sshConfig = {
          username: "ec2-user",
          host: "3.209.213.83",
          port: 33306, //tried here with 3306 and 22 too. 
          privateKey: readFileSync("./certificates/Justoaca-db-bridge.pem"),
        };
    
        console.log("Connecting...");
        const conn = new Client();
        conn.on('ready', () => {
          console.log("SSH connection established.");
          // Establish SSH tunnel to the remote database
          conn.forwardOut(
            // Source: Local IP and port for forwarding
            '127.0.0.1',
            33306,
            // Destination: IP and port of the remote database
            'justoaca-db-prod.ciengjumlrqb.us-east-1.rds.amazonaws.com',
            3306,
            (err, stream) => {
              if (err) {
                console.error('Error establishing SSH tunnel:', err);
                callback(err);
                return;
              }
    
              console.log('SSH tunnel established successfully.');
    
              // Create a database connection using the SSH tunnel stream
              const dbConnection = mysql.createConnection({
                host: '127.0.0.1',
                port: 33306,
                user: 'justoacaread',
                password: 'XXXXXXXX',
                database: 'justoaca',
                stream: stream, // Pass the SSH tunnel stream as the communication channel
              });
    
              dbConnection.connect((err) => {
                if (err) {
                  console.error('Error connecting to the database:', err);
                  callback(err);
                  return;
                }
    
                console.log('Connected to the database successfully.');
                callback(null, dbConnection);
              });
            }
          );
        })
          .on('error', (err) => {
            console.error('Error in SSH connection:', err);
            callback(err);
          })
          .connect(sshConfig);
      }
    
      async query(sql) {
        console.log("Executing query");
        return new Promise((resolve, reject) => {
          this.connection.query(sql, (error, results) => {
            if (error) {
              console.error("Error executing the query:", error);
              reject(error);
            } else {
              console.log("Resolving query results");
              resolve(results);
            }
          });
        });
      }
    
      async disconnect() {
        console.log("DISCONNECTING!");
        //This method was used when i tried to create the ssh with the exec command from the module child_process
    
        // Command to stop the SSH tunnel process
        let killCommand;
        if (os.platform() === 'win32') {
          // Windows
          killCommand = 'taskkill /IM "ssh.exe" /F';
        } else {
          // Other Unix-based systems
          killCommand = 'pkill -f "ssh -N -L 33306:justoaca-db-prod.ciengjumlrqb.us-east-1.rds.amazonaws.com:3306"';
        }
    
        await exec(killCommand, (error, stdout, stderr) => {
          if (error) {
            console.error('Error executing the SSH disconnect command:', error);
            return;
          }
    
          // The command executed successfully
          console.log('SSH disconnect command executed successfully.');
          console.log('Output:', stdout);
        });
    
        this.connection.end();
    
        if (this.tunnel) {
          this.tunnel = null;
        }
      }
    }
    
    module.exports = new dbReadOnly();
    
    

    我最接近的一次是尝试使用child_process模块中的exec方法。 重要的方法是connect,看起来是这样的:

      async connect() {
        console.log("connecting...")
        const command = 'ssh -vvv -N -L 33306:justoaca-db-prod.ciengjumlrqb.us-east-1.rds.amazonaws.com:3306 [email protected] -i ./certificates/Justoaca-db-bridge.pem';
        await exec(command, (error, stdout, stderr) => {
          if (error) {
            console.error('Error executing SSH:', error);
            return;
          }
        });
       
      }
    

    左边是使用子进程exec的终端调试,右边是使用终端直接命令的终端调试(它有效) enter image description here

    奇怪的是,有时它是有效的。它从node.js中检索表。但当我从一个新的终端重试时,它会中断。有时它能工作一段时间,有时它永远不会工作,而且我不会修改代码或任何东西。我不知道为什么会这样。

    所以在简历中,请帮我创建这个隧道。我已经花了好几天的时间试图解决这个问题,但都无济于事。

    我已尝试使用所有ssh模块。

    当我将ssh方法包装在promise中时,它总是会中断(保持加载直到断开连接)。

    此外,如果我不把它包装在承诺中,它就根本没有联系。

    0 回复  |  直到 2 年前
        1
  •  0
  •   Mauricio Vilar    2 年前

    对于任何有同样困难的人,请使用child_process中的“派生”方法。 这使它发挥了作用。