feat(eims): allow private key/cert as inline base64 env vars

EIMS_PRIVATE_KEY_BASE64 / EIMS_CERTIFICATE_BASE64, alternative to the
existing _PATH vars. Wins over the path when set; falls back to the
file otherwise. Neither var required at boot on its own — the
either/or check moved out of the flat REQUIRED_VARS list.

Lets a dockerized deployment receive the key/cert the same way it
already receives every other EIMS_* secret (plain env var into the
container) instead of needing a host bind mount into the container
filesystem.
This commit is contained in:
Hagernesh
2026-08-17 09:14:38 +00:00
parent 28c9dd93e0
commit 4a4b1981cb
4 changed files with 72 additions and 20 deletions

View File

@@ -24,25 +24,31 @@ export class EimsCredentialsProvider {
return this.config.get<EimsConfig>("eims")!;
}
/** RSA private key, parsed once. Throws a config error if the path is missing or unusable. */
/**
* RSA private key, parsed once. `privateKeyBase64` wins when set (no file I/O at all — for a
* container that can't be given a host bind mount); otherwise falls back to `privateKeyPath`.
* Throws a config error if neither is usable.
*/
getPrivateKey(): KeyObject {
if (this.privateKey) return this.privateKey;
const path = this.cfg.privateKeyPath;
if (!path) throw new EimsConfigException("EIMS_PRIVATE_KEY_PATH is not set");
const { privateKeyBase64, privateKeyPath: path } = this.cfg;
const source = privateKeyBase64 ? "EIMS_PRIVATE_KEY_BASE64" : `EIMS_PRIVATE_KEY_PATH (${path})`;
if (!privateKeyBase64 && !path) throw new EimsConfigException("EIMS_PRIVATE_KEY_PATH is not set");
let key: KeyObject;
try {
key = createPrivateKey(readFileSync(path));
const bytes = privateKeyBase64 ? Buffer.from(privateKeyBase64, "base64") : readFileSync(path);
key = createPrivateKey(bytes);
} catch (err) {
// The path is operational information, not a secret; the key material never appears.
// The source is operational information, not a secret; the key material never appears.
throw new EimsConfigException(
`EIMS private key at ${path} could not be read or parsed: ${(err as Error).message}`,
`EIMS private key from ${source} could not be read or parsed: ${(err as Error).message}`,
);
}
if (key.asymmetricKeyType !== "rsa") {
throw new EimsConfigException(
`EIMS private key at ${path} is ${key.asymmetricKeyType ?? "of unknown type"}; EIMS requires RSA`,
`EIMS private key from ${source} is ${key.asymmetricKeyType ?? "of unknown type"}; EIMS requires RSA`,
);
}
@@ -51,11 +57,20 @@ export class EimsCredentialsProvider {
return key;
}
/** Base64 of the certificate file's exact bytes. No parsing, no re-encoding. */
/**
* Base64 of the certificate file's exact bytes. No parsing, no re-encoding. `certificateBase64`
* config wins when set (already base64, used as-is); otherwise read from `certificatePath`.
*/
getCertificateBase64(): string {
if (this.certificateBase64) return this.certificateBase64;
const path = this.cfg.certificatePath;
const { certificateBase64: inline, certificatePath: path } = this.cfg;
if (inline) {
this.certificateBase64 = inline;
this.logger.log(`EIMS certificate bundle loaded from EIMS_CERTIFICATE_BASE64`);
return this.certificateBase64;
}
if (!path) throw new EimsConfigException("EIMS_CERTIFICATE_PATH is not set");
let bytes: Buffer;