diff options
Diffstat (limited to 'sys/nspawn.nix')
| -rw-r--r-- | sys/nspawn.nix | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/sys/nspawn.nix b/sys/nspawn.nix new file mode 100644 index 0000000..6f1558c --- /dev/null +++ b/sys/nspawn.nix @@ -0,0 +1,130 @@ +{ lib, config, pkgs, ... }: +with lib; let + cfg = config.local; +in +{ + options.local.nspawn.dmz = with types; { + enable = mkEnableOption "DMZ services in a container"; + + net = mkOption { + type = str; + }; + + netBits = mkOption { + type = int; + }; + + hostAddr = mkOption { + type = str; + }; + + system = mkOption { + type = attrs; + }; + }; + + # Situación con os-release + # + # La idea aquí es poder hacer 'btrfs subvol create /var/lib/machines/foo' y + # dejar que systemd-nspawn y el activation script creen todo lo demás. Esto + # no sirve bien debido a la prueba barata que hace systemd para revisar si el + # árbol parece contener una imagen de sistema operativo. Esta prueba falla en + # dos momentos distintos: + # + # 1. Inmediatamente tras crear un árbol vacío, puesto que os-release no existe. + # La solución naive es 'mkdir rootfs/etc && touch rootfs/etc/os-release'. + # + # 2. Luego de reiniciar el contenedor una vez que NixOS ha preparado /etc, ya que + # systemd espera un archivo regular y no telera el symlink a la store. + # + # Resulta ser que systemd revisa tanto /etc/os-release como /usr/lib/os-release. + # NixOS evidentemente no usa la segunda ruta por ser FHS, así que la duct tape + # final es 'mkdir rootfs/usr/lib && touch rootfs/usr/lib/os-release'. + + config = mkIf cfg.nspawn.dmz.enable { + local = { + mailHost = { + mdaListen = cfg.nspawn.dmz.hostAddr; + saslPort = 11000; + lmtpPort = 11001; + }; + + nspawn.dmz = { + system = + let + containerModule = { ... }: { + #TODO: urgente: bloquear puertos de dovecot a non-postfix con iptables + config = { + boot.isContainer = true; + + local.mta = { + mdaAddr = cfg.mailHost.mdaListen; + inherit (cfg.mailHost) saslPort lmtpPort; + }; + }; + }; + in + pkgs.nixos [ ../dmz containerModule ]; + + net = "10.34.3.0"; + netBits = 28; + hostAddr = "10.34.3.1"; + }; + }; + + systemd = { + nspawn.dmz = { + execConfig.PrivateUsers = "pick"; + + filesConfig.BindReadOnly = [ + # idmap porque algunos hacks en nixpkgs (postfix-setup.service) + # asumen que la store es de root + "/nix/store:/nix/store:idmap" + "${cfg.nspawn.dmz.system.toplevel}/init:/sbin/init" + ]; + + networkConfig.Port = [ "tcp:25" "tcp:80" "tcp:443" "tcp:587" ]; + }; + + network.networks."40-ve-dmz" = { + matchConfig = { + Name = "ve-dmz"; + Driver = "veth"; + }; + + networkConfig = { + Address = "${cfg.nspawn.dmz.hostAddr}/${toString cfg.nspawn.dmz.netBits}"; + LinkLocalAddressing = "yes"; + DHCPServer = "yes"; + IPMasquerade = "both"; + LLDP = "yes"; + EmitLLDP = "customer-bridge"; + IPv6SendRA = "yes"; + }; + + # IP de contenedor fijada en hostAddr + 1 + dhcpServerConfig = { + PoolOffset = 2; + PoolSize = 1; + }; + }; + + services = { + dovecot2.after = [ "systemd-nspawn@dmz.service" ]; + + "systemd-nspawn@dmz" = { + overrideStrategy = "asDropin"; + + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "machines.target" ]; + }; + }; + }; + + networking.firewall.interfaces.ve-dmz = { + allowedTCPPorts = [ cfg.mailHost.saslPort cfg.mailHost.lmtpPort ]; + allowedUDPPorts = [ 67 ]; # DHCP + }; + }; +} |
