@apolitical/server
Version:
Node.js module to encapsulate Apolitical's express server setup
78 lines (61 loc) • 1.96 kB
JavaScript
;
module.exports = ({ secretManager, config, logger }) => {
let client = null;
const resolvedImpersonationTarget = config.GOOGLE_IMPERSONATE_SERVICE_ACCOUNT?.trim() || null;
function isImpersonationEnabled() {
return resolvedImpersonationTarget !== null;
}
function impersonationLogContext() {
return resolvedImpersonationTarget ? { targetServiceAccount: resolvedImpersonationTarget } : {};
}
function getClient() {
if (!client) {
if (isImpersonationEnabled()) {
logger.info('[secrets] using impersonation', impersonationLogContext());
}
client = new secretManager.SecretManagerServiceClient();
}
return client;
}
async function loadSecrets(opts) {
const { secrets } = opts;
const projectId = opts.projectId ?? config.GOOGLE_CLOUD_PROJECT;
if (!projectId) {
throw new Error('Missing projectId for Secret Manager');
}
if (!secrets || secrets.length === 0) {
return;
}
const secretClient = getClient();
for (const spec of secrets) {
const version = spec.version ?? 'latest';
const name = `projects/${projectId}/secrets/${spec.name}/versions/${version}`;
try {
const [resp] = await secretClient.accessSecretVersion({ name });
const payload = resp.payload?.data?.toString('utf8');
if (!payload) {
throw new Error(`Empty payload for secret ${spec.name}`);
}
process.env[spec.envVar] = payload;
logger.info('[secrets] loaded', {
name: spec.name,
envVar: spec.envVar,
version,
});
} catch (err) {
throw new Error(`Failed to load secret "${spec.name}": ${err.message}`);
}
}
}
function getSecret(envVar) {
const val = process.env[envVar];
if (!val) {
throw new Error(`Secret "${envVar}" not loaded`);
}
return val;
}
return {
loadSecrets,
getSecret,
};
};