blob: da6fd02c9a84a105c735ccb52155acf3e60b9705 (
plain) (
blame)
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
|
{
config,
pkgs,
lib,
...
}: let
inherit (lib) mkOption types mkIf;
cfg = config.services.turtle;
in {
options = {
services.turtle = {
enable = lib.mkEnableOption "turtle server for shell history sync";
package = lib.mkPackageOption pkgs "turtle" {};
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = "The host address the turtle server should listen on.";
};
port = mkOption {
type = types.port;
default = 8888;
description = "The port the turtle server should listen on.";
};
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:///turtle?host=/run/postgresql";
example = "postgresql://turtle@localhost:5432/turtle";
description = ''
URI to the database.
Can be set to null in which case ATUIN_DB_URI should be set through an EnvironmentFile
'';
};
};
environmentFile = lib.mkOption {
type = lib.types.nullOr lib.types.externalPath;
default = null;
description = ''
Environment file, used to set any secret ATUIN_* environment variables, such as ATUIN_DB_URI containing a password.
See https://docs.atuin.sh/cli/self-hosting/server-setup/#configuration for available environment variables.
'';
};
};
};
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 = "turtle";
ensureDBOwnership = true;
}
];
ensureDatabases = ["turtle"];
};
systemd.services.turtle = {
description = "turtle server";
requires = lib.optionals cfg.database.createLocally ["postgresql.target"];
after =
[
"network-online.target"
]
++ lib.optionals cfg.database.createLocally ["postgresql.target"];
wants =
[
"network-online.target"
]
++ lib.optionals cfg.database.createLocally ["postgresql.target"];
wantedBy = ["multi-user.target"];
serviceConfig = {
ExecStart = "${lib.getExe' cfg.package "atuin"} server start";
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [cfg.environmentFile];
RuntimeDirectory = "turtle";
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_CONFIG_DIR = "/run/turtle"; # required to start, but not used as configuration is via environment variables
}
// lib.optionalAttrs (cfg.database.uri != null) {ATUIN_DB_URI = cfg.database.uri;};
};
};
}
|