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