aboutsummaryrefslogblamecommitdiff
path: root/virtual/eldiron.nix
blob: 292b31aa55d521d2c4f39b786ad04dc7f2f90d95 (plain) (tree)
1
2
3
4
5
6
7
8
9





                                    

                                       
                                    

      


                      
                                                  






















                                                                                











                                                                   

                 
         

      




                                                 

                                                                                                     
                                        
           

                                 
                                  

                                           
                                  

          













                                                                                                       

      



















                                                                                                                                                                                                                                                                                                                                                                                                                                  

                                                             
                       






                                                                       



                          
                                             
                                                                   
                                                                     
                                                 


        

                                                                       
                                                                        
                                                    

                                                       
           



                              






































                                                                                                     

      


                         
                                                           


                                                                 






























                                                                                                                       
            
                    


                                       
                    















                                       

                                            
                                          
                                                   
                                                    
                                     



                                                                                                   



                                                 



                                    




                                                 
                                                        
                                           
            
          




                                                        
                                           
                                        

            








                                                           







                                                        




                                                












                                                                            

                               

                                                                          
















                                                                                        










                                           



                                                              
                







                                                                          
                         
                   
                






































                                                                          
{
  network = {
    description = "Immae's network";
    enableRollback = true;
  };

  eldiron = { config, pkgs, ... }:
    let mypkgs = import ./packages.nix;
        mylibs = import ../libs.nix;
    in
  {
    networking = {
      firewall = {
        enable = true;
        allowedTCPPorts = [ 22 80 443 3306 5432 ];
      };
    };

    deployment = {
      targetEnv = "hetzner";
      hetzner = {
        #robotUser = "defined in HETZNER_ROBOT_USER";
        #robotPass = "defined in HETZNER_ROBOT_PASS";
        mainIPv4 = "176.9.151.89";
        partitions = ''
          clearpart --all --initlabel --drives=sda,sdb

          part swap1 --recommended --label=swap1 --fstype=swap --ondisk=sda
          part swap2 --recommended --label=swap2 --fstype=swap --ondisk=sdb

          part raid.1 --grow --ondisk=sda
          part raid.2 --grow --ondisk=sdb

          raid / --level=1 --device=md0 --fstype=ext4 --label=root raid.1 raid.2
        '';
      };
    };

    environment.systemPackages = let
      # FIXME: move it to nextcloud
      occ = pkgs.writeScriptBin "nextcloud-occ" ''
        #! ${pkgs.stdenv.shell}
        cd ${mypkgs.nextcloud.webRoot}
        NEXTCLOUD_CONFIG_DIR="${mypkgs.nextcloud.webRoot}/config" \
          exec \
          ${config.services.phpfpm.phpPackage}/bin/php \
          -c ${config.services.phpfpm.phpPackage}/etc/php.ini \
          occ $*
        '';
    in [
      pkgs.telnet
      pkgs.vim
      occ
    ];

    security.acme.certs = {
      "eldiron" = {
        webroot = "/var/lib/acme/acme-challenge";
        email = "ismael@bouya.org";
        domain = "eldiron.immae.eu";
        plugins = [ "cert.pem" "chain.pem" "fullchain.pem" "full.pem" "key.pem" "account_key.json" ];
        postRun = ''
          systemctl reload httpd.service
        '';
        extraDomains = {
          "db-1.immae.eu" = null;
          "tools.immae.eu" = null;
          "connexionswing.immae.eu" = null;
          "sandetludo.immae.eu" = null;
          "cloud.immae.eu" = null;
        };
      };
      # "connexionswing" = {
      #   webroot = "/var/lib/acme/acme-challenge";
      #   email = "ismael@bouya.org";
      #   domain = "connexionswing.com";
      #   plugins = [ "cert.pem" "chain.pem" "fullchain.pem" "full.pem" "key.pem" "account_key.json" ];
      #   postRun = ''
      #     systemctl reload httpd.service
      #   '';
      #   extraDomains = {
      #     "www.connexionswing.com" = null;
      #     "sandetludo.com" = null;
      #     "www.sandetludo.com" = null;
      #   };
      # };
    };

    services.openssh.extraConfig = ''
      AuthorizedKeysCommand     /etc/ssh/ldap_authorized_keys
      AuthorizedKeysCommandUser nobody
      '';

    # FIXME: after initial install, need to
    # (1) copy rc file (adjust gitolite_ldap_groups.sh)
    # (2) (mark old readonly and) sync repos except gitolite-admin
    #     rsync -av --exclude=gitolite-admin.git old:/var/lib/gitolite/repositories /var/lib/gitolite/
    #     chown -R gitolite:gitolite /var/lib/gitolite
    # (3) push force the gitolite-admin to new location (from external point)
    #     Don't use an existing key, it will take precedence over
    #     gitolite-admin
    # (4) su -u gitolite gitolite setup
    services.gitolite = {
      enable = true;
      # FIXME: key from ./ssh
      adminPubkey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXqRbiHw7QoHADNIEuo4nUT9fSOIEBMdJZH0bkQAxXyJFyCM1IMz0pxsHV0wu9tdkkr36bPEUj2aV5bkYLBN6nxcV2Y49X8bjOSCPfx3n6Own1h+NeZVBj4ZByrFmqCbTxUJIZ2bZKcWOFncML39VmWdsVhNjg0X4NBBehqXRIKr2gt3E/ESAxTYJFm0BnU0baciw9cN0bsRGqvFgf5h2P48CIAfwhVcGmPQnnAwabnosYQzRWxR0OygH5Kd8mePh6FheIRIigfXsDO8f/jdxwut8buvNIf3m5EBr3tUbTsvM+eV3M5vKGt7sk8T64DVtepTSdOOWtp+47ktsnHOMh immae@immae.eu";
    };

    services.ympd = mypkgs.ympd.config // { enable = true; };

    services.phpfpm = {
      # /!\ phppackage is used in nextcloud configuation
      phpOptions = ''
        ; For nextcloud
        extension=${pkgs.phpPackages.redis}/lib/php/extensions/redis.so
        ; For nextcloud
        extension=${pkgs.phpPackages.apcu}/lib/php/extensions/apcu.so
        '';
      extraConfig = ''
        log_level = notice
        '';
      poolConfigs = {
        adminer = mypkgs.adminer.phpFpm.pool;
        connexionswing_dev = mypkgs.connexionswing_dev.phpFpm.pool;
        connexionswing_prod = mypkgs.connexionswing_prod.phpFpm.pool;
        nextcloud = mypkgs.nextcloud.phpFpm.pool;
      };
    };

    system.activationScripts = {
      connexionswing_dev  = mypkgs.connexionswing_dev.activationScript;
      connexionswing_prod = mypkgs.connexionswing_prod.activationScript;
      nextcloud = mypkgs.nextcloud.activationScript;
      httpd = ''
        install -d -m 0755 /var/lib/acme/acme-challenge
        '';
      redis = ''
        mkdir -p /run/redis
        chown redis /run/redis
        '';
      gitolite =
        assert mylibs.checkEnv "NIXOPS_GITOLITE_LDAP_PASSWORD";
        let
        gitolite_ldap_groups = mylibs.wrap {
          name = "gitolite_ldap_groups.sh";
          file = ./packages/gitolite_ldap_groups.sh;
          vars = {
            LDAP_PASS = builtins.getEnv "NIXOPS_GITOLITE_LDAP_PASSWORD";
          };
          paths = [ pkgs.openldap pkgs.stdenv.shellPackage pkgs.gnugrep pkgs.coreutils ];
        };
      in {
        deps = [ "users" ];
        text = ''
          if [ -d /var/lib/gitolite ]; then
            ln -sf ${gitolite_ldap_groups} /var/lib/gitolite/gitolite_ldap_groups.sh
          fi
        '';
      };
    };

    environment.etc."ssh/ldap_authorized_keys" = let
      ldap_authorized_keys =
        assert mylibs.checkEnv "NIXOPS_SSHD_LDAP_PASSWORD";
        mylibs.wrap {
          name = "ldap_authorized_keys";
          file = ./ldap_authorized_keys.sh;
          vars = {
            LDAP_PASS = builtins.getEnv "NIXOPS_SSHD_LDAP_PASSWORD";
            GITOLITE_SHELL = "${pkgs.gitolite}/bin/gitolite-shell";
            ECHO = "${pkgs.coreutils}/bin/echo";
          };
          paths = [ pkgs.openldap pkgs.stdenv.shellPackage pkgs.gnugrep pkgs.gnused pkgs.coreutils ];
        };
    in {
      enable = true;
      mode = "0755";
      user = "root";
      source = ldap_authorized_keys;
    };

    services.httpd = let
      withSSL = domain: {
        enableSSL = true;
        sslServerCert = "/var/lib/acme/${domain}/cert.pem";
        sslServerKey = "/var/lib/acme/${domain}/key.pem";
        sslServerChain = "/var/lib/acme/${domain}/fullchain.pem";
      };
      apacheConfig = {
        gzip = {
          modules = [ "deflate" "filter" ];
          extraConfig = ''
            AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript
          '';
        };
        ldap = {
          modules = [ "ldap" "authnz_ldap" ];
          extraConfig = assert mylibs.checkEnv "NIXOPS_HTTP_LDAP_PASSWORD"; ''
            <IfModule ldap_module>
              LDAPSharedCacheSize 500000
              LDAPCacheEntries 1024
              LDAPCacheTTL 600
              LDAPOpCacheEntries 1024
              LDAPOpCacheTTL 600
            </IfModule>

            <Macro LDAPConnect>
              <IfModule authnz_ldap_module>
                AuthLDAPURL          ldap://ldap.immae.eu:389/dc=immae,dc=eu
                AuthLDAPBindDN       cn=httpd,ou=services,dc=immae,dc=eu
                AuthLDAPBindPassword "${builtins.getEnv "NIXOPS_HTTP_LDAP_PASSWORD"}"
                AuthType             Basic
                AuthName             "Authentification requise (Acces LDAP)"
                AuthBasicProvider    ldap
              </IfModule>
            </Macro>
          '';
        };
      };
    in rec {
      enable = true;
      logPerVirtualHost = true;
      multiProcessingModule = "worker";
      adminAddr = "httpd@immae.eu";
      # FIXME: http2
      # FIXME: voir les autres modules:
      #    authz_core_module
      #    reqtimeout_module
      #    http2_module
      #    version_module
      #    proxy_connect_module
      #    proxy_ftp_module
      #    proxy_scgi_module
      #    proxy_ajp_module
      #    proxy_balancer_module
      #    proxy_express_module
      #    lbmethod_byrequests_module
      #    lbmethod_bytraffic_module
      #    lbmethod_bybusyness_module
      #    lbmethod_heartbeat_module

      extraModules = pkgs.lib.lists.unique (
        mypkgs.adminer.apache.modules ++
        mypkgs.nextcloud.apache.modules ++
        mypkgs.connexionswing_dev.apache.modules ++
        mypkgs.connexionswing_prod.apache.modules ++
        mypkgs.ympd.apache.modules ++
        pkgs.lib.lists.flatten (pkgs.lib.attrsets.mapAttrsToList (n: v: v.modules) apacheConfig) ++
        [ "macro" ]);
      extraConfig = builtins.concatStringsSep "\n"
        (pkgs.lib.attrsets.mapAttrsToList (n: v: v.extraConfig) apacheConfig);
      virtualHosts = [
        (withSSL "eldiron" // {
          listen = [ { ip = "*"; port = 443; } ];
          hostName = "eldiron.immae.eu";
          documentRoot = ./www;
          extraConfig = ''
            DirectoryIndex index.htm
            '';
        })
        (withSSL "eldiron" // {
          listen = [ { ip = "*"; port = 443; } ];
          hostName = "db-1.immae.eu";
          documentRoot = null;
          extraConfig = builtins.concatStringsSep "\n" [
            mypkgs.adminer.apache.vhostConf
          ];
        })
        (withSSL "eldiron" // {
          listen = [ { ip = "*"; port = 443; } ];
          hostName = "tools.immae.eu";
          documentRoot = null;
          extraConfig = builtins.concatStringsSep "\n" [
            mypkgs.adminer.apache.vhostConf
            mypkgs.ympd.apache.vhostConf
          ];
        })
        (withSSL "eldiron" // {
          listen = [ { ip = "*"; port = 443; } ];
          hostName = "connexionswing.immae.eu";
          serverAliases = [ "sandetludo.immae.eu" ];
          documentRoot = mypkgs.connexionswing_dev.webRoot;
          extraConfig = builtins.concatStringsSep "\n" [
            mypkgs.connexionswing_dev.apache.vhostConf
          ];
        })
        (withSSL "eldiron" // {
          listen = [ { ip = "*"; port = 443; } ];
          hostName = "cloud.immae.eu";
          documentRoot = mypkgs.nextcloud.webRoot;
          extraConfig = builtins.concatStringsSep "\n" [
            mypkgs.nextcloud.apache.vhostConf
          ];
        })
        { # Should go last, default fallback
          listen = [ { ip = "*"; port = 80; } ];
          hostName = "redirectSSL";
          serverAliases = [ "*" ];
          enableSSL = false;
          documentRoot = "/var/lib/acme/acme-challenge";
          extraConfig = ''
            RewriteEngine on
            RewriteCond "%{REQUEST_URI}"   "!^/\.well-known"
            RewriteRule ^(.+)              https://%{HTTP_HOST}$1  [R=301]
            # To redirect in specific "VirtualHost *:80", do
            #   RedirectMatch 301 ^/((?!\.well-known.*$).*)$ https://host/$1
            # rather than rewrite
            '';
        }
        ];
    };

    security.pam.services = let
      pam_ldap = pkgs.pam_ldap;
      pam_ldap_mysql = assert mylibs.checkEnv "NIXOPS_MYSQL_PAM_PASSWORD";
              pkgs.writeText "mysql.conf" ''
        host ldap.immae.eu
        base dc=immae,dc=eu
        binddn cn=mysql,cn=pam,ou=services,dc=immae,dc=eu
        bindpw ${builtins.getEnv "NIXOPS_MYSQL_PAM_PASSWORD"}
        pam_filter memberOf=cn=users,cn=mysql,cn=pam,ou=services,dc=immae,dc=eu
        '';
    in [
      {
        name = "mysql";
        text = ''
          # https://mariadb.com/kb/en/mariadb/pam-authentication-plugin/
          auth    required ${pam_ldap}/lib/security/pam_ldap.so config=${pam_ldap_mysql}
          account required ${pam_ldap}/lib/security/pam_ldap.so config=${pam_ldap_mysql}
          '';
      }
    ];

    # FIXME: backup
    services.redis = rec {
      enable = true;
      bind = "127.0.0.1";
      unixSocket = "/run/redis/redis.sock";
      extraConfig = ''
        unixsocketperm 777
        maxclients 1024
        '';
    };

    # FIXME: initial sync
    # FIXME: backup
    # FIXME: restart after pam
    # FIXME: pam access doesn’t work (because of php module)
    # FIXME: ssl
    services.mysql = rec {
      enable = true;
      package = pkgs.mariadb.overrideAttrs(old: rec {
        cmakeFlags = old.cmakeFlags ++ [ "-DWITH_AUTHENTICATION_PAM=ON" ];
        buildInputs = old.buildInputs ++ [ pkgs.pam ];
      });
    };

    # FIXME: initial sync
    # FIXME: backup
    # FIXME: ssl
    services.postgresql = rec {
      enable = true;
      package = pkgs.postgresql100.overrideAttrs(old: rec {
        passthru = old.passthru // { psqlSchema = "11.0"; };
        name = "postgresql-11.1";
        src = pkgs.fetchurl {
          url = "mirror://postgresql/source/v11.1/${name}.tar.bz2";
          sha256 = "026v0sicsh7avzi45waf8shcbhivyxmi7qgn9fd1x0vl520mx0ch";
        };
      });
      enableTCPIP = true;
      extraConfig = ''
        max_connections = 100
        wal_level = logical
        shared_buffers = 128MB
        max_wal_size = 1GB
        min_wal_size = 80MB
        log_timezone = 'Europe/Paris'
        datestyle = 'iso, mdy'
        timezone = 'Europe/Paris'
        lc_messages = 'en_US.UTF-8'
        lc_monetary = 'en_US.UTF-8'
        lc_numeric = 'en_US.UTF-8'
        lc_time = 'en_US.UTF-8'
        default_text_search_config = 'pg_catalog.english'
        # ssl = on
        # ssl_cert_file = '/var/lib/acme/eldiron/fullchain.pem'
        # ssl_key_file = '/var/lib/acme/eldiron/key.pem'
        '';
      authentication = ''
        local	all	postgres				ident
        local	all	all					md5
        host	all	all		178.33.252.96/32	md5
        host	all	all		188.165.209.148/32	md5
        #host	all	all		all			pam
      '';
    };
  };
}