homelab/nixos/hosts/media/lib/api-keys.nix
2025-07-16 02:10:31 +02:00

98 lines
3.9 KiB
Nix

{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.nixarr;
# Helper to create API key extraction for a service
mkApiKeyExtractor = serviceName: serviceConfig: {
description = "Extract ${serviceName} API key";
after = ["${serviceName}.service"];
requires = ["${serviceName}.service"];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
# Use DynamicUser if the parent service does
DynamicUser = serviceConfig.serviceConfig.DynamicUser or false;
# Only set User if not using DynamicUser
${
if !(serviceConfig.serviceConfig.DynamicUser or false)
then "User"
else null
} =
serviceConfig.user or null;
Group = "${serviceName}-api";
UMask = "0027"; # Results in 0640 permissions
ExecStartPre = [
"${pkgs.coreutils}/bin/mkdir -p ${cfg.stateDir}/api-keys"
"${pkgs.coreutils}/bin/chown root:${serviceName}-api ${cfg.stateDir}/api-keys"
"${pkgs.coreutils}/bin/chmod 750 ${cfg.stateDir}/api-keys"
# Wait for config file to exist
"${pkgs.bash}/bin/bash -c 'while [ ! -f ${serviceConfig.stateDir}/config.xml ]; do sleep 1; done'"
];
# Bazarr api key is located a different place...
ExecStart = pkgs.writeShellScript "extract-${serviceName}-api-key" ''
${pkgs.dasel}/bin/dasel -f "${serviceConfig.stateDir}/config.xml" \
-s ".Config.ApiKey" | tr -d '\n\r' > "${cfg.stateDir}/api-keys/${serviceName}.key"
chown $USER:${serviceName}-api "${cfg.stateDir}/api-keys/${serviceName}.key"
'';
};
};
in {
config = mkIf cfg.enable {
# Create per-service API key groups
users.groups = mkMerge [
(mkIf cfg.sonarr.enable {sonarr-api = {};})
(mkIf cfg.radarr.enable {radarr-api = {};})
(mkIf cfg.lidarr.enable {lidarr-api = {};})
(mkIf cfg.readarr.enable {readarr-api = {};})
(mkIf cfg.prowlarr.enable {prowlarr-api = {};})
# (mkIf cfg.bazarr.enable {bazarr-api = {};})
];
# Add services that need API keys to their respective groups
users.users = mkMerge [
# Static users
(mkIf cfg.transmission.enable {
transmission.extraGroups = optional cfg.prowlarr.enable "prowlarr-api";
})
(mkIf cfg.transmission.privateTrackers.cross-seed.enable {
cross-seed.extraGroups = optional cfg.prowlarr.enable "prowlarr-api";
})
];
# Add api groups to services with DynamicUser
systemd.services = mkMerge [
(mkIf cfg.sonarr.enable {sonarr.serviceConfig.SupplementaryGroups = ["sonarr-api"];})
(mkIf cfg.radarr.enable {radarr.serviceConfig.SupplementaryGroups = ["radarr-api"];})
(mkIf cfg.lidarr.enable {lidarr.serviceConfig.SupplementaryGroups = ["lidarr-api"];})
(mkIf cfg.readarr.enable {readarr.serviceConfig.SupplementaryGroups = ["readarr-api"];})
(mkIf cfg.prowlarr.enable {prowlarr.serviceConfig.SupplementaryGroups = ["prowlarr-api"];})
# (mkIf cfg.bazarr.enable {bazarr.serviceConfig.SupplementaryGroups = ["bazarr-api"];})
(mkIf cfg.recyclarr.enable {
recyclarr.serviceConfig.SupplementaryGroups =
(optional cfg.sonarr.enable "sonarr-api")
++ (optional cfg.radarr.enable "radarr-api");
})
# Create API key extractors for enabled services
(mkIf cfg.sonarr.enable {"sonarr-api-key" = mkApiKeyExtractor "sonarr" cfg.sonarr;})
(mkIf cfg.radarr.enable {"radarr-api-key" = mkApiKeyExtractor "radarr" cfg.radarr;})
(mkIf cfg.lidarr.enable {"lidarr-api-key" = mkApiKeyExtractor "lidarr" cfg.lidarr;})
(mkIf cfg.readarr.enable {"readarr-api-key" = mkApiKeyExtractor "readarr" cfg.readarr;})
(mkIf cfg.prowlarr.enable {"prowlarr-api-key" = mkApiKeyExtractor "prowlarr" cfg.prowlarr;})
# (mkIf cfg.bazarr.enable {"bazarr-api-key" = mkApiKeyExtractor "bazarr" cfg.bazarr;})
];
# Create the api-keys directory
systemd.tmpfiles.rules = [
"d ${cfg.stateDir}/api-keys 0750 root root - -"
];
};
}