Posted at

【Node.js】SSH経由でRedisへ接続する


概要

ioredisssh2モジュールを使用して、SSH経由でRedisへ接続します。


環境


  • Node.js v8.15.0

  • ioredis v4.2.0

  • ssh2 v0.8.2


方法


依存モジュールを読み込みます。

const Redis = require('ioredis');

const { Client: SSHClient } = require('ssh2');
const net = require('net');
const fs = require('fs');


SSHサーバへ接続する関数を用意します。

function connectToSSH(options) {

return new Promise((resolve, reject) => {
const connection = new SSHClient();

connection.once('ready', () => resolve(connection));
connection.once('error', reject);

connection.connect(options);
});
}


Redisへ接続するためのヘルパー関数を用意します。

function connectToRedis(options) {

const redis = new Redis(options);
return new Promise((resolve, reject) => {
redis.once('error', reject);
redis.once('ready', () => resolve(redis));
});
}


ポートフォワーディング用の中間サーバを作成します。

server.listenの第1引数に0を渡すと、システムの空きポートが割り当てられます。

function createIntermediateServer(connectionListener) {

return new Promise((resolve, reject) => {
const server = net.createServer(connectionListener);
server.once('error', reject);
server.listen(0, () => resolve(server));
});
}


一連のヘルパー関数をまとめて、SSH経由でRedisへ接続する関数を用意します。

async function connectToRedisViaSSH(options = {

ssh: {
host: 'localhost',
port: 22
},
redis: {
host: 'localhost',
port: 6379
}
}) {
const sshConnection = await connectToSSH({
host: options.ssh.host,
port: options.ssh.port,
username: options.ssh.username,
privateKey: options.ssh.privateKey,
passphrase: options.ssh.passphrase
});

const server = await createIntermediateServer(socket => {
sshConnection.forwardOut(
socket.remoteAddress,
socket.remotePort,
options.redis.host,
options.redis.port,
(error, stream) => {
if (error) {
socket.end();
} else {
socket.pipe(stream).pipe(socket);
}
}
);
});

// Redisサーバのアドレスではなく、中間サーバのアドレスを指定します。
const redis = await connectToRedis({
host: server.address().address,
port: server.address().port
});

return redis;
}


作成した関数を利用してRedisへ接続します。

const redis = await connectToRedisViaSSH({

ssh: {
host: '<ssh-server-address>',
port: 22,
username: '<username>',
privateKey: fs.readFileSync('/path/to/private-key'),
passphrase: '<passphrase>'
},
redis: {
host: '<redis-server-address>',
port: 6379
}
});
const keys = await redis.keys('*');
console.log(keys);


参考

https://gist.github.com/luoyjx/b2ea3cfaa20fee43258573b90c2e01a9