]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Add Tinc VPN
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Thu, 13 Feb 2020 12:05:40 +0000 (13:05 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Thu, 13 Feb 2020 12:05:40 +0000 (13:05 +0100)
13 files changed:
modules/private/default.nix
modules/private/environment.nix
modules/private/system/eldiron.nix
modules/private/vpn/default.nix [new file with mode: 0644]
modules/private/vpn/tinc/host-down [new file with mode: 0755]
modules/private/vpn/tinc/host-up [new file with mode: 0755]
modules/private/vpn/tinc/tinc-down [new file with mode: 0755]
modules/private/vpn/tinc/tinc-up [new file with mode: 0755]
modules/private/vpn/tinc/tinc.conf [new file with mode: 0644]
modules/private/websites/tools/tools/default.nix
modules/private/websites/tools/vpn/default.nix [new file with mode: 0644]
modules/private/websites/tools/vpn/www/index.html [new file with mode: 0644]
modules/private/websites/tools/vpn/www/style.css [new file with mode: 0644]

index 945a79936842c8ecf2015943003e8d9b2f627d31..3996eac1dff6c464c1d151edff1c563f85dcd0c1 100644 (file)
@@ -46,6 +46,7 @@ set = {
 
   cloudTool = ./websites/tools/cloud;
   davTool = ./websites/tools/dav;
+  vpnTool = ./websites/tools/vpn;
   dbTool = ./websites/tools/db;
   diasporaTool = ./websites/tools/diaspora;
   etherTool = ./websites/tools/ether;
@@ -72,6 +73,7 @@ set = {
   ssh = ./ssh;
   monitoring = ./monitoring;
   status = ./monitoring/status.nix;
+  vpn = ./vpn;
 
   environment = ./environment.nix;
   system = ./system.nix;
index 3b51f37a7458f49513c7cf32259ef688f6364fa1..2cecc6d7be7c9ac7095490d8430de7966ff26185 100644 (file)
@@ -536,6 +536,16 @@ in
         };
       };
     };
