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