Allow passing config secrets as paths

This commit is contained in:
Rory&
2025-12-27 10:27:50 +01:00
parent be2ff3bcba
commit df1aea808b
3 changed files with 119 additions and 32 deletions
+103 -31
View File
@@ -79,10 +79,77 @@ in
gatewayEndpoint = mkEndpointOptions "gateway.sb.localhost" 3003;
cdnEndpoint = mkEndpointOptions "cdn.sb.localhost" 3003;
cdnPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
type = lib.types.str;
default = "./files";
description = "Path to store CDN files.";
};
cdnSignaturePath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
legacyJwtSecretPath = libMkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
mailjetApiKeyPath = libMkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
mailjetApiSecretPath = libMkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
smtpPasswordPath = libMkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
gifApiKeyPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
rabbitmqHost = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
rabbitmqHostPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
abuseIpDbApiKeyPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
captchaSecretKeyPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
captchaSiteKeyPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
ipdataApiKeyPath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
requestSignaturePath = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to the secret";
};
extraEnvironment = lib.mkOption {
default = { };
description = ''
@@ -127,7 +194,35 @@ in
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
environment =
{ }
// (if cfg.cdnSignaturePath != null then { CDN_SIGNATURE_PATH = "%d/cdnSignature"; } else { })
// (if cfg.legacyJwtSecretPath != null then { LEGACY_JWT_SECRET_PATH = "%d/legacyJwtSecret"; } else { })
// (if cfg.mailjetApiKeyPath != null then { MAILJET_API_KEY_PATH = "%d/mailjetApiKey"; } else { })
// (if cfg.mailjetApiSecretPath != null then { MAILJET_API_SECRET_PATH = "%d/mailjetApiSecret"; } else { })
// (if cfg.smtpPasswordPath != null then { SMTP_PASSWORD_PATH = "%d/smtpPassword"; } else { })
// (if cfg.gifApiKeyPath != null then { GIF_API_KEY_PATH = "%d/gifApiKey"; } else { })
// (if cfg.rabbitmqHostPath != null then { RABBITMQ_HOST_PATH = "%d/rabbitmqHost"; } else { })
// (if cfg.abuseIpDbApiKeyPath != null then { ABUSE_IP_DB_API_KEY_PATH = "%d/abuseIpDbApiKey"; } else { })
// (if cfg.captchaSecretKeyPath != null then { CAPTCHA_SECRET_KEY_PATH = "%d/captchaSecretKey"; } else { })
// (if cfg.captchaSiteKeyPath != null then { CAPTCHA_SITE_KEY_PATH = "%d/captchaSiteKey"; } else { })
// (if cfg.ipdataApiKeyPath != null then { IPDATA_API_KEY_PATH = "%d/ipdataApiKey"; } else { })
// (if cfg.requestSignaturePath != null then { REQUEST_SIGNATURE_PATH = "%d/requestSignature"; } else { });
serviceConfig = {
LoadCredential =
[ ]
++ (if cfg.cdnSignaturePath != null then [ "cdnSignature:${cfg.cdnSignaturePath}" ] else [ ])
++ (if cfg.legacyJwtSecretPath != null then [ "legacyJwtSecret:${cfg.legacyJwtSecretPath}" ] else [ ])
++ (if cfg.mailjetApiKeyPath != null then [ "mailjetApiKey:${cfg.mailjetApiKeyPath}" ] else [ ])
++ (if cfg.mailjetApiSecretPath != null then [ "mailjetApiSecret:${cfg.mailjetApiSecretPath}" ] else [ ])
++ (if cfg.smtpPasswordPath != null then [ "smtpPassword:${cfg.smtpPasswordPath}" ] else [ ])
++ (if cfg.gifApiKeyPath != null then [ "gifApiKey:${cfg.gifApiKeyPath}" ] else [ ])
++ (if cfg.rabbitmqHostPath != null then [ "rabbitmqHost:${cfg.rabbitmqHostPath}" ] else [ ])
++ (if cfg.abuseIpDbApiKeyPath != null then [ "abuseIpDbApiKey:${cfg.abuseIpDbApiKeyPath}" ] else [ ])
++ (if cfg.captchaSecretKeyPath != null then [ "captchaSecretKey:${cfg.captchaSecretKeyPath}" ] else [ ])
++ (if cfg.captchaSiteKeyPath != null then [ "captchaSiteKey:${cfg.captchaSiteKeyPath}" ] else [ ])
++ (if cfg.ipdataApiKeyPath != null then [ "ipdataApiKey:${cfg.ipdataApiKeyPath}" ] else [ ])
++ (if cfg.requestSignaturePath != null then [ "requestSignature:${cfg.requestSignaturePath}" ] else [ ]);
User = "spacebarchat";
Group = "spacebarchat";
DynamicUser = false;
@@ -172,14 +267,12 @@ in
in
{
assertions = [
# {
# assertion = !((cfg.extraEnvironment.THREADS > 1) && !config.services.rabbitmq.enable);
# message = "Make sure you've setup RabbitMQ when using more than one thread with Spacebar";
# }
{
assertion = lib.all (map (key: !(key == "CONFIG_PATH" || key == "CONFIG_READONLY" || key == "PORT" || key == "STORAGE_LOCATION")) (lib.attrNames cfg.extraEnvironment));
message = "You cannot set CONFIG_PATH, CONFIG_READONLY, PORT or STORAGE_LOCATION in extraEnvironment, these are managed by the NixOS module.";
}
];
# systemd.tmpfiles.rules = [ "d /run/spacebarchat 0750 spacebar spacebar" ];
users.users.spacebarchat = {
isSystemUser = true;
description = "Spacebar service user";
@@ -202,15 +295,8 @@ in
CONFIG_PATH = configFile;
CONFIG_READONLY = 1;
PORT = toString cfg.apiEndpoint.localPort;
STORAGE_LOCATION = cfg.cdnPath;
}
// (
if cfg.cdnPath != null then
{
STORAGE_LOCATION = cfg.cdnPath;
}
else
{ }
)
);
serviceConfig = {
ExecStart = "${cfg.package}/bin/start-api";
@@ -231,15 +317,8 @@ in
CONFIG_PATH = configFile;
CONFIG_READONLY = 1;
PORT = toString cfg.gatewayEndpoint.localPort;
STORAGE_LOCATION = cfg.cdnPath;
}
// (
if cfg.cdnPath != null then
{
STORAGE_LOCATION = cfg.cdnPath;
}
else
{ }
)
);
serviceConfig = {
ExecStart = "${cfg.package}/bin/start-gateway";
@@ -260,15 +339,8 @@ in
CONFIG_PATH = configFile;
CONFIG_READONLY = 1;
PORT = toString cfg.cdnEndpoint.localPort;
STORAGE_LOCATION = cfg.cdnPath;
}
// (
if cfg.cdnPath != null then
{
STORAGE_LOCATION = cfg.cdnPath;
}
else
{ }
)
);
serviceConfig = {
ExecStart = "${cfg.package}/bin/start-cdn";
+1 -1
View File
@@ -14,7 +14,7 @@ in
};
config = lib.mkIf (cfg.enable && cfg.nginx.enable) {
services.nginx = lib.trace (cfg.apiEndpoint) {
services.nginx = {
virtualHosts = lib.mkIf cfg.enable {
"${cfg.apiEndpoint.host}" = {
enableACME = cfg.apiEndpoint.useSsl;
+15
View File
@@ -53,6 +53,21 @@ export class Config {
config = OrmUtils.mergeDeep({}, { ...new ConfigValue() }, config);
// TODO: factor this out someday
if (process.env.CDN_SIGNATURE_PATH) config.security.cdnSignatureKey = (await fs.readFile(process.env.CDN_SIGNATURE_PATH, "utf-8")).trim();
if (process.env.LEGACY_JWT_SECRET_PATH) config.security.jwtSecret = (await fs.readFile(process.env.LEGACY_JWT_SECRET_PATH, "utf-8")).trim();
if (process.env.MAILJET_API_KEY_PATH) config.email.mailjet.apiKey = (await fs.readFile(process.env.MAILJET_API_KEY_PATH, "utf-8")).trim();
if (process.env.MAILJET_API_SECRET_PATH) config.email.mailjet.apiSecret = (await fs.readFile(process.env.MAILJET_API_SECRET_PATH, "utf-8")).trim();
if (process.env.SMTP_PASSWORD_PATH) config.email.smtp.password = (await fs.readFile(process.env.SMTP_PASSWORD_PATH, "utf-8")).trim();
if (process.env.GIF_API_KEY_PATH) config.gif.apiKey = (await fs.readFile(process.env.GIF_API_KEY_PATH, "utf-8")).trim();
if (process.env.RABBITMQ_HOST) config.rabbitmq.host = process.env.RABBITMQ_HOST.trim();
if (process.env.RABBITMQ_HOST_PATH) config.rabbitmq.host = (await fs.readFile(process.env.RABBITMQ_HOST_PATH, "utf-8")).trim();
if (process.env.ABUSEIPDB_API_KEY_PATH) config.security.abuseIpDbApiKey = (await fs.readFile(process.env.ABUSEIPDB_API_KEY_PATH, "utf-8")).trim();
if (process.env.CAPTCHA_SECRET_KEY_PATH) config.security.captcha.secret = (await fs.readFile(process.env.CAPTCHA_SECRET_KEY_PATH, "utf-8")).trim();
if (process.env.CAPTCHA_SITE_KEY_PATH) config.security.captcha.sitekey = (await fs.readFile(process.env.CAPTCHA_SITE_KEY_PATH, "utf-8")).trim();
if (process.env.IPDATA_API_KEY_PATH) config.security.ipdataApiKey = (await fs.readFile(process.env.IPDATA_API_KEY_PATH, "utf-8")).trim();
if (process.env.REQUEST_SIGNATURE_PATH) config.security.requestSignature = (await fs.readFile(process.env.REQUEST_SIGNATURE_PATH, "utf-8")).trim();
await this.set(config);
validateFinalConfig(config);
return config;