fix: use CreateKeyPair instead of ImportKeyPair for simpler SSH key management
AWS CreateKeyPair generates the RSA key pair server-side and returns the private key, avoiding the need to manually format RSA public keys in OpenSSH wire format. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import { getAdminSettings } from "../lib/adminSettings";
|
|||||||
import { env } from "../lib/env";
|
import { env } from "../lib/env";
|
||||||
import {
|
import {
|
||||||
makeEc2Client,
|
makeEc2Client,
|
||||||
generateAndImportKeyPair,
|
createKeyPairAndGetPrivateKey,
|
||||||
createPreviewSecurityGroup,
|
createPreviewSecurityGroup,
|
||||||
launchInstance,
|
launchInstance,
|
||||||
waitForInstanceRunning,
|
waitForInstanceRunning,
|
||||||
@@ -200,7 +200,7 @@ async function firstDeploy(
|
|||||||
checkAbort(previewId);
|
checkAbort(previewId);
|
||||||
|
|
||||||
const keyName = `pp-preview-${previewId}`;
|
const keyName = `pp-preview-${previewId}`;
|
||||||
const { privateKey } = await generateAndImportKeyPair(ec2, keyName);
|
const { privateKey } = await createKeyPairAndGetPrivateKey(ec2, keyName);
|
||||||
const encPrivateKey = encrypt(privateKey);
|
const encPrivateKey = encrypt(privateKey);
|
||||||
|
|
||||||
await prisma.preview.update({ where: { id: previewId }, data: { sshPrivateKey: encPrivateKey, sshKeyName: keyName } });
|
await prisma.preview.update({ where: { id: previewId }, data: { sshPrivateKey: encPrivateKey, sshKeyName: keyName } });
|
||||||
|
|||||||
@@ -7,12 +7,11 @@ import {
|
|||||||
DeleteSecurityGroupCommand,
|
DeleteSecurityGroupCommand,
|
||||||
AuthorizeSecurityGroupIngressCommand,
|
AuthorizeSecurityGroupIngressCommand,
|
||||||
DescribeSecurityGroupsCommand,
|
DescribeSecurityGroupsCommand,
|
||||||
ImportKeyPairCommand,
|
CreateKeyPairCommand,
|
||||||
DeleteKeyPairCommand,
|
DeleteKeyPairCommand,
|
||||||
CreateTagsCommand,
|
CreateTagsCommand,
|
||||||
} from "@aws-sdk/client-ec2";
|
} from "@aws-sdk/client-ec2";
|
||||||
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
|
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
|
||||||
import { generateKeyPairSync, createPublicKey } from "crypto";
|
|
||||||
import { createLogger } from "../lib/logger";
|
import { createLogger } from "../lib/logger";
|
||||||
import { decrypt } from "../lib/encryption";
|
import { decrypt } from "../lib/encryption";
|
||||||
import type { User } from "@prisma/client";
|
import type { User } from "@prisma/client";
|
||||||
@@ -68,38 +67,13 @@ export async function validateAwsCredentials(user: User): Promise<{ success: boo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateSshKeyPair(): { privateKey: string; publicKeyOpenssh: string } {
|
export async function createKeyPairAndGetPrivateKey(ec2: EC2Client, keyName: string): Promise<{ privateKey: string }> {
|
||||||
const { privateKey: privKeyPem, publicKey: pubKeyPem } = generateKeyPairSync("rsa", {
|
const res = await ec2.send(new CreateKeyPairCommand({
|
||||||
modulusLength: 2048,
|
|
||||||
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
||||||
privateKeyEncoding: { type: "pkcs1", format: "pem" },
|
|
||||||
});
|
|
||||||
|
|
||||||
const pubKeyObj = createPublicKey(pubKeyPem);
|
|
||||||
const pubKeyDer = pubKeyObj.export({ type: "spki", format: "der" });
|
|
||||||
|
|
||||||
function sshEncodeBuffer(buf: Buffer): Buffer {
|
|
||||||
const lenBuf = Buffer.allocUnsafe(4);
|
|
||||||
lenBuf.writeUInt32BE(buf.length, 0);
|
|
||||||
return Buffer.concat([lenBuf, buf]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyTypeStr = Buffer.from("ssh-rsa");
|
|
||||||
const keyTypeEncoded = sshEncodeBuffer(keyTypeStr);
|
|
||||||
|
|
||||||
const base64Encoded = pubKeyDer.toString("base64");
|
|
||||||
const openSshKey = `ssh-rsa ${Buffer.concat([keyTypeEncoded]).toString("base64")} pp-generated`;
|
|
||||||
|
|
||||||
return { privateKey: privKeyPem, publicKeyOpenssh: `ssh-rsa ${base64Encoded} pp-generated` };
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function generateAndImportKeyPair(ec2: EC2Client, keyName: string): Promise<{ privateKey: string }> {
|
|
||||||
const { privateKey, publicKeyOpenssh } = generateSshKeyPair();
|
|
||||||
await ec2.send(new ImportKeyPairCommand({
|
|
||||||
KeyName: keyName,
|
KeyName: keyName,
|
||||||
PublicKeyMaterial: Buffer.from(publicKeyOpenssh),
|
KeyType: "rsa",
|
||||||
|
KeyFormat: "pem",
|
||||||
}));
|
}));
|
||||||
return { privateKey };
|
return { privateKey: res.KeyMaterial! };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createPreviewSecurityGroup(ec2: EC2Client, groupName: string, port: number): Promise<string> {
|
export async function createPreviewSecurityGroup(ec2: EC2Client, groupName: string, port: number): Promise<string> {
|
||||||
|
|||||||
Reference in New Issue
Block a user