feat: add ssh key

This commit is contained in:
Mauricio Siu
2024-10-02 22:50:01 -06:00
parent f13e5d449c
commit d41c8c70c3
24 changed files with 3908 additions and 192 deletions

View File

@@ -9,7 +9,6 @@ import {
recreateDirectory,
recreateDirectoryRemote,
} from "../filesystem/directory";
import { readSSHKey } from "../filesystem/ssh";
import { execAsyncRemote } from "../process/execAsync";
export const unzipDrop = async (zipFile: File, application: Application) => {
@@ -90,7 +89,6 @@ const getSFTPConnection = async (serverId: string): Promise<SFTPWrapper> => {
const server = await findServerById(serverId);
if (!server.sshKeyId) throw new Error("No SSH key available for this server");
const keys = await readSSHKey(server.sshKeyId);
return new Promise((resolve, reject) => {
const conn = new Client();
conn
@@ -104,7 +102,7 @@ const getSFTPConnection = async (serverId: string): Promise<SFTPWrapper> => {
host: server.ipAddress,
port: server.port,
username: server.username,
privateKey: keys.privateKey,
privateKey: server.sshKey?.privateKey,
timeout: 99999,
});
});

View File

@@ -1,99 +1,26 @@
import * as fs from "node:fs";
import * as path from "node:path";
import { paths } from "@/server/constants";
import { spawnAsync } from "../process/spawnAsync";
import * as ssh2 from "ssh2";
export const readSSHKey = async (id: string) => {
const { SSH_PATH } = paths();
export const generateSSHKey = async (type: "rsa" | "ed25519" = "rsa") => {
try {
if (!fs.existsSync(SSH_PATH)) {
fs.mkdirSync(SSH_PATH, { recursive: true });
if (type === "rsa") {
const keys = ssh2.utils.generateKeyPairSync("rsa", {
bits: 4096,
comment: "dokploy",
});
return {
privateKey: keys.private,
publicKey: keys.public,
};
}
const keys = ssh2.utils.generateKeyPairSync("ed25519", {
comment: "dokploy",
});
return {
privateKey: fs.readFileSync(path.join(SSH_PATH, `${id}_rsa`), {
encoding: "utf-8",
}),
publicKey: fs.readFileSync(path.join(SSH_PATH, `${id}_rsa.pub`), {
encoding: "utf-8",
}),
privateKey: keys.private,
publicKey: keys.public,
};
} catch (error) {
throw error;
}
};
export const saveSSHKey = async (
id: string,
publicKey: string,
privateKey: string,
) => {
const { SSH_PATH } = paths();
const applicationDirectory = SSH_PATH;
const privateKeyPath = path.join(applicationDirectory, `${id}_rsa`);
const publicKeyPath = path.join(applicationDirectory, `${id}_rsa.pub`);
const privateKeyStream = fs.createWriteStream(privateKeyPath, {
mode: 0o600,
});
privateKeyStream.write(privateKey);
privateKeyStream.end();
fs.writeFileSync(publicKeyPath, publicKey);
};
export const generateSSHKey = async (type: "rsa" | "ed25519" = "rsa") => {
const { SSH_PATH } = paths();
const applicationDirectory = SSH_PATH;
if (!fs.existsSync(applicationDirectory)) {
fs.mkdirSync(applicationDirectory, { recursive: true });
}
const keyPath = path.join(applicationDirectory, "temp_rsa");
if (fs.existsSync(`${keyPath}`)) {
fs.unlinkSync(`${keyPath}`);
}
if (fs.existsSync(`${keyPath}.pub`)) {
fs.unlinkSync(`${keyPath}.pub`);
}
const args = [
"-t",
type,
"-b",
"4096",
"-C",
"dokploy",
"-m",
"PEM",
"-f",
keyPath,
"-N",
"",
];
try {
await spawnAsync("ssh-keygen", args);
const data = await readSSHKey("temp");
await removeSSHKey("temp");
return data;
} catch (error) {
throw error;
}
};
export const removeSSHKey = async (id: string) => {
try {
const { SSH_PATH } = paths();
const publicKeyPath = path.join(SSH_PATH, `${id}_rsa.pub`);
const privateKeyPath = path.join(SSH_PATH, `${id}_rsa`);
await fs.promises.unlink(publicKeyPath);
await fs.promises.unlink(privateKeyPath);
} catch (error) {
throw error;
}
};

View File

@@ -2,7 +2,6 @@ import { exec } from "node:child_process";
import util from "node:util";
import { findServerById } from "@/server/services/server";
import { Client } from "ssh2";
import { readSSHKey } from "../filesystem/ssh";
export const execAsync = util.promisify(exec);
export const execAsyncRemote = async (
@@ -13,8 +12,6 @@ export const execAsyncRemote = async (
const server = await findServerById(serverId);
if (!server.sshKeyId) throw new Error("No SSH key available for this server");
const keys = await readSSHKey(server.sshKeyId);
let stdout = "";
let stderr = "";
return new Promise((resolve, reject) => {
@@ -62,7 +59,7 @@ export const execAsyncRemote = async (
host: server.ipAddress,
port: server.port,
username: server.username,
privateKey: keys.privateKey,
privateKey: server.sshKey?.privateKey,
timeout: 99999,
});
});

View File

@@ -1,13 +1,11 @@
import { findServerById } from "@/server/services/server";
import { docker } from "@/server/constants";
import Dockerode from "dockerode";
import { readSSHKey } from "../filesystem/ssh";
export const getRemoteDocker = async (serverId?: string | null) => {
if (!serverId) return docker;
const server = await findServerById(serverId);
if (!server.sshKeyId) return docker;
const keys = await readSSHKey(server.sshKeyId);
const dockerode = new Dockerode({
host: server.ipAddress,
port: server.port,
@@ -15,7 +13,7 @@ export const getRemoteDocker = async (serverId?: string | null) => {
protocol: "ssh",
// @ts-ignore
sshOptions: {
privateKey: keys.privateKey,
privateKey: server.sshKey?.privateKey,
},
});