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