+    vpn = mkOption {
+      description = "VPN configuration";
+      type = attrsOf (submodule {
+        options = {
+          prefix = mkOption { type = str; description = "ipv6 prefix for the vpn subnet"; };
+          privateKey = mkOption { type = str; description = "Private key for the host"; };
+          publicKey = mkOption { type = str; description = "Public key for the host"; };
+        };
+      });
+    };
     mail = mkOption {
       description = "Mail configuration";
       type = submodule {
index 0ff99637026b9ca64cd126f82aea263aaa271a84..5e3d45cce1c59fcd4f8f605113807170539860e7 100644 (file)
@@ -34,6 +34,7 @@
   myServices.websites.enable = true;
   myServices.mail.enable = true;
   myServices.ejabberd.enable = true;
+  myServices.vpn.enable = true;
   services.pure-ftpd.enable = true;
   services.duplyBackup.enable = true;
   services.duplyBackup.profiles.oldies.rootDir = "/var/lib/oldies";
diff --git a/modules/private/vpn/default.nix b/modules/private/vpn/default.nix
new file mode 100644 (file)
index 0000000..fbcba2f
--- /dev/null
@@ -0,0 +1,62 @@
+{ config, pkgs, lib, ... }:
+let
+  cfg = config.myServices.vpn;
+in
+{
+  options.myServices = {
+    vpn.enable = lib.mkEnableOption "Enable vpn service";
+  };
+
+  config = lib.mkIf cfg.enable {
+    secrets.keys = [
+      {
+        dest = "tinc/key.priv";
+        user = "root";
+        group = "root";
+        permissions = "0400";
+        text = config.myEnv.vpn.eldiron.privateKey;
+      }
+      {
+        dest = "tinc/key.pub";
+        user = "root";
+        group = "root";
+        permissions = "0400";
+        text = config.myEnv.vpn.eldiron.publicKey;
+      }
+    ];
+    networking.firewall.allowedTCPPorts = [ 655 1194 ];
+    system.activationScripts.tinc = let
+      configFiles = pkgs.runCommand "tinc-files" {
+        mainInterface = "eth0";
+        hostName = "ImmaeEu";
+        network = "Immae";
+        keyFile = config.secrets.fullPaths."tinc/key.priv";
+      } ''
+        mkdir -p $out
+        for i in ${./tinc}/*; do
+          substituteAll $i $out/$(basename $i)
+        done
+      '';
+    in ''
+      install -m750 -o root -g root -d /var/lib/tinc/ /var/lib/tinc/Immae
+      install -m700 -o root -g root -t /var/lib/tinc/Immae ${configFiles}/{host-*,tinc-*}
+      install -m400 -o root -g root -t /var/lib/tinc/Immae ${configFiles}/tinc.conf
+      if [ ! -d /var/lib/tinc/Immae/hosts ]; then
+        ${pkgs.git}/bin/git clone -b master https://git.immae.eu/perso/Immae/Config/tinc/hosts /var/lib/tinc/Immae/hosts
+      fi
+    '';
+
+    systemd.services.tinc-Immae = {
+      description = "Tinc Daemon - Immae";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      path = [ pkgs.tinc pkgs.bashInteractive pkgs.iproute pkgs.gnused pkgs.gawk pkgs.git pkgs.glibc ];
+      serviceConfig = {
+        Type = "simple";
+        Restart = "always";
+        RestartSec = "3";
+        ExecStart = "${pkgs.tinc}/bin/tincd -d1 -D -c /var/lib/tinc/Immae --pidfile /run/tinc.Immae.pid";
+      };
+    };
+  };
+}
diff --git a/modules/private/vpn/tinc/host-down b/modules/private/vpn/tinc/host-down
new file mode 100755 (executable)
index 0000000..1e79bd3
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+SUBDOMAIN=$(echo "$NODE" | sed -e "s/\([A-Z][a-z0-9]*\)/\L\1 /g;" | awk '{ for (i=NF; i>1; i--) printf("%s.",$i); print $1; }')
+NODEIPS=`getent hosts ${SUBDOMAIN}.immae.eu | cut -d' ' -f1 | tr "\\n" ' '`
+for NODEIP in $NODEIPS; do
+  ip neigh del proxy $NODEIP dev @mainInterface@
+done
diff --git a/modules/private/vpn/tinc/host-up b/modules/private/vpn/tinc/host-up
new file mode 100755 (executable)
index 0000000..2f7cee2
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+SUBDOMAIN=$(echo "$NODE" | sed -e "s/\([A-Z][a-z0-9]*\)/\L\1 /g;" | awk '{ for (i=NF; i>1; i--) printf("%s.",$i); print $1; }')
+while [ -z "$NODEIPS" ]; do
+  NODEIPS=`getent hosts ${SUBDOMAIN}.immae.eu | cut -d' ' -f1 | tr "\\n" ' '`
+  sleep 5
+done
+for NODEIP in $NODEIPS; do
+  ip neigh add proxy $NODEIP dev @mainInterface@
+done
+(cd /var/lib/tinc/@network@/hosts && git pull -q origin master) || true
diff --git a/modules/private/vpn/tinc/tinc-down b/modules/private/vpn/tinc/tinc-down
new file mode 100755 (executable)
index 0000000..1cc45c0
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+# This file closes down the tap device.
+
+echo 0 > /proc/sys/net/ipv6/conf/@mainInterface@/proxy_ndp
+echo 0 > /proc/sys/net/ipv6/conf/all/forwarding
+
+GWIP=`getent hosts gw.vpn.immae.eu | head -n1 | cut -d' ' -f1`
+
+ip neigh del proxy $GWIP dev eth0
+
+ip -6 addr del $GWIP/96 dev $INTERFACE
+ip -6 link set $INTERFACE down
diff --git a/modules/private/vpn/tinc/tinc-up b/modules/private/vpn/tinc/tinc-up
new file mode 100755 (executable)
index 0000000..26c1ec3
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+echo 1 > /proc/sys/net/ipv6/conf/@mainInterface@/proxy_ndp
+echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
+
+SUBNET=`getent hosts sn.vpn.immae.eu | head -n1 | cut -d' ' -f1`
+GWIP=`getent hosts gw.vpn.immae.eu | head -n1 | cut -d' ' -f1`
+
+ip -6 link set $INTERFACE up mtu 1280 txqueuelen 1000
+
+ip -6 addr add $GWIP/96 dev $INTERFACE
+ip -6 route add $SUBNET/80 dev $INTERFACE
+
+ip neigh add proxy $GWIP dev @mainInterface@
diff --git a/modules/private/vpn/tinc/tinc.conf b/modules/private/vpn/tinc/tinc.conf
new file mode 100644 (file)
index 0000000..7a4f103
--- /dev/null
@@ -0,0 +1,11 @@
+BindToAddress = * 655
+BindToAddress = * 1194
+
+Name = @hostName@
+Interface = vpn6
+
+Mode = switch
+
+Device = /dev/net/tun
+GraphDumpFile = /var/lib/tinc/@network@/tinc_graph
+PrivateKeyFile = @keyFile@
index f88cf061e72d70641c5c8911b66c58d2a825743c..9fb2d0357858d5a6e8a5fdc1810c8912db540ff5 100644 (file)
@@ -102,6 +102,7 @@ in {
       root        = "/var/lib/ftp/tools.immae.eu";
       extraConfig = [
         ''
+          RedirectMatch 301 ^/vpn(.*)$         https://vpn.immae.eu$1
           RedirectMatch 301 ^/roundcube(.*)$   https://mail.immae.eu/roundcube$1
           RedirectMatch 301 ^/jappix(.*)$      https://im.immae.fr/converse
 
@@ -152,6 +153,8 @@ in {
 
         RedirectMatch 301 ^/jappix(.*)$      https://im.immae.fr/converse
 
+        RedirectMatch 301 ^/vpn(.*)$         https://vpn.immae.eu$1
+
         RedirectMatch 301 ^/(.*)$            https://tools.immae.eu/$1
         ''
       ];
diff --git a/modules/private/websites/tools/vpn/default.nix b/modules/private/websites/tools/vpn/default.nix
new file mode 100644 (file)
index 0000000..cfe010c
--- /dev/null
@@ -0,0 +1,15 @@
+{ lib, pkgs, config,  ... }:
+let
+  cfg = config.myServices.vpn;
+in {
+  config = lib.mkIf cfg.enable {
+    services.websites.env.tools.vhostConfs.vpn = {
+      certName    = "eldiron";
+      addToCerts  = true;
+      hosts       = [ "vpn.immae.eu" ];
+      root        = "/run/current-system/webapps/_vpn";
+    };
+
+    myServices.websites.webappDirs._vpn = ./www;
+  };
+}
diff --git a/modules/private/websites/tools/vpn/www/index.html b/modules/private/websites/tools/vpn/www/index.html
new file mode 100644 (file)
index 0000000..08199fb
--- /dev/null
@@ -0,0 +1,91 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>VPN configuration</title>
+  <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'>
+  <link rel="stylesheet" href="style.css" type="text/css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1" />
+ </head>
+ <body>
+   <div class="instructions">
+     <h2>Installation</h2>
+     <ul>
+       <li>Installer tinc</li>
+       <li>Créer un fichier /etc/tinc/Immae/tinc.conf sur ce modèle, en remplaçant la ligne <code>A choisir</code> par un nom de la forme DomaineMachine. La machine sera accessible par <code>machine.domaine.immae.eu</code> par la suite
+         <pre>
+Name = A choisir
+Mode = switch
+Interface = vpn6
+ConnectTo = ImmaeEu
+
+# The tap device tinc will use.
+# Default is /dev/tap0 for ethertap or FreeBSD,
+# /dev/tun0 for Solaris and OpenBSD,
+# and /dev/net/tun for Linux tun/tap device.
+Device = /dev/net/tun
+LocalDiscovery = yes
+         </pre>
+         </li>
+       <li>Vérifier l'existence du device indiqué à la ligne "<code>Device</code>" dans le système.
+         <pre>ls /dev/net/tun</pre>
+       </li>
+       <li><em class="important">Si tinc tourne déjà, l'arrêter !!</em></li>
+       <li>Générer les clés&nbsp;:
+         <pre>tincd -K -n Immae</pre>
+         Stocker la clé privée dans <code>/etc/tinc/Immae/rsa_key.priv</code> et la clé publique dans un autre dossier<br />
+         (<em>pas <code>/etc/tinc/Immae/hosts/</code> comme proposé par défaut</em>).<br />
+         L'endroit importe peu, elle ne sera pas conservée.</li>
+       <li>M'envoyer le nom choisi dans <code>tinc.conf</code>, et la clé publique</li>
+       <li>Cloner le dépôt des hôtes du réseau
+         <pre>
+cd /etc/tinc/Immae
+git clone https://git.immae.eu/perso/Immae/Config/tinc/hosts
+         </pre>
+       </li>
+       <li>Une fois que j'ai confirmé avoir reçu la clé&nbsp;:
+         <pre>
+cd /etc/tinc/Immae/hosts
+git pull origin master
+         </pre>
+       </li>
+       <li>Uniquement pour Debian/Ubuntu: Ajouter <code>Immae</code> dans <code>/etc/tinc/nets.boot</code> (créer le fichier si nécessaire).</li>
+       <li>Selon le système, démarrer tinc&nbsp;:
+         <pre>
+/etc/init.d/tinc start
+         </pre>
+         ou
+         <pre>
+systemctl enable tincd@Immae.service
+systemctl start tincd@Immae.service
+         </pre>
+       </li>
+     </ul>
+
+     <h2>Choix d'ip</h2>
+     <ul>
+       <li>Choisir une ip : <code>2001:aaaa:b:cccc:d::xxxx:yyyy/96</code> (le préfixe <code>2001:aaaa:b:cccc:d</code> est imposé). Choix uniquement sur le <code>yyyy</code> (n'importe quel nombre entre <code>1</code> et <code>ffff</code>), le <code>xxxx</code> est dépendant du domaine</li>
+       <li>M'envoyer le choix de l'ip</li>
+
+       <li>Si on veut éviter de passer systématiquement par le serveur immae.eu (Par
+         défaut linux préfère l'ipv6 dès qu'il en a possibilité), modifier le fichier
+         <code>/etc/gai.conf</code>. Quelques lignes à décommenter, tout est déjà dans le fichier :
+         <pre>
+(...)
+#
+precedence  ::1/128       50
+precedence  ::/0          40
+precedence  2002::/16     30
+precedence ::/96          20
+#precedence ::ffff:0:0/96  10
+#
+#    For sites which prefer IPv4 connections change the last line to
+#
+precedence ::ffff:0:0/96  100
+(...)
+         </pre>
+       </li>
+     </ul>
+   </div>
+ </body>
+</html>
diff --git a/modules/private/websites/tools/vpn/www/style.css b/modules/private/websites/tools/vpn/www/style.css
new file mode 100644 (file)
index 0000000..b177fec
--- /dev/null
@@ -0,0 +1,61 @@
+* {
+  margin:0;
+  padding:0;
+  -webkit-box-sizing:border-box;
+  -moz-box-sizing:border-box;
+  box-sizing: border-box; 
+}
+
+html {
+  min-height:100%;
+  border-top:10px solid #ECEEF1;
+  border-bottom:10px solid #ECEEF1;
+  color:#61666c;
+  font-weight:400;
+  font-size:1em;
+  font-family:'Open Sans', sans-serif;
+  line-height:2em;
+}
+body {
+  padding:20px;
+  -webkit-backface-visibility:hidden;
+}
+code {
+  font-family:consolas,monospace;
+}
+a {
+  color:#61666c;
+  text-decoration:none;
+}
+a, img {
+  border:none;
+  outline:none
+}
+a:hover {
+  color:#2a2a2a;
+}
+
+.instructions {
+  margin:0 auto;
+  padding-top:20px;
+  max-width:80%;
+}
+
+.instructions a {
+  text-decoration: underline;
+}
+
+.instructions h2 {
+  margin-top: 10px;
+}
+.instructions em.important:before {
+  content: "⚠ Important ⚠ ";
+  color: red;
+}
+.instructions pre {
+  width: 50em;
+  padding: 10px 15px;
+  display: table;
+  border: 1px inset black;
+  line-height: 1em;
+}