{ description = "Skynet LDAP backend"; inputs = { nixpkgs.url = "nixpkgs/nixos-23.05"; naersk.url = "github:nix-community/naersk"; utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, utils, naersk }: utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages."${system}"; naersk-lib = naersk.lib."${system}"; package_name = "skynet_ldap_backend"; package_update = "update_groups"; desc = "Skynet LDAP backend"; in rec { # `nix build` packages."${package_name}" = naersk-lib.buildPackage { pname = "${package_name}"; root = ./.; buildInputs = [ pkgs.openssl pkgs.pkg-config ]; }; defaultPackage = packages."${package_name}"; # `nix run` apps."${package_name}" = utils.lib.mkApp { drv = packages."${package_name}"; }; defaultApp = apps."${package_name}"; # `nix develop` devShell = pkgs.mkShell { nativeBuildInputs = with pkgs; [ rustc cargo pkg-config openssl]; }; nixosModule = { lib, pkgs, config, ... }: with lib; let cfg = config.services."${package_name}"; # secret options are in the env file loaded separately environment_config = { # basic server stuff HOME = cfg.home; DATABASE = "database.db"; HOST_PORT = cfg.host_port; SSH_ROOT = "skynet_old"; # special categories of users USERS_ADMIN = lib.strings.concatStringsSep "," cfg.users.admin; USERS_COMMITTEE = lib.strings.concatStringsSep "," cfg.users.committee; USERS_LIFETIME = lib.strings.concatStringsSep "," cfg.users.lifetime; USERS_BANNED = lib.strings.concatStringsSep "," cfg.users.banned; USERS_RESTRICTED = lib.strings.concatStringsSep "," cfg.users.restricted; }; service_name = script: lib.strings.sanitizeDerivationName("${cfg.user}@${script}"); # oneshot scripts to run serviceGenerator = mapAttrs' (script: time: nameValuePair (service_name script) { description = "Service for ${desc} ${script}"; wantedBy = [ ]; after = [ "network-online.target" ]; environment = environment_config; serviceConfig = { Type = "oneshot"; User = "${cfg.user}"; Group = "${cfg.user}"; ExecStart = "${self.defaultPackage."${system}"}/bin/${script}"; EnvironmentFile = [ "${cfg.env.ldap}" "${cfg.env.discord}" "${cfg.env.mail}" "${cfg.env.wolves}" ]; }; }); # each timer will run the above service timerGenerator = mapAttrs' (script: time: nameValuePair (service_name script) { description = "Timer for ${desc} ${script}"; wantedBy = [ "timers.target" ]; partOf = [ "${service_name script}.service" ]; timerConfig = { OnCalendar = time; Unit = "${service_name script}.service"; Persistent = true; }; }); # modify these scripts = { # every 15 min "update_data" = "*:0,15,30,45"; #"new_users" = "*:5,20,35,50"; # groups are updated every 8 hours "update_groups" = "00,08,16:00:00"; }; in { options.services."${package_name}" = { enable = mkEnableOption "enable ${package_name}"; # keep really secret stuff in this env = { ldap = mkOption rec { type = types.str; description = "Auth for the LDAP, has LDAP_HOST, LDAP_ADMIN, LDAP_ADMIN_PW"; }; discord = mkOption rec { type = types.str; description = "Auth for the discord bot, has LDAP_DISCORD_AUTH"; }; mail = mkOption rec { type = types.str; description = "Mail details, has EMAIL_SMTP, EMAIL_USER, EMAIL_PASS"; }; wolves = mkOption rec { type = types.str; description = "Mail details, has WOLVES_URL, WOLVES_KEY"; }; }; users = { admin = mkOption rec { type = types.listOf types.str; default = []; description = "array of admins"; }; committee = mkOption rec { type = types.listOf types.str; default = []; description = "array of committee members"; }; lifetime = mkOption rec { type = types.listOf types.str; default = []; description = "array of lifetime users"; }; banned = mkOption rec { type = types.listOf types.str; default = []; description = "array of banned users"; }; restricted = mkOption rec { type = types.listOf types.str; default = []; description = "array of restricted user accounts"; }; }; host_port = mkOption rec { type = types.str; default = "127.0.0.1:8087"; description = "host/port for teh server tro run on"; }; # specific for teh program running user = mkOption rec { type = types.str; default = "${package_name}"; description = "The user to run the service"; }; home = mkOption rec { type = types.str; default = "/etc/${cfg.prefix}${package_name}"; description = "The home for the user"; }; prefix = mkOption rec { type = types.str; default = "skynet_"; example = default; description = "The prefix used to name service/folders"; }; }; config = mkIf cfg.enable { users.groups."${cfg.user}" = { }; users.users."${cfg.user}" = { createHome = true; isSystemUser = true; home = "${cfg.home}"; group = "${cfg.user}"; }; systemd.services = { # main service "${cfg.user}" = { description = desc; wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; wants = [ ]; environment = environment_config; serviceConfig = { # because we are storing data we need a home for it User = "${cfg.user}"; Group = "${cfg.user}"; Restart = "always"; ExecStart = "${self.defaultPackage."${system}"}/bin/${package_name}"; # multiple files EnvironmentFile = [ "${cfg.env.ldap}" "${cfg.env.discord}" "${cfg.env.mail}" "${cfg.env.wolves}" ]; }; restartTriggers = [ "${cfg.env.ldap}" "${cfg.env.discord}" "${cfg.env.mail}" "${cfg.env.wolves}" ]; }; } // serviceGenerator scripts; # timers to run the above services systemd.timers = timerGenerator scripts; }; }; }); }