-
-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #234998 from yayayayaka/backport-184586-to-release…
…-23.05 [23.05] nixos/sftpgo: init, nixosTests.sftpgo: init
- Loading branch information
Showing
5 changed files
with
769 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,375 @@ | ||
{ options, config, lib, pkgs, utils, ... }: | ||
|
||
with lib; | ||
|
||
let | ||
cfg = config.services.sftpgo; | ||
defaultUser = "sftpgo"; | ||
settingsFormat = pkgs.formats.json {}; | ||
configFile = settingsFormat.generate "sftpgo.json" cfg.settings; | ||
hasPrivilegedPorts = any (port: port > 0 && port < 1024) ( | ||
catAttrs "port" (cfg.settings.httpd.bindings | ||
++ cfg.settings.ftpd.bindings | ||
++ cfg.settings.sftpd.bindings | ||
++ cfg.settings.webdavd.bindings | ||
) | ||
); | ||
in | ||
{ | ||
options.services.sftpgo = { | ||
enable = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = mdDoc "sftpgo"; | ||
}; | ||
|
||
package = mkOption { | ||
type = types.package; | ||
default = pkgs.sftpgo; | ||
defaultText = literalExpression "pkgs.sftpgo"; | ||
description = mdDoc '' | ||
Which SFTPGo package to use. | ||
''; | ||
}; | ||
|
||
extraArgs = mkOption { | ||
type = with types; listOf str; | ||
default = []; | ||
description = mdDoc '' | ||
Additional command line arguments to pass to the sftpgo daemon. | ||
''; | ||
example = [ "--log-level" "info" ]; | ||
}; | ||
|
||
dataDir = mkOption { | ||
type = types.str; | ||
default = "/var/lib/sftpgo"; | ||
description = mdDoc '' | ||
The directory where SFTPGo stores its data files. | ||
''; | ||
}; | ||
|
||
user = mkOption { | ||
type = types.str; | ||
default = defaultUser; | ||
description = mdDoc '' | ||
User account name under which SFTPGo runs. | ||
''; | ||
}; | ||
|
||
group = mkOption { | ||
type = types.str; | ||
default = defaultUser; | ||
description = mdDoc '' | ||
Group name under which SFTPGo runs. | ||
''; | ||
}; | ||
|
||
loadDataFile = mkOption { | ||
default = null; | ||
type = with types; nullOr path; | ||
description = mdDoc '' | ||
Path to a json file containing users and folders to load (or update) on startup. | ||
Check the [documentation](https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md) | ||
for the `--loaddata-from` command line argument for more info. | ||
''; | ||
}; | ||
|
||
settings = mkOption { | ||
default = {}; | ||
description = mdDoc '' | ||
The primary sftpgo configuration. See the | ||
[configuration reference](https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md) | ||
for possible values. | ||
''; | ||
type = with types; submodule { | ||
freeformType = settingsFormat.type; | ||
options = { | ||
httpd.bindings = mkOption { | ||
default = []; | ||
description = mdDoc '' | ||
Configure listen addresses and ports for httpd. | ||
''; | ||
type = types.listOf (types.submodule { | ||
freeformType = settingsFormat.type; | ||
options = { | ||
address = mkOption { | ||
type = types.str; | ||
default = "127.0.0.1"; | ||
description = mdDoc '' | ||
Network listen address. Leave blank to listen on all available network interfaces. | ||
On *NIX you can specify an absolute path to listen on a Unix-domain socket. | ||
''; | ||
}; | ||
|
||
port = mkOption { | ||
type = types.port; | ||
default = 8080; | ||
description = mdDoc '' | ||
The port for serving HTTP(S) requests. | ||
Setting the port to `0` disables listening on this interface binding. | ||
''; | ||
}; | ||
|
||
enable_web_admin = mkOption { | ||
type = types.bool; | ||
default = true; | ||
description = mdDoc '' | ||
Enable the built-in web admin for this interface binding. | ||
''; | ||
}; | ||
|
||
enable_web_client = mkOption { | ||
type = types.bool; | ||
default = true; | ||
description = mdDoc '' | ||
Enable the built-in web client for this interface binding. | ||
''; | ||
}; | ||
}; | ||
}); | ||
}; | ||
|
||
ftpd.bindings = mkOption { | ||
default = []; | ||
description = mdDoc '' | ||
Configure listen addresses and ports for ftpd. | ||
''; | ||
type = types.listOf (types.submodule { | ||
freeformType = settingsFormat.type; | ||
options = { | ||
address = mkOption { | ||
type = types.str; | ||
default = "127.0.0.1"; | ||
description = mdDoc '' | ||
Network listen address. Leave blank to listen on all available network interfaces. | ||
On *NIX you can specify an absolute path to listen on a Unix-domain socket. | ||
''; | ||
}; | ||
|
||
port = mkOption { | ||
type = types.port; | ||
default = 0; | ||
description = mdDoc '' | ||
The port for serving FTP requests. | ||
Setting the port to `0` disables listening on this interface binding. | ||
''; | ||
}; | ||
}; | ||
}); | ||
}; | ||
|
||
sftpd.bindings = mkOption { | ||
default = []; | ||
description = mdDoc '' | ||
Configure listen addresses and ports for sftpd. | ||
''; | ||
type = types.listOf (types.submodule { | ||
freeformType = settingsFormat.type; | ||
options = { | ||
address = mkOption { | ||
type = types.str; | ||
default = "127.0.0.1"; | ||
description = mdDoc '' | ||
Network listen address. Leave blank to listen on all available network interfaces. | ||
On *NIX you can specify an absolute path to listen on a Unix-domain socket. | ||
''; | ||
}; | ||
|
||
port = mkOption { | ||
type = types.port; | ||
default = 0; | ||
description = mdDoc '' | ||
The port for serving SFTP requests. | ||
Setting the port to `0` disables listening on this interface binding. | ||
''; | ||
}; | ||
}; | ||
}); | ||
}; | ||
|
||
webdavd.bindings = mkOption { | ||
default = []; | ||
description = mdDoc '' | ||
Configure listen addresses and ports for webdavd. | ||
''; | ||
type = types.listOf (types.submodule { | ||
freeformType = settingsFormat.type; | ||
options = { | ||
address = mkOption { | ||
type = types.str; | ||
default = "127.0.0.1"; | ||
description = mdDoc '' | ||
Network listen address. Leave blank to listen on all available network interfaces. | ||
On *NIX you can specify an absolute path to listen on a Unix-domain socket. | ||
''; | ||
}; | ||
|
||
port = mkOption { | ||
type = types.port; | ||
default = 0; | ||
description = mdDoc '' | ||
The port for serving WebDAV requests. | ||
Setting the port to `0` disables listening on this interface binding. | ||
''; | ||
}; | ||
}; | ||
}); | ||
}; | ||
|
||
smtp = mkOption { | ||
default = {}; | ||
description = mdDoc '' | ||
SMTP configuration section. | ||
''; | ||
type = types.submodule { | ||
freeformType = settingsFormat.type; | ||
options = { | ||
host = mkOption { | ||
type = types.str; | ||
default = ""; | ||
description = mdDoc '' | ||
Location of SMTP email server. Leave empty to disable email sending capabilities. | ||
''; | ||
}; | ||
|
||
port = mkOption { | ||
type = types.port; | ||
default = 465; | ||
description = mdDoc "Port of the SMTP Server."; | ||
}; | ||
|
||
encryption = mkOption { | ||
type = types.enum [ 0 1 2 ]; | ||
default = 1; | ||
description = mdDoc '' | ||
Encryption scheme: | ||
- `0`: No encryption | ||
- `1`: TLS | ||
- `2`: STARTTLS | ||
''; | ||
}; | ||
|
||
auth_type = mkOption { | ||
type = types.enum [ 0 1 2 ]; | ||
default = 0; | ||
description = mdDoc '' | ||
- `0`: Plain | ||
- `1`: Login | ||
- `2`: CRAM-MD5 | ||
''; | ||
}; | ||
|
||
user = mkOption { | ||
type = types.str; | ||
default = "sftpgo"; | ||
description = mdDoc "SMTP username."; | ||
}; | ||
|
||
from = mkOption { | ||
type = types.str; | ||
default = "SFTPGo <sftpgo@example.com>"; | ||
description = mdDoc '' | ||
From address. | ||
''; | ||
}; | ||
}; | ||
}; | ||
}; | ||
}; | ||
}; | ||
}; | ||
}; | ||
|
||
config = mkIf cfg.enable { | ||
services.sftpgo.settings = (mapAttrs (name: mkDefault) { | ||
ftpd.bindings = [{ port = 0; }]; | ||
httpd.bindings = [{ port = 0; }]; | ||
sftpd.bindings = [{ port = 0; }]; | ||
webdavd.bindings = [{ port = 0; }]; | ||
httpd.openapi_path = "${cfg.package}/share/sftpgo/openapi"; | ||
httpd.templates_path = "${cfg.package}/share/sftpgo/templates"; | ||
httpd.static_files_path = "${cfg.package}/share/sftpgo/static"; | ||
smtp.templates_path = "${cfg.package}/share/sftpgo/templates"; | ||
}); | ||
|
||
users = optionalAttrs (cfg.user == defaultUser) { | ||
users = { | ||
${defaultUser} = { | ||
description = "SFTPGo system user"; | ||
isSystemUser = true; | ||
group = defaultUser; | ||
home = cfg.dataDir; | ||
}; | ||
}; | ||
|
||
groups = { | ||
${defaultUser} = { | ||
members = [ defaultUser ]; | ||
}; | ||
}; | ||
}; | ||
|
||
systemd.services.sftpgo = { | ||
description = "SFTPGo daemon"; | ||
after = [ "network.target" ]; | ||
wantedBy = [ "multi-user.target" ]; | ||
|
||
environment = { | ||
SFTPGO_CONFIG_FILE = mkDefault configFile; | ||
SFTPGO_LOG_FILE_PATH = mkDefault ""; # log to journal | ||
SFTPGO_LOADDATA_FROM = mkIf (cfg.loadDataFile != null) cfg.loadDataFile; | ||
}; | ||
|
||
serviceConfig = mkMerge [ | ||
({ | ||
Type = "simple"; | ||
User = cfg.user; | ||
Group = cfg.group; | ||
WorkingDirectory = cfg.dataDir; | ||
ReadWritePaths = [ cfg.dataDir ]; | ||
LimitNOFILE = 8192; # taken from upstream | ||
KillMode = "mixed"; | ||
ExecStart = "${cfg.package}/bin/sftpgo serve ${utils.escapeSystemdExecArgs cfg.extraArgs}"; | ||
ExecReload = "${pkgs.util-linux}/bin/kill -s HUP $MAINPID"; | ||
|
||
# Service hardening | ||
CapabilityBoundingSet = [ (optionalString hasPrivilegedPorts "CAP_NET_BIND_SERVICE") ]; | ||
DevicePolicy = "closed"; | ||
LockPersonality = true; | ||
NoNewPrivileges = true; | ||
PrivateDevices = true; | ||
PrivateTmp = true; | ||
ProcSubset = "pid"; | ||
ProtectClock = true; | ||
ProtectControlGroups = true; | ||
ProtectHome = true; | ||
ProtectHostname = true; | ||
ProtectKernelLogs = true; | ||
ProtectKernelModules = true; | ||
ProtectKernelTunables = true; | ||
ProtectProc = "invisible"; | ||
ProtectSystem = "strict"; | ||
RemoveIPC = true; | ||
RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX"; | ||
RestrictNamespaces = true; | ||
RestrictRealtime = true; | ||
RestrictSUIDSGID = true; | ||
SystemCallArchitectures = "native"; | ||
SystemCallFilter = [ "@system-service" "~@privileged" ]; | ||
UMask = "0077"; | ||
}) | ||
(mkIf hasPrivilegedPorts { | ||
AmbientCapabilities = "CAP_NET_BIND_SERVICE"; | ||
}) | ||
(mkIf (cfg.dataDir == options.services.sftpgo.dataDir.default) { | ||
StateDirectory = baseNameOf cfg.dataDir; | ||
}) | ||
]; | ||
}; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.