Load backend secrets from Vault
Some checks failed
Build and deploy Backend / build (push) Failing after 27s

This commit is contained in:
Ruslan Bakiev
2026-05-08 16:57:41 +07:00
parent f956148141
commit e55a7f1f37
3 changed files with 69 additions and 1 deletions

View File

@@ -5,7 +5,6 @@ RUN npm ci
FROM node:22-alpine AS build FROM node:22-alpine AS build
WORKDIR /app WORKDIR /app
ENV DATABASE_URL="postgresql://mapflow:mapflow@localhost:5432/mapflow"
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules
COPY . . COPY . .
RUN npm run prisma:generate RUN npm run prisma:generate

View File

@@ -1,5 +1,9 @@
import 'dotenv/config'; import 'dotenv/config';
import { loadVaultEnvironment } from './vault/env.js';
await loadVaultEnvironment();
export const config = { export const config = {
host: process.env.HOST ?? '0.0.0.0', host: process.env.HOST ?? '0.0.0.0',
port: Number(process.env.PORT ?? '4000'), port: Number(process.env.PORT ?? '4000'),

65
src/vault/env.ts Normal file
View File

@@ -0,0 +1,65 @@
type VaultConfig = {
address: string;
token: string;
mount: string;
sharedPath: string;
projectPath: string;
};
function requireEnv(name: string) {
const value = process.env[name];
if (!value) {
throw new Error(`${name} is required when VAULT_ENABLED=true.`);
}
return value;
}
function vaultConfig(): VaultConfig {
return {
address: requireEnv('VAULT_ADDR').replace(/\/$/, ''),
token: requireEnv('VAULT_TOKEN'),
mount: requireEnv('VAULT_KV_MOUNT'),
sharedPath: requireEnv('VAULT_SHARED_PATH'),
projectPath: requireEnv('VAULT_PROJECT_PATH'),
};
}
async function readVaultPath(config: VaultConfig, path: string) {
const response = await fetch(
`${config.address}/v1/${config.mount}/data/${path}`,
{ headers: { 'X-Vault-Token': config.token } },
);
if (!response.ok) {
throw new Error(`Vault read failed for ${path}: ${response.status}.`);
}
const payload = (await response.json()) as {
data?: { data?: Record<string, unknown> };
};
const data = payload.data?.data;
if (!data) {
throw new Error(`Vault path ${path} has no KV v2 data.`);
}
return data;
}
function applyEnvironment(values: Record<string, unknown>) {
for (const [key, value] of Object.entries(values)) {
if (typeof value !== 'string') {
throw new Error(`Vault value ${key} must be a string.`);
}
process.env[key] = value;
}
}
export async function loadVaultEnvironment() {
if (process.env.VAULT_ENABLED !== 'true') {
return;
}
const config = vaultConfig();
applyEnvironment(await readVaultPath(config, config.sharedPath));
applyEnvironment(await readVaultPath(config, config.projectPath));
}