aboutsummaryrefslogblamecommitdiff
path: root/systems/eldiron/ftp.nix
blob: e5bc0f5c1aeedfca7e67c32eabe3a5290ccf3cee (plain) (tree)
1
2
3
4
5
6
7
8
                           

                                                                

                                                             
  

             







                                                    





                                    






                                                  

    
                                                  



                                                        







































































                                                                                   
                                  


                                                                 
                                                        
                                           


                                                  
                                            

      

                  
                                     



                                                                 






                                         


                                               
                                     
                                                   


                                                                              
 
                                                                



                           
                                                         

                                


                                                             



                                 
                                                                     


                                

                                                                           

                                             
      





















                                                                                                     
 
                                                                  
                     
                                                            
      



                                                               
 
                                    

                                                     
                                       












                                        
                                                                                 















                                            
                                                                                         
           
                                   



                                         
                                                                         


                                                   




























































                                                                                         

                                                           
                                           















                                                                               















                                                                              


    
{ 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";
      }

    ];

  };

}