feat: restrict customer DB user permissions on provision
Some checks failed
Build & Release / build (push) Failing after 1m3s
Some checks failed
Build & Release / build (push) Failing after 1m3s
This commit is contained in:
@@ -5,6 +5,7 @@ export const config = {
|
||||
gitSshKey: process.env.GIT_SSH_KEY!,
|
||||
gitRepoUrl: process.env.GIT_REPO_URL ?? "ssh://git@git-ssh.lunarfront.tech/ryan/lunarfront-charts.git",
|
||||
dbUrl: process.env.DATABASE_URL!,
|
||||
doadminDbUrl: process.env.DOADMIN_DATABASE_URL!,
|
||||
};
|
||||
|
||||
for (const [key, val] of Object.entries(config)) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { z } from "zod";
|
||||
import { createDatabase, createDatabaseUser, deleteDatabase, deleteDatabaseUser } from "../services/do";
|
||||
import { addCustomerToPool, removeCustomerFromPool } from "../services/pgbouncer";
|
||||
import { addCustomerChart, removeCustomerChart } from "../services/git";
|
||||
import { setupCustomerDatabase, teardownCustomerDatabase } from "../services/db";
|
||||
|
||||
const ProvisionSchema = z.object({
|
||||
name: z.string().min(2).max(32).regex(/^[a-z0-9-]+$/, "lowercase letters, numbers, and hyphens only"),
|
||||
@@ -21,6 +22,7 @@ export async function customerRoutes(app: FastifyInstance) {
|
||||
createDatabaseUser(slug),
|
||||
]);
|
||||
|
||||
await setupCustomerDatabase(slug, user.name);
|
||||
await addCustomerToPool(slug, user.password);
|
||||
addCustomerChart(slug, body.appVersion);
|
||||
|
||||
@@ -35,6 +37,7 @@ export async function customerRoutes(app: FastifyInstance) {
|
||||
|
||||
removeCustomerChart(slug);
|
||||
await removeCustomerFromPool(slug);
|
||||
await teardownCustomerDatabase(slug, slug);
|
||||
await Promise.all([
|
||||
deleteDatabase(slug),
|
||||
deleteDatabaseUser(slug),
|
||||
|
||||
37
src/services/db.ts
Normal file
37
src/services/db.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import postgres from "postgres";
|
||||
import { config } from "../lib/config";
|
||||
|
||||
// Runs setup SQL as doadmin against a specific database
|
||||
export async function setupCustomerDatabase(dbName: string, username: string) {
|
||||
const sql = postgres(config.doadminDbUrl.replace(/\/\w+(\?|$)/, `/${dbName}$1`), { max: 1 });
|
||||
|
||||
try {
|
||||
// Revoke all public access, then grant only to this user
|
||||
await sql.unsafe(`
|
||||
REVOKE ALL ON DATABASE "${dbName}" FROM PUBLIC;
|
||||
GRANT CONNECT ON DATABASE "${dbName}" TO "${username}";
|
||||
GRANT ALL PRIVILEGES ON DATABASE "${dbName}" TO "${username}";
|
||||
ALTER DATABASE "${dbName}" OWNER TO "${username}";
|
||||
`);
|
||||
|
||||
// Set default privileges so any tables the app creates are accessible to itself
|
||||
await sql.unsafe(`
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "${username}" IN SCHEMA public
|
||||
GRANT ALL ON TABLES TO "${username}";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "${username}" IN SCHEMA public
|
||||
GRANT ALL ON SEQUENCES TO "${username}";
|
||||
`);
|
||||
} finally {
|
||||
await sql.end();
|
||||
}
|
||||
}
|
||||
|
||||
export async function teardownCustomerDatabase(dbName: string, username: string) {
|
||||
// Reassign ownership back to doadmin before dropping
|
||||
const sql = postgres(config.doadminDbUrl.replace(/\/\w+(\?|$)/, `/${dbName}$1`), { max: 1 });
|
||||
try {
|
||||
await sql.unsafe(`REASSIGN OWNED BY "${username}" TO doadmin;`);
|
||||
} finally {
|
||||
await sql.end();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user