···
1
+
{ pkgs, config, lib, ... }:
4
+
cfg = config.services.cockpit;
5
+
inherit (lib) types mkEnableOption mkOption mkIf mdDoc literalMD mkPackageOptionMD;
6
+
settingsFormat = pkgs.formats.ini {};
10
+
enable = mkEnableOption (mdDoc "Cockpit");
12
+
package = mkPackageOptionMD pkgs "Cockpit" {
13
+
default = [ "cockpit" ];
16
+
settings = lib.mkOption {
17
+
type = settingsFormat.type;
21
+
description = mdDoc ''
22
+
Settings for cockpit that will be saved in /etc/cockpit/cockpit.conf.
24
+
See the [documentation](https://cockpit-project.org/guide/latest/cockpit.conf.5.html), that is also available with `man cockpit.conf.5` for details.
29
+
description = mdDoc "Port where cockpit will listen.";
34
+
openFirewall = mkOption {
35
+
description = mdDoc "Open port for cockpit.";
41
+
config = mkIf cfg.enable {
43
+
# expose cockpit-bridge system-wide
44
+
environment.systemPackages = [ cfg.package ];
46
+
# allow cockpit to find its plugins
47
+
environment.pathsToLink = [ "/share/cockpit" ];
49
+
# generate cockpit settings
50
+
environment.etc."cockpit/cockpit.conf".source = settingsFormat.generate "cockpit.conf" cfg.settings;
52
+
security.pam.services.cockpit = {};
54
+
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
56
+
# units are in reverse sort order if you ls $out/lib/systemd/system
57
+
# all these units are basically verbatim translated from upstream
59
+
# Translation from $out/lib/systemd/system/systemd-cockpithttps.slice
60
+
systemd.slices.system-cockpithttps = {
61
+
description = "Resource limits for all cockpit-ws-https@.service instances";
69
+
# Translation from $out/lib/systemd/system/cockpit-wsinstance-https@.socket
70
+
systemd.sockets."cockpit-wsinstance-https@" = {
72
+
Description = "Socket for Cockpit Web Service https instance %I";
73
+
BindsTo = [ "cockpit.service" "cockpit-wsinstance-https@%i.service" ];
74
+
# clean up the socket after the service exits, to prevent fd leak
75
+
# this also effectively prevents a DoS by starting arbitrarily many sockets, as
76
+
# the services are resource-limited by system-cockpithttps.slice
77
+
Documentation = "man:cockpit-ws(8)";
80
+
ListenStream = "/run/cockpit/wsinstance/https@%i.sock";
81
+
SocketUser = "root";
82
+
SocketMode = "0600";
86
+
# Translation from $out/lib/systemd/system/cockpit-wsinstance-https@.service
87
+
systemd.services."cockpit-wsinstance-https@" = {
88
+
description = "Cockpit Web Service https instance %I";
89
+
bindsTo = [ "cockpit.service"];
90
+
path = [ cfg.package ];
91
+
documentation = [ "man:cockpit-ws(8)" ];
93
+
Slice = "system-cockpithttps.slice";
94
+
ExecStart = "${cfg.package}/libexec/cockpit-ws --for-tls-proxy --port=0";
100
+
# Translation from $out/lib/systemd/system/cockpit-wsinstance-http.socket
101
+
systemd.sockets.cockpit-wsinstance-http = {
103
+
Description = "Socket for Cockpit Web Service http instance";
104
+
BindsTo = "cockpit.service";
105
+
Documentation = "man:cockpit-ws(8)";
108
+
ListenStream = "/run/cockpit/wsinstance/http.sock";
109
+
SocketUser = "root";
110
+
SocketMode = "0600";
114
+
# Translation from $out/lib/systemd/system/cockpit-wsinstance-https-factory.socket
115
+
systemd.sockets.cockpit-wsinstance-https-factory = {
117
+
Description = "Socket for Cockpit Web Service https instance factory";
118
+
BindsTo = "cockpit.service";
119
+
Documentation = "man:cockpit-ws(8)";
122
+
ListenStream = "/run/cockpit/wsinstance/https-factory.sock";
124
+
SocketUser = "root";
125
+
SocketMode = "0600";
129
+
# Translation from $out/lib/systemd/system/cockpit-wsinstance-https-factory@.service
130
+
systemd.services."cockpit-wsinstance-https-factory@" = {
131
+
description = "Cockpit Web Service https instance factory";
132
+
documentation = [ "man:cockpit-ws(8)" ];
133
+
path = [ cfg.package ];
135
+
ExecStart = "${cfg.package}/libexec/cockpit-wsinstance-factory";
140
+
# Translation from $out/lib/systemd/system/cockpit-wsinstance-http.service
141
+
systemd.services."cockpit-wsinstance-http" = {
142
+
description = "Cockpit Web Service http instance";
143
+
bindsTo = [ "cockpit.service" ];
144
+
path = [ cfg.package ];
145
+
documentation = [ "man:cockpit-ws(8)" ];
147
+
ExecStart = "${cfg.package}/libexec/cockpit-ws --no-tls --port=0";
153
+
# Translation from $out/lib/systemd/system/cockpit.socket
154
+
systemd.sockets."cockpit" = {
156
+
Description = "Cockpit Web Service Socket";
157
+
Documentation = "man:cockpit-ws(8)";
158
+
Wants = "cockpit-motd.service";
161
+
ListenStream = cfg.port;
163
+
"-${cfg.package}/share/cockpit/motd/update-motd \"\" localhost"
164
+
"-${pkgs.coreutils}/bin/ln -snf active.motd /run/cockpit/motd"
166
+
ExecStopPost = "-${pkgs.coreutils}/bin/ln -snf inactive.motd /run/cockpit/motd";
168
+
wantedBy = [ "sockets.target" ];
171
+
# Translation from $out/lib/systemd/system/cockpit.service
172
+
systemd.services."cockpit" = {
173
+
description = "Cockpit Web Service";
174
+
documentation = [ "man:cockpit-ws(8)" ];
175
+
restartIfChanged = true;
176
+
path = with pkgs; [ coreutils cfg.package ];
177
+
requires = [ "cockpit.socket" "cockpit-wsinstance-http.socket" "cockpit-wsinstance-https-factory.socket" ];
178
+
after = [ "cockpit-wsinstance-http.socket" "cockpit-wsinstance-https-factory.socket" ];
180
+
G_MESSAGES_DEBUG = "cockpit-ws,cockpit-bridge";
183
+
RuntimeDirectory="cockpit/tls";
185
+
# cockpit-tls runs in a more constrained environment, these + means that these commands
186
+
# will run with full privilege instead of inside that constrained environment
187
+
# See https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart= for details
188
+
"+${cfg.package}/libexec/cockpit-certificate-ensure --for-cockpit-tls"
190
+
ExecStart = "${cfg.package}/libexec/cockpit-tls";
193
+
NoNewPrivileges = true;
194
+
ProtectSystem = "strict";
195
+
ProtectHome = true;
197
+
PrivateDevices = true;
198
+
ProtectKernelTunables = true;
199
+
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
200
+
MemoryDenyWriteExecute = true;
204
+
# Translation from $out/lib/systemd/system/cockpit-motd.service
205
+
# This part basically implements a motd state machine:
206
+
# - If cockpit.socket is enabled then /run/cockpit/motd points to /run/cockpit/active.motd
207
+
# - If cockpit.socket is disabled then /run/cockpit/motd points to /run/cockpit/inactive.motd
208
+
# - As cockpit.socket is disabled by default, /run/cockpit/motd points to /run/cockpit/inactive.motd
209
+
# /run/cockpit/active.motd is generated dynamically by cockpit-motd.service
210
+
systemd.services."cockpit-motd" = {
211
+
path = with pkgs; [ nettools ];
214
+
ExecStart = "${cfg.package}/share/cockpit/motd/update-motd";
216
+
description = "Cockpit motd updater service";
217
+
documentation = [ "man:cockpit-ws(8)" ];
218
+
wants = [ "network.target" ];
219
+
after = [ "network.target" "cockpit.socket" ];
222
+
systemd.tmpfiles.rules = [ # From $out/lib/tmpfiles.d/cockpit-tmpfiles.conf
223
+
"C /run/cockpit/inactive.motd 0640 root root - ${cfg.package}/share/cockpit/motd/inactive.motd"
224
+
"f /run/cockpit/active.motd 0640 root root -"
225
+
"L+ /run/cockpit/motd - - - - inactive.motd"
226
+
"d /etc/cockpit/ws-certs.d 0600 root root 0"
230
+
meta.maintainers = pkgs.cockpit.meta.maintainers;