]>
Commit | Line | Data |
---|---|---|
ab8f306d | 1 | { lib, pkgs, config, ... }: |
fe696f35 IB |
2 | let |
3 | package = pkgs.pure-ftpd.override { ldapFtpId = "immaeFtp"; }; | |
fcbdf67a IB |
4 | pure-ftpd-enabled = config.myServices.ftp.pure-ftpd.enable; |
5 | proftpd-enabled = config.myServices.ftp.proftpd.enable; | |
fe696f35 | 6 | in |
439049e5 IB |
7 | { |
8 | options = { | |
fcbdf67a IB |
9 | myServices.ftp.enable = lib.mkOption { |
10 | type = lib.types.bool; | |
11 | default = false; | |
12 | description = '' | |
13 | Whether to enable ftp. | |
14 | ''; | |
15 | }; | |
16 | myServices.ftp.pure-ftpd.enable = lib.mkOption { | |
439049e5 IB |
17 | type = lib.types.bool; |
18 | default = false; | |
19 | description = '' | |
20 | Whether to enable pure-ftpd. | |
21 | ''; | |
22 | }; | |
fcbdf67a IB |
23 | myServices.ftp.proftpd.enable = lib.mkOption { |
24 | type = lib.types.bool; | |
25 | default = true; | |
26 | description = '' | |
27 | Whether to enable proftpd. | |
28 | ''; | |
29 | }; | |
439049e5 IB |
30 | }; |
31 | ||
fcbdf67a | 32 | config = lib.mkIf config.myServices.ftp.enable { |
1c90c0dd IB |
33 | services.borgBackup.profiles.global.ignoredPaths = [ |
34 | "ftp/test_ftp" | |
35 | "proftpd/authorized_keys" | |
36 | ]; | |
1a64deeb IB |
37 | myServices.dns.zones."immae.eu".subdomains.ftp = |
38 | with config.myServices.dns.helpers; ips servers.eldiron.ips.main; | |
39 | ||
40 | myServices.chatonsProperties.services.espace-de-stockage = { | |
41 | file.datetime = "2022-08-22T01:00:00"; | |
42 | service = { | |
43 | name = "Espace de stockage"; | |
44 | description = "Compte FTP/SFTP"; | |
45 | logo = if pure-ftpd-enabled | |
46 | then "https://www.pureftpd.org/project/pure-ftpd/images/favicon.png" | |
47 | else if proftpd-enabled | |
48 | then "http://proftpd.org/proftpd.png" | |
49 | else ""; | |
50 | website = "ftp.immae.eu"; | |
51 | status.level = "OK"; | |
52 | status.description = "OK"; | |
53 | registration."" = ["MEMBER" "CLIENT"]; | |
54 | registration.load = "OPEN"; | |
55 | install.type = "PACKAGE"; | |
56 | }; | |
57 | software = if pure-ftpd-enabled then { | |
58 | name = "Pure-ftpd"; | |
59 | website = "https://www.pureftpd.org/project/pure-ftpd/"; | |
60 | license.url = "https://github.com/jedisct1/pure-ftpd/blob/master/COPYING"; | |
61 | license.name = "MIT Licence"; | |
62 | version = package.version; | |
63 | source.url = "https://github.com/jedisct1/pure-ftpd/"; | |
64 | modules = "openssh"; | |
65 | } else if proftpd-enabled then { | |
66 | name = "ProFTPD"; | |
67 | website = "http://proftpd.org/"; | |
68 | license.url = "https://github.com/proftpd/proftpd/blob/master/COPYING"; | |
69 | license.name = "GNU General Public License v2.0"; | |
70 | version = pkgs.proftpd.version; | |
71 | source.url = "https://github.com/proftpd/proftpd/"; | |
72 | modules = "openssh"; | |
73 | } else {}; | |
74 | }; | |
75 | #myServices.chatonsProperties.services.ftp = { | |
76 | # file.datetime = "2022-08-22T01:00:00"; | |
77 | # service = { | |
78 | # name = "Comptes FTP"; | |
79 | # description = "Compte FTP/SFTP"; | |
80 | # logo = if pure-ftpd-enabled | |
81 | # then "https://www.pureftpd.org/project/pure-ftpd/images/favicon.png" | |
82 | # else if proftpd-enabled | |
83 | # then "http://proftpd.org/proftpd.png" | |
84 | # else ""; | |
85 | # website = "ftp.immae.eu"; | |
86 | # status.level = "OK"; | |
87 | # status.description = "OK"; | |
88 | # registration."" = ["MEMBER" "CLIENT"]; | |
89 | # registration.load = "OPEN"; | |
90 | # install.type = "PACKAGE"; | |
91 | # }; | |
92 | # software = if pure-ftpd-enabled then { | |
93 | # name = "Pure-ftpd"; | |
94 | # website = "https://www.pureftpd.org/project/pure-ftpd/"; | |
95 | # license.url = "https://github.com/jedisct1/pure-ftpd/blob/master/COPYING"; | |
96 | # license.name = "MIT Licence"; | |
97 | # version = package.version; | |
98 | # source.url = "https://github.com/jedisct1/pure-ftpd/"; | |
99 | # } else if proftpd-enabled then { | |
100 | # name = "ProFTPD"; | |
101 | # website = "http://proftpd.org/"; | |
102 | # license.url = "https://github.com/proftpd/proftpd/blob/master/COPYING"; | |
103 | # license.name = "GNU General Public License v2.0"; | |
104 | # version = pkgs.proftpd.version; | |
105 | # source.url = "https://github.com/proftpd/proftpd/"; | |
106 | # } else {}; | |
107 | #}; | |
108 | security.acme.certs."ftp" = { | |
439049e5 | 109 | domain = "eldiron.immae.eu"; |
1a64deeb IB |
110 | # FIXME: make it global |
111 | extraLegoRunFlags = ["--preferred-chain" "ISRG Root X1"]; | |
112 | extraLegoRenewFlags = ["--preferred-chain" "ISRG Root X1"]; | |
fcbdf67a | 113 | postRun = (lib.optionalString pure-ftpd-enabled '' |
740f9843 | 114 | systemctl restart pure-ftpd.service |
fcbdf67a IB |
115 | '') + (lib.optionalString proftpd-enabled '' |
116 | systemctl restart proftpd.service | |
117 | ''); | |
1a64deeb | 118 | extraDomainNames = [ "ftp.immae.eu" ]; |
439049e5 IB |
119 | }; |
120 | ||
439049e5 IB |
121 | networking = { |
122 | firewall = { | |
fcbdf67a | 123 | allowedTCPPorts = [ 21 115 ]; |
439049e5 IB |
124 | allowedTCPPortRanges = [ { from = 40000; to = 50000; } ]; |
125 | }; | |
126 | }; | |
127 | ||
258dd18b IB |
128 | users.users.ftp = { |
129 | uid = config.ids.uids.ftp; # 8 | |
130 | group = "ftp"; | |
131 | description = "Anonymous FTP user"; | |
132 | home = "/homeless-shelter"; | |
133 | extraGroups = [ "keys" ]; | |
134 | }; | |
439049e5 IB |
135 | |
136 | users.groups.ftp.gid = config.ids.gids.ftp; | |
137 | ||
fcbdf67a | 138 | system.activationScripts.ftp = '' |
439049e5 | 139 | install -m 0755 -o ftp -g ftp -d /var/lib/ftp |
fcbdf67a IB |
140 | '' + (lib.optionalString proftpd-enabled '' |
141 | install -m 0755 -o nobody -g nogroup -d /var/lib/proftpd/authorized_keys | |
142 | ''); | |
439049e5 | 143 | |
fcbdf67a | 144 | secrets.keys."pure-ftpd-ldap" = lib.mkIf pure-ftpd-enabled { |
926a4007 IB |
145 | permissions = "0400"; |
146 | user = "ftp"; | |
147 | group = "ftp"; | |
148 | text = '' | |
ab8f306d | 149 | LDAPServer ${config.myEnv.ftp.ldap.host} |
439049e5 IB |
150 | LDAPPort 389 |
151 | LDAPUseTLS True | |
ab8f306d IB |
152 | LDAPBaseDN ${config.myEnv.ftp.ldap.base} |
153 | LDAPBindDN ${config.myEnv.ftp.ldap.dn} | |
154 | LDAPBindPW ${config.myEnv.ftp.ldap.password} | |
439049e5 IB |
155 | LDAPDefaultUID 500 |
156 | LDAPForceDefaultUID False | |
157 | LDAPDefaultGID 100 | |
158 | LDAPForceDefaultGID False | |
fcbdf67a | 159 | LDAPFilter ${config.myEnv.ftp.ldap.pure-ftpd_filter} |
439049e5 IB |
160 | |
161 | LDAPAuthMethod BIND | |
162 | ||
926a4007 IB |
163 | # Pas de possibilite de donner l'Uid/Gid ! |
164 | # Compile dans pure-ftpd directement avec immaeFtpUid / immaeFtpGid | |
439049e5 IB |
165 | LDAPHomeDir immaeFtpDirectory |
166 | ''; | |
4c4652aa | 167 | }; |
fcbdf67a IB |
168 | secrets.keys."proftpd-ldap.conf" = lib.mkIf proftpd-enabled { |
169 | permissions = "0400"; | |
170 | user = "ftp"; | |
171 | group = "ftp"; | |
172 | text = '' | |
173 | LDAPServer ldaps://${config.myEnv.ftp.ldap.host}:636/??sub | |
174 | LDAPUseTLS on | |
175 | LDAPAuthBinds on | |
176 | LDAPBindDN "${config.myEnv.ftp.ldap.dn}" "${config.myEnv.ftp.ldap.password}" | |
177 | LDAPSearchScope subtree | |
178 | LDAPAuthBinds on | |
179 | LDAPDefaultGID 100 | |
180 | LDAPDefaultUID 500 | |
181 | LDAPForceDefaultUID off | |
182 | LDAPForceDefaultGID off | |
183 | LDAPAttr gidNumber immaeFtpGid | |
184 | LDAPAttr uidNumber immaeFtpUid | |
185 | LDAPAttr homeDirectory immaeFtpDirectory | |
186 | LDAPUsers "${config.myEnv.ftp.ldap.base}" "${config.myEnv.ftp.ldap.proftpd_filter}" | |
187 | LDAPGroups "${config.myEnv.ftp.ldap.base}" | |
188 | ''; | |
189 | }; | |
926a4007 | 190 | |
fcbdf67a | 191 | services.filesWatcher.pure-ftpd = lib.mkIf pure-ftpd-enabled { |
17f6eae9 | 192 | restart = true; |
da30ae4f | 193 | paths = [ config.secrets.fullPaths."pure-ftpd-ldap" ]; |
17f6eae9 | 194 | }; |
fcbdf67a IB |
195 | services.filesWatcher.proftpd = lib.mkIf proftpd-enabled { |
196 | restart = true; | |
197 | paths = [ config.secrets.fullPaths."proftpd-ldap.conf" ]; | |
198 | }; | |
17f6eae9 | 199 | |
926a4007 | 200 | systemd.services.pure-ftpd = let |
439049e5 IB |
201 | configFile = pkgs.writeText "pure-ftpd.conf" '' |
202 | PassivePortRange 40000 50000 | |
fcbdf67a | 203 | Bind 42 |
439049e5 IB |
204 | ChrootEveryone yes |
205 | CreateHomeDir yes | |
206 | BrokenClientsCompatibility yes | |
207 | MaxClientsNumber 50 | |
208 | Daemonize yes | |
209 | MaxClientsPerIP 8 | |
210 | VerboseLog no | |
211 | DisplayDotFiles yes | |
212 | AnonymousOnly no | |
213 | NoAnonymous no | |
214 | SyslogFacility ftp | |
215 | DontResolve yes | |
216 | MaxIdleTime 15 | |
da30ae4f | 217 | LDAPConfigFile ${config.secrets.fullPaths."pure-ftpd-ldap"} |
439049e5 IB |
218 | LimitRecursion 10000 8 |
219 | AnonymousCanCreateDirs no | |
220 | MaxLoad 4 | |
221 | AntiWarez yes | |
222 | Umask 133:022 | |
223 | # ftp | |
224 | MinUID 8 | |
225 | AllowUserFXP no | |
226 | AllowAnonymousFXP no | |
227 | ProhibitDotFilesWrite no | |
228 | ProhibitDotFilesRead no | |
229 | AutoRename no | |
230 | AnonymousCantUpload no | |
231 | MaxDiskUsage 99 | |
232 | CustomerProof yes | |
233 | TLS 1 | |
5400b9b6 | 234 | CertFile ${config.security.acme.certs.ftp.directory}/full.pem |
439049e5 | 235 | ''; |
fcbdf67a | 236 | in lib.mkIf pure-ftpd-enabled { |
439049e5 IB |
237 | description = "Pure-FTPd server"; |
238 | wantedBy = [ "multi-user.target" ]; | |
239 | after = [ "network.target" ]; | |
240 | ||
fe696f35 | 241 | serviceConfig.ExecStart = "${package}/bin/pure-ftpd ${configFile}"; |
439049e5 IB |
242 | serviceConfig.Type = "forking"; |
243 | serviceConfig.PIDFile = "/run/pure-ftpd.pid"; | |
244 | }; | |
fcbdf67a IB |
245 | |
246 | systemd.services.proftpd = let | |
247 | configFile = pkgs.writeText "proftpd.conf" '' | |
248 | ServerName "ProFTPD" | |
249 | ServerType standalone | |
250 | DefaultServer on | |
251 | ||
252 | Port 21 | |
253 | UseIPv6 on | |
254 | Umask 022 | |
255 | MaxInstances 30 | |
256 | MaxClients 50 | |
257 | MaxClientsPerHost 8 | |
258 | ||
259 | # Set the user and group under which the server will run. | |
260 | User ftp | |
261 | Group ftp | |
262 | ||
263 | CreateHome on | |
264 | DefaultRoot ~ | |
265 | ||
266 | AllowOverwrite on | |
267 | ||
268 | TLSEngine on | |
269 | TLSRequired off | |
270 | TLSProtocol TLSv1.1 TLSv1.2 TLSv1.3 | |
271 | ||
272 | TLSCertificateChainFile ${config.security.acme.certs.ftp.directory}/fullchain.pem | |
273 | TLSECCertificateFile ${config.security.acme.certs.ftp.directory}/cert.pem | |
274 | TLSECCertificateKeyFile ${config.security.acme.certs.ftp.directory}/key.pem | |
275 | TLSRenegotiate none | |
276 | PidFile /run/proftpd/proftpd.pid | |
277 | ||
278 | ScoreboardFile /run/proftpd/proftpd.scoreboard | |
279 | ||
280 | PassivePorts 40000 50000 | |
281 | #DebugLevel 10 | |
282 | Include ${config.secrets.fullPaths."proftpd-ldap.conf"} | |
283 | ||
284 | RequireValidShell off | |
285 | ||
286 | # Bar use of SITE CHMOD by default | |
287 | <Limit SITE_CHMOD> | |
288 | DenyAll | |
289 | </Limit> | |
290 | ||
291 | <VirtualHost 0.0.0.0> | |
292 | Umask 022 | |
293 | Port 115 | |
294 | SFTPEngine on | |
295 | CreateHome on | |
296 | DefaultRoot ~ | |
297 | ||
298 | AllowOverwrite on | |
299 | ||
300 | SFTPHostKey /etc/ssh/ssh_host_ed25519_key | |
301 | SFTPHostKey /etc/ssh/ssh_host_rsa_key | |
302 | Include ${config.secrets.fullPaths."proftpd-ldap.conf"} | |
303 | RequireValidShell off | |
304 | SFTPAuthorizedUserKeys file:/var/lib/proftpd/authorized_keys/%u | |
305 | SFTPAuthMethods password publickey | |
87e1ff0f IB |
306 | |
307 | SFTPOptions IgnoreSFTPSetOwners | |
1a64deeb | 308 | AllowChrootSymlinks off |
fcbdf67a IB |
309 | </VirtualHost> |
310 | ''; | |
311 | in lib.mkIf proftpd-enabled { | |
312 | description = "ProFTPD server"; | |
313 | wantedBy = [ "multi-user.target" ]; | |
314 | after = [ "network.target" ]; | |
315 | ||
316 | serviceConfig.ExecStart = "${pkgs.proftpd}/bin/proftpd -c ${configFile}"; | |
317 | serviceConfig.Type = "forking"; | |
318 | serviceConfig.PIDFile = "/run/proftpd/proftpd.pid"; | |
319 | serviceConfig.RuntimeDirectory = "proftpd"; | |
320 | }; | |
321 | ||
322 | services.cron.systemCronJobs = lib.mkIf proftpd-enabled [ | |
323 | "*/2 * * * * nobody ${./ftp_sync.sh}" | |
324 | ]; | |
1a64deeb IB |
325 | |
326 | myServices.monitoring.fromMasterActivatedPlugins = [ "ftp" ]; | |
327 | myServices.monitoring.fromMasterObjects.service = [ | |
328 | { | |
329 | service_description = "ftp has access to database for authentication"; | |
330 | host_name = config.hostEnv.fqdn; | |
331 | use = "external-service"; | |
332 | check_command = "check_ftp_database"; | |
333 | ||
334 | servicegroups = "webstatus-remote-services"; | |
335 | _webstatus_name = "FTP"; | |
336 | _webstatus_url = "ftp.immae.eu"; | |
337 | } | |
338 | ||
339 | ]; | |
340 | ||
439049e5 IB |
341 | }; |
342 | ||
343 | } |