blob: e5bc0f5c1aeedfca7e67c32eabe3a5290ccf3cee (
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
|
{ lib, pkgs, config, ... }:
let
package = pkgs.pure-ftpd.override { ldapFtpId = "immaeFtp"; };
pure-ftpd-enabled = config.myServices.ftp.pure-ftpd.enable;
proftpd-enabled = config.myServices.ftp.proftpd.enable;
in
{
options = {
myServices.ftp.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable ftp.
'';
};
myServices.ftp.pure-ftpd.enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable pure-ftpd.
'';
};
myServices.ftp.proftpd.enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Whether to enable proftpd.
'';
};
};
config = lib.mkIf config.myServices.ftp.enable {
services.borgBackup.profiles.global.ignoredPaths = [
"ftp/test_ftp"
"proftpd/authorized_keys"
];
myServices.dns.zones."immae.eu".subdomains.ftp =
with config.myServices.dns.helpers; ips servers.eldiron.ips.main;
myServices.chatonsProperties.services.espace-de-stockage = {
file.datetime = "2022-08-22T01:00:00";
service = {
name = "Espace de stockage";
description = "Compte FTP/SFTP";
logo = if pure-ftpd-enabled
then "https://www.pureftpd.org/project/pure-ftpd/images/favicon.png"
else if proftpd-enabled
then "http://proftpd.org/proftpd.png"
else "";
website = "ftp.immae.eu";
status.level = "OK";
status.description = "OK";
registration."" = ["MEMBER" "CLIENT"];
registration.load = "OPEN";
install.type = "PACKAGE";
};
software = if pure-ftpd-enabled then {
name = "Pure-ftpd";
website = "https://www.pureftpd.org/project/pure-ftpd/";
license.url = "https://github.com/jedisct1/pure-ftpd/blob/master/COPYING";
license.name = "MIT Licence";
version = package.version;
source.url = "https://github.com/jedisct1/pure-ftpd/";
modules = "openssh";
} else if proftpd-enabled then {
name = "ProFTPD";
website = "http://proftpd.org/";
license.url = "https://github.com/proftpd/proftpd/blob/master/COPYING";
license.name = "GNU General Public License v2.0";
version = pkgs.proftpd.version;
source.url = "https://github.com/proftpd/proftpd/";
modules = "openssh";
} else {};
};
#myServices.chatonsProperties.services.ftp = {
# file.datetime = "2022-08-22T01:00:00";
# service = {
# name = "Comptes FTP";
# description = "Compte FTP/SFTP";
# logo = if pure-ftpd-enabled
# then "https://www.pureftpd.org/project/pure-ftpd/images/favicon.png"
# else if proftpd-enabled
# then "http://proftpd.org/proftpd.png"
# else "";
# website = "ftp.immae.eu";
# status.level = "OK";
# status.description = "OK";
# registration."" = ["MEMBER" "CLIENT"];
# registration.load = "OPEN";
# install.type = "PACKAGE";
# };
# software = if pure-ftpd-enabled then {
# name = "Pure-ftpd";
# website = "https://www.pureftpd.org/project/pure-ftpd/";
# license.url = "https://github.com/jedisct1/pure-ftpd/blob/master/COPYING";
# license.name = "MIT Licence";
# version = package.version;
# source.url = "https://github.com/jedisct1/pure-ftpd/";
# } else if proftpd-enabled then {
# name = "ProFTPD";
# website = "http://proftpd.org/";
# license.url = "https://github.com/proftpd/proftpd/blob/master/COPYING";
# license.name = "GNU General Public License v2.0";
# version = pkgs.proftpd.version;
# source.url = "https://github.com/proftpd/proftpd/";
# } else {};
#};
security.acme.certs."ftp" = {
domain = "eldiron.immae.eu";
# FIXME: make it global
extraLegoRunFlags = ["--preferred-chain" "ISRG Root X1"];
extraLegoRenewFlags = ["--preferred-chain" "ISRG Root X1"];
postRun = (lib.optionalString pure-ftpd-enabled ''
systemctl restart pure-ftpd.service
'') + (lib.optionalString proftpd-enabled ''
systemctl restart proftpd.service
'');
extraDomainNames = [ "ftp.immae.eu" ];
};
networking = {
firewall = {
allowedTCPPorts = [ 21 115 ];
allowedTCPPortRanges = [ { from = 40000; to = 50000; } ];
};
};
users.users.ftp = {
uid = config.ids.uids.ftp; # 8
group = "ftp";
description = "Anonymous FTP user";
home = "/homeless-shelter";
extraGroups = [ "keys" ];
};
users.groups.ftp.gid = config.ids.gids.ftp;
system.activationScripts.ftp = ''
install -m 0755 -o ftp -g ftp -d /var/lib/ftp
'' + (lib.optionalString proftpd-enabled ''
install -m 0755 -o nobody -g nogroup -d /var/lib/proftpd/authorized_keys
'');
secrets.keys."pure-ftpd-ldap" = lib.mkIf pure-ftpd-enabled {
permissions = "0400";
user = "ftp";
group = "ftp";
text = ''
LDAPServer ${config.myEnv.ftp.ldap.host}
LDAPPort 389
LDAPUseTLS True
LDAPBaseDN ${config.myEnv.ftp.ldap.base}
LDAPBindDN ${config.myEnv.ftp.ldap.dn}
LDAPBindPW ${config.myEnv.ftp.ldap.password}
LDAPDefaultUID 500
LDAPForceDefaultUID False
LDAPDefaultGID 100
LDAPForceDefaultGID False
LDAPFilter ${config.myEnv.ftp.ldap.pure-ftpd_filter}
LDAPAuthMethod BIND
# Pas de possibilite de donner l'Uid/Gid !
# Compile dans pure-ftpd directement avec immaeFtpUid / immaeFtpGid
LDAPHomeDir immaeFtpDirectory
'';
};
secrets.keys."proftpd-ldap.conf" = lib.mkIf proftpd-enabled {
permissions = "0400";
user = "ftp";
group = "ftp";
text = ''
LDAPServer ldaps://${config.myEnv.ftp.ldap.host}:636/??sub
LDAPUseTLS on
LDAPAuthBinds on
LDAPBindDN "${config.myEnv.ftp.ldap.dn}" "${config.myEnv.ftp.ldap.password}"
LDAPSearchScope subtree
LDAPAuthBinds on
LDAPDefaultGID 100
LDAPDefaultUID 500
LDAPForceDefaultUID off
LDAPForceDefaultGID off
LDAPAttr gidNumber immaeFtpGid
LDAPAttr uidNumber immaeFtpUid
LDAPAttr homeDirectory immaeFtpDirectory
LDAPUsers "${config.myEnv.ftp.ldap.base}" "${config.myEnv.ftp.ldap.proftpd_filter}"
LDAPGroups "${config.myEnv.ftp.ldap.base}"
'';
};
services.filesWatcher.pure-ftpd = lib.mkIf pure-ftpd-enabled {
restart = true;
paths = [ config.secrets.fullPaths."pure-ftpd-ldap" ];
};
services.filesWatcher.proftpd = lib.mkIf proftpd-enabled {
restart = true;
paths = [ config.secrets.fullPaths."proftpd-ldap.conf" ];
};
systemd.services.pure-ftpd = let
configFile = pkgs.writeText "pure-ftpd.conf" ''
PassivePortRange 40000 50000
Bind 42
ChrootEveryone yes
CreateHomeDir yes
BrokenClientsCompatibility yes
MaxClientsNumber 50
Daemonize yes
MaxClientsPerIP 8
VerboseLog no
DisplayDotFiles yes
AnonymousOnly no
NoAnonymous no
SyslogFacility ftp
DontResolve yes
MaxIdleTime 15
LDAPConfigFile ${config.secrets.fullPaths."pure-ftpd-ldap"}
LimitRecursion 10000 8
AnonymousCanCreateDirs no
MaxLoad 4
AntiWarez yes
Umask 133:022
# ftp
MinUID 8
AllowUserFXP no
AllowAnonymousFXP no
ProhibitDotFilesWrite no
ProhibitDotFilesRead no
AutoRename no
AnonymousCantUpload no
MaxDiskUsage 99
CustomerProof yes
TLS 1
CertFile ${config.security.acme.certs.ftp.directory}/full.pem
'';
in lib.mkIf pure-ftpd-enabled {
description = "Pure-FTPd server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig.ExecStart = "${package}/bin/pure-ftpd ${configFile}";
serviceConfig.Type = "forking";
serviceConfig.PIDFile = "/run/pure-ftpd.pid";
};
systemd.services.proftpd = let
configFile = pkgs.writeText "proftpd.conf" ''
ServerName "ProFTPD"
ServerType standalone
DefaultServer on
Port 21
UseIPv6 on
Umask 022
MaxInstances 30
MaxClients 50
MaxClientsPerHost 8
# Set the user and group under which the server will run.
User ftp
Group ftp
CreateHome on
DefaultRoot ~
AllowOverwrite on
TLSEngine on
TLSRequired off
TLSProtocol TLSv1.1 TLSv1.2 TLSv1.3
TLSCertificateChainFile ${config.security.acme.certs.ftp.directory}/fullchain.pem
TLSECCertificateFile ${config.security.acme.certs.ftp.directory}/cert.pem
TLSECCertificateKeyFile ${config.security.acme.certs.ftp.directory}/key.pem
TLSRenegotiate none
PidFile /run/proftpd/proftpd.pid
ScoreboardFile /run/proftpd/proftpd.scoreboard
PassivePorts 40000 50000
#DebugLevel 10
Include ${config.secrets.fullPaths."proftpd-ldap.conf"}
RequireValidShell off
# Bar use of SITE CHMOD by default
<Limit SITE_CHMOD>
DenyAll
</Limit>
<VirtualHost 0.0.0.0>
Umask 022
Port 115
SFTPEngine on
CreateHome on
DefaultRoot ~
AllowOverwrite on
SFTPHostKey /etc/ssh/ssh_host_ed25519_key
SFTPHostKey /etc/ssh/ssh_host_rsa_key
Include ${config.secrets.fullPaths."proftpd-ldap.conf"}
RequireValidShell off
SFTPAuthorizedUserKeys file:/var/lib/proftpd/authorized_keys/%u
SFTPAuthMethods password publickey
SFTPOptions IgnoreSFTPSetOwners
AllowChrootSymlinks off
</VirtualHost>
'';
in lib.mkIf proftpd-enabled {
description = "ProFTPD server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig.ExecStart = "${pkgs.proftpd}/bin/proftpd -c ${configFile}";
serviceConfig.Type = "forking";
serviceConfig.PIDFile = "/run/proftpd/proftpd.pid";
serviceConfig.RuntimeDirectory = "proftpd";
};
services.cron.systemCronJobs = lib.mkIf proftpd-enabled [
"*/2 * * * * nobody ${./ftp_sync.sh}"
];
myServices.monitoring.fromMasterActivatedPlugins = [ "ftp" ];
myServices.monitoring.fromMasterObjects.service = [
{
service_description = "ftp has access to database for authentication";
host_name = config.hostEnv.fqdn;
use = "external-service";
check_command = "check_ftp_database";
servicegroups = "webstatus-remote-services";
_webstatus_name = "FTP";
_webstatus_url = "ftp.immae.eu";
}
];
};
}
|