Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 49faf97c9b |
+15
-41
@@ -1,5 +1,4 @@
|
|||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import crypto from "crypto";
|
|
||||||
import { PrismaPg } from "@prisma/adapter-pg";
|
import { PrismaPg } from "@prisma/adapter-pg";
|
||||||
import { Prisma, PrismaClient } from "../generated/prisma/client";
|
import { Prisma, PrismaClient } from "../generated/prisma/client";
|
||||||
import * as msal from "@azure/msal-node";
|
import * as msal from "@azure/msal-node";
|
||||||
@@ -29,46 +28,21 @@ const isProduction = process.env.NODE_ENV === "production";
|
|||||||
|
|
||||||
const readKeyFile = (path: string) => readFileSync(path).toString();
|
const readKeyFile = (path: string) => readFileSync(path).toString();
|
||||||
|
|
||||||
/**
|
export const accessTokenPrivateKey = isProduction
|
||||||
* Convert a PKCS#1 PEM key to PKCS#8 PEM format.
|
? process.env.ACCESS_TOKEN_PRIVATE_KEY!
|
||||||
* The compiled Bun binary on Ubuntu uses an OpenSSL that doesn't auto-detect PKCS#1 format,
|
: readKeyFile(`.accessToken.key`);
|
||||||
* so we normalize all keys to PKCS#8 at load time.
|
export const refreshTokenPrivateKey = isProduction
|
||||||
*/
|
? process.env.REFRESH_TOKEN_PRIVATE_KEY!
|
||||||
const toPkcs8Private = (pem: string) =>
|
: readKeyFile(`.refreshToken.key`);
|
||||||
crypto
|
export const permissionsPrivateKey = isProduction
|
||||||
.createPrivateKey({ key: pem, format: "pem", type: "pkcs1" })
|
? process.env.PERMISSIONS_PRIVATE_KEY!
|
||||||
.export({ type: "pkcs8", format: "pem" }) as string;
|
: readKeyFile(`.permissions.key`);
|
||||||
|
export const secureValuesPrivateKey = isProduction
|
||||||
const toPkcs8Public = (pem: string) =>
|
? process.env.SECURE_VALUES_PRIVATE_KEY!
|
||||||
crypto
|
: readKeyFile(`.secureValues.key`);
|
||||||
.createPublicKey({ key: pem, format: "pem", type: "pkcs1" })
|
export const secureValuesPublicKey = isProduction
|
||||||
.export({ type: "spki", format: "pem" }) as string;
|
? process.env.SECURE_VALUES_PUBLIC_KEY!
|
||||||
|
: readKeyFile(`public-keys/.secureValues.pub`);
|
||||||
export const accessTokenPrivateKey = toPkcs8Private(
|
|
||||||
isProduction
|
|
||||||
? process.env.ACCESS_TOKEN_PRIVATE_KEY!
|
|
||||||
: readKeyFile(`.accessToken.key`),
|
|
||||||
);
|
|
||||||
export const refreshTokenPrivateKey = toPkcs8Private(
|
|
||||||
isProduction
|
|
||||||
? process.env.REFRESH_TOKEN_PRIVATE_KEY!
|
|
||||||
: readKeyFile(`.refreshToken.key`),
|
|
||||||
);
|
|
||||||
export const permissionsPrivateKey = toPkcs8Private(
|
|
||||||
isProduction
|
|
||||||
? process.env.PERMISSIONS_PRIVATE_KEY!
|
|
||||||
: readKeyFile(`.permissions.key`),
|
|
||||||
);
|
|
||||||
export const secureValuesPrivateKey = toPkcs8Private(
|
|
||||||
isProduction
|
|
||||||
? process.env.SECURE_VALUES_PRIVATE_KEY!
|
|
||||||
: readKeyFile(`.secureValues.key`),
|
|
||||||
);
|
|
||||||
export const secureValuesPublicKey = toPkcs8Public(
|
|
||||||
isProduction
|
|
||||||
? process.env.SECURE_VALUES_PUBLIC_KEY!
|
|
||||||
: readKeyFile(`public-keys/.secureValues.pub`),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Microsoft Auth Constants
|
// Microsoft Auth Constants
|
||||||
const msalConfig: msal.Configuration = {
|
const msalConfig: msal.Configuration = {
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { execSync } from "child_process";
|
||||||
|
|
||||||
|
const kubeconfig = "/Users/jroberts/projects/K8S-QuickDeploy/k8s.yaml";
|
||||||
|
|
||||||
|
function getKey(name: string): string {
|
||||||
|
const b64 = execSync(
|
||||||
|
`KUBECONFIG=${kubeconfig} kubectl get secret optima-keys-secret -n optima -o jsonpath="{.data.${name}}"`,
|
||||||
|
)
|
||||||
|
.toString()
|
||||||
|
.trim();
|
||||||
|
return Buffer.from(b64, "base64").toString("utf-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
const privKeys = [
|
||||||
|
"ACCESS_TOKEN_PRIVATE_KEY",
|
||||||
|
"REFRESH_TOKEN_PRIVATE_KEY",
|
||||||
|
"PERMISSIONS_PRIVATE_KEY",
|
||||||
|
"SECURE_VALUES_PRIVATE_KEY",
|
||||||
|
];
|
||||||
|
|
||||||
|
const converted: Record<string, string> = {};
|
||||||
|
|
||||||
|
// Use openssl CLI to convert PKCS#1 to PKCS#8 (Bun's crypto has issues with some keys)
|
||||||
|
for (const k of privKeys) {
|
||||||
|
const pem = getKey(k);
|
||||||
|
const pkcs8 = execSync("openssl pkey -in /dev/stdin", {
|
||||||
|
input: pem,
|
||||||
|
}).toString();
|
||||||
|
converted[k] = pkcs8;
|
||||||
|
console.log(`${k}: converted to PKCS#8 ✅`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pubPem = getKey("SECURE_VALUES_PUBLIC_KEY");
|
||||||
|
const spki = execSync("openssl rsa -RSAPublicKey_in -pubout -in /dev/stdin", {
|
||||||
|
input: pubPem,
|
||||||
|
}).toString();
|
||||||
|
converted["SECURE_VALUES_PUBLIC_KEY"] = spki;
|
||||||
|
console.log("SECURE_VALUES_PUBLIC_KEY: converted to SPKI ✅");
|
||||||
|
|
||||||
|
// Generate kubectl command to recreate the secret with PKCS#8 keys
|
||||||
|
const args = Object.entries(converted)
|
||||||
|
.map(([k, v]) => `--from-literal=${k}='${v}'`)
|
||||||
|
.join(" \\\n ");
|
||||||
|
|
||||||
|
console.log("\n--- Delete and recreate secret with PKCS#8 keys ---\n");
|
||||||
|
console.log(
|
||||||
|
`KUBECONFIG=${kubeconfig} kubectl delete secret optima-keys-secret -n optima`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`KUBECONFIG=${kubeconfig} kubectl create secret generic optima-keys-secret -n optima \\\n ${args}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Actually do it
|
||||||
|
console.log("\nApplying...");
|
||||||
|
execSync(
|
||||||
|
`KUBECONFIG=${kubeconfig} kubectl delete secret optima-keys-secret -n optima`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const literals = Object.entries(converted).map(
|
||||||
|
([k, v]) => `--from-literal=${k}=${v}`,
|
||||||
|
);
|
||||||
|
const cmd = `KUBECONFIG=${kubeconfig} kubectl create secret generic optima-keys-secret -n optima ${literals.join(" ")}`;
|
||||||
|
execSync(cmd);
|
||||||
|
|
||||||
|
console.log("Secret recreated with PKCS#8 keys ✅");
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import keypair from "keypair";
|
import crypto from "crypto";
|
||||||
|
|
||||||
console.log(`
|
console.log(`
|
||||||
Generating Private Keys
|
Generating Private Keys
|
||||||
-----------------
|
-----------------
|
||||||
This script will go through and genrate all the keys necessary for running the Credential Manager API locally.
|
This script will go through and generate all the keys necessary for running the Credential Manager API locally.
|
||||||
This process might take several minutes.
|
This process might take several minutes.
|
||||||
-----------------`);
|
-----------------`);
|
||||||
|
|
||||||
@@ -42,9 +42,13 @@ await Promise.all(
|
|||||||
if (!privExists || !pubExists) {
|
if (!privExists || !pubExists) {
|
||||||
// Always regenerate both files together to ensure the key pair matches
|
// Always regenerate both files together to ensure the key pair matches
|
||||||
console.log(`Generating '${v}' and '${pubPath}'...`);
|
console.log(`Generating '${v}' and '${pubPath}'...`);
|
||||||
const keys = keypair({ bits: 4096 });
|
const { privateKey, publicKey } = crypto.generateKeyPairSync("rsa", {
|
||||||
await Bun.write(v, keys.private);
|
modulusLength: 4096,
|
||||||
await Bun.write(pubPath, keys.public);
|
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
||||||
|
publicKeyEncoding: { type: "spki", format: "pem" },
|
||||||
|
});
|
||||||
|
await Bun.write(v, privateKey);
|
||||||
|
await Bun.write(pubPath, publicKey);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}),
|
}),
|
||||||
|
|||||||
+16
-11
@@ -1,4 +1,4 @@
|
|||||||
import keypair from "keypair";
|
import crypto from "crypto";
|
||||||
import { mkdirSync } from "fs";
|
import { mkdirSync } from "fs";
|
||||||
|
|
||||||
const outputDir = "production-keys";
|
const outputDir = "production-keys";
|
||||||
@@ -19,14 +19,18 @@ const generatedKeys: Record<string, { private: string; public: string }> = {};
|
|||||||
|
|
||||||
for (const name of keyFiles) {
|
for (const name of keyFiles) {
|
||||||
console.log(`Generating '${name}' key pair (4096-bit RSA)...`);
|
console.log(`Generating '${name}' key pair (4096-bit RSA)...`);
|
||||||
const keys = keypair({ bits: 4096 });
|
const { privateKey, publicKey } = crypto.generateKeyPairSync("rsa", {
|
||||||
generatedKeys[name] = keys;
|
modulusLength: 4096,
|
||||||
|
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
||||||
|
publicKeyEncoding: { type: "spki", format: "pem" },
|
||||||
|
});
|
||||||
|
generatedKeys[name] = { private: privateKey, public: publicKey };
|
||||||
|
|
||||||
const privPath = `${outputDir}/${name}.key`;
|
const privPath = `${outputDir}/${name}.key`;
|
||||||
const pubPath = `${outputDir}/${name}.pub`;
|
const pubPath = `${outputDir}/${name}.pub`;
|
||||||
|
|
||||||
await Bun.write(privPath, keys.private);
|
await Bun.write(privPath, privateKey);
|
||||||
await Bun.write(pubPath, keys.public);
|
await Bun.write(pubPath, publicKey);
|
||||||
|
|
||||||
console.log(` ✔ ${privPath}`);
|
console.log(` ✔ ${privPath}`);
|
||||||
console.log(` ✔ ${pubPath}`);
|
console.log(` ✔ ${pubPath}`);
|
||||||
@@ -38,14 +42,15 @@ const toBase64 = (str: string) => Buffer.from(str).toString("base64");
|
|||||||
const secretYaml = `apiVersion: v1
|
const secretYaml = `apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: optima-keys
|
name: optima-keys-secret
|
||||||
|
namespace: optima
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
accessToken.key: ${toBase64(generatedKeys["accessToken"].private)}
|
ACCESS_TOKEN_PRIVATE_KEY: ${toBase64(generatedKeys["accessToken"].private)}
|
||||||
refreshToken.key: ${toBase64(generatedKeys["refreshToken"].private)}
|
REFRESH_TOKEN_PRIVATE_KEY: ${toBase64(generatedKeys["refreshToken"].private)}
|
||||||
permissions.key: ${toBase64(generatedKeys["permissions"].private)}
|
PERMISSIONS_PRIVATE_KEY: ${toBase64(generatedKeys["permissions"].private)}
|
||||||
secureValues.key: ${toBase64(generatedKeys["secureValues"].private)}
|
SECURE_VALUES_PRIVATE_KEY: ${toBase64(generatedKeys["secureValues"].private)}
|
||||||
secureValues.pub: ${toBase64(generatedKeys["secureValues"].public)}
|
SECURE_VALUES_PUBLIC_KEY: ${toBase64(generatedKeys["secureValues"].public)}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const secretPath = `${outputDir}/optima-keys-secret.yaml`;
|
const secretPath = `${outputDir}/optima-keys-secret.yaml`;
|
||||||
|
|||||||
Reference in New Issue
Block a user