at 25.11-pre 4.5 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7let 8 inherit (lib) mkOption types mkIf; 9 cfg = config.services.atuin; 10in 11{ 12 options = { 13 services.atuin = { 14 enable = lib.mkEnableOption "Atuin server for shell history sync"; 15 16 package = lib.mkPackageOption pkgs "atuin" { }; 17 18 openRegistration = mkOption { 19 type = types.bool; 20 default = false; 21 description = "Allow new user registrations with the atuin server."; 22 }; 23 24 path = mkOption { 25 type = types.str; 26 default = ""; 27 description = "A path to prepend to all the routes of the server."; 28 }; 29 30 host = mkOption { 31 type = types.str; 32 default = "127.0.0.1"; 33 description = "The host address the atuin server should listen on."; 34 }; 35 36 maxHistoryLength = mkOption { 37 type = types.int; 38 default = 8192; 39 description = "The max length of each history item the atuin server should store."; 40 }; 41 42 port = mkOption { 43 type = types.port; 44 default = 8888; 45 description = "The port the atuin server should listen on."; 46 }; 47 48 openFirewall = mkOption { 49 type = types.bool; 50 default = false; 51 description = "Open ports in the firewall for the atuin server."; 52 }; 53 54 database = { 55 createLocally = mkOption { 56 type = types.bool; 57 default = true; 58 description = "Create the database and database user locally."; 59 }; 60 61 uri = mkOption { 62 type = types.nullOr types.str; 63 default = "postgresql:///atuin?host=/run/postgresql"; 64 example = "postgresql://atuin@localhost:5432/atuin"; 65 description = '' 66 URI to the database. 67 Can be set to null in which case ATUIN_DB_URI should be set through an EnvironmentFile 68 ''; 69 }; 70 }; 71 }; 72 }; 73 74 config = mkIf cfg.enable { 75 assertions = [ 76 { 77 assertion = cfg.database.createLocally -> config.services.postgresql.enable; 78 message = "Postgresql must be enabled to create a local database"; 79 } 80 ]; 81 82 services.postgresql = mkIf cfg.database.createLocally { 83 enable = true; 84 ensureUsers = [ 85 { 86 name = "atuin"; 87 ensureDBOwnership = true; 88 } 89 ]; 90 ensureDatabases = [ "atuin" ]; 91 }; 92 93 systemd.services.atuin = { 94 description = "atuin server"; 95 requires = lib.optionals cfg.database.createLocally [ "postgresql.service" ]; 96 after = [ "network.target" ] ++ lib.optionals cfg.database.createLocally [ "postgresql.service" ]; 97 wantedBy = [ "multi-user.target" ]; 98 99 serviceConfig = { 100 ExecStart = "${lib.getExe cfg.package} server start"; 101 RuntimeDirectory = "atuin"; 102 RuntimeDirectoryMode = "0700"; 103 DynamicUser = true; 104 105 # Hardening 106 CapabilityBoundingSet = ""; 107 LockPersonality = true; 108 NoNewPrivileges = true; 109 MemoryDenyWriteExecute = true; 110 PrivateDevices = true; 111 PrivateMounts = true; 112 PrivateTmp = true; 113 PrivateUsers = true; 114 ProcSubset = "pid"; 115 ProtectClock = true; 116 ProtectControlGroups = true; 117 ProtectHome = true; 118 ProtectHostname = true; 119 ProtectKernelLogs = true; 120 ProtectKernelModules = true; 121 ProtectKernelTunables = true; 122 ProtectProc = "invisible"; 123 ProtectSystem = "full"; 124 RemoveIPC = true; 125 RestrictAddressFamilies = [ 126 "AF_INET" 127 "AF_INET6" 128 # Required for connecting to database sockets, 129 "AF_UNIX" 130 ]; 131 RestrictNamespaces = true; 132 RestrictRealtime = true; 133 RestrictSUIDSGID = true; 134 SystemCallArchitectures = "native"; 135 SystemCallFilter = [ 136 "@system-service" 137 "~@privileged" 138 ]; 139 UMask = "0077"; 140 }; 141 142 environment = 143 { 144 ATUIN_HOST = cfg.host; 145 ATUIN_PORT = toString cfg.port; 146 ATUIN_MAX_HISTORY_LENGTH = toString cfg.maxHistoryLength; 147 ATUIN_OPEN_REGISTRATION = lib.boolToString cfg.openRegistration; 148 ATUIN_PATH = cfg.path; 149 ATUIN_CONFIG_DIR = "/run/atuin"; # required to start, but not used as configuration is via environment variables 150 } 151 // lib.optionalAttrs (cfg.database.uri != null) { 152 ATUIN_DB_URI = cfg.database.uri; 153 }; 154 }; 155 156 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; 157 }; 158}