204 lines
5.7 KiB
Nix
204 lines
5.7 KiB
Nix
{ zentralwerk, options, config, lib, pkgs, ... }:
|
|
|
|
let
|
|
defaultGateways = {
|
|
serv = "serv-gw";
|
|
c3d2 = "c3d2-gw3";
|
|
pub = "pub-gw";
|
|
flpk = "flpk-gw";
|
|
};
|
|
|
|
inherit (config.networking) hostName;
|
|
inherit (config.c3d2.deployment) server;
|
|
serverFQDN = "${server}.cluster.zentralwerk.org";
|
|
|
|
generateMacAddress = net:
|
|
let
|
|
hash = builtins.hashString "md5" "1-${net}-${hostName}";
|
|
c = off: builtins.substring off 2 hash;
|
|
in
|
|
"${builtins.substring 0 1 hash}2:${c 2}:${c 4}:${c 6}:${c 8}:${c 10}";
|
|
|
|
nets = builtins.attrNames (
|
|
lib.filterAttrs (_: { hosts4, hosts6, ... }:
|
|
hosts4 ? ${hostName} ||
|
|
lib.filterAttrs (_: hosts6:
|
|
hosts6 ? ${hostName}
|
|
) hosts6 != {}
|
|
) zentralwerk.lib.config.site.net
|
|
);
|
|
|
|
arch-to-host = rec {
|
|
server9 = "westmere";
|
|
server10 = "ivybridge";
|
|
nomad = server9;
|
|
};
|
|
in
|
|
{
|
|
options.c3d2.deployment = with lib; {
|
|
server = mkOption {
|
|
type = types.enum [ "server9" "server10" ];
|
|
default = null;
|
|
description = ''
|
|
Server that is supposed to host this MicroVM.
|
|
'';
|
|
};
|
|
|
|
autoNetSetup = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
description = ''
|
|
Automatically configure MicroVM network interfaces and
|
|
systemd-networkd according to Zentralwerk network data.
|
|
'';
|
|
};
|
|
|
|
mounts = mkOption {
|
|
description = "Persistent filesystems to create, without leading /.";
|
|
type = with types; listOf str;
|
|
default = [ "etc" "home" "var" ];
|
|
};
|
|
|
|
mountBase = mkOption {
|
|
description = ''
|
|
Location (ZFS dataset, ...) where all the shares live.
|
|
'';
|
|
type = types.path;
|
|
default = "/var/lib/microvms/${hostName}";
|
|
};
|
|
};
|
|
|
|
config = {
|
|
# autoupdates do not make sense inside MicroVMs with read-only /nix/store
|
|
c3d2.autoUpdate = false;
|
|
|
|
boot = {
|
|
kernel.sysctl = lib.optionalAttrs (config.microvm.mem <= 1024) {
|
|
# table overflow causing packets from nginx to the service to drop
|
|
# nf_conntrack: nf_conntrack: table full, dropping packet
|
|
"net.netfilter.nf_conntrack_max" = "65536";
|
|
};
|
|
kernelParams = [
|
|
"preempt=none"
|
|
# No server/router runs any untrusted user code
|
|
"mitigations=off"
|
|
];
|
|
};
|
|
|
|
hardware.enableRedistributableFirmware = false;
|
|
|
|
microvm = {
|
|
hypervisor = lib.mkDefault "cloud-hypervisor";
|
|
mem = lib.mkDefault 512;
|
|
vcpu = lib.mkDefault 4;
|
|
|
|
interfaces = lib.mkIf config.c3d2.deployment.autoNetSetup (
|
|
map (net: {
|
|
type = "tap";
|
|
id = builtins.substring 0 15 "${net}-${hostName}";
|
|
mac = generateMacAddress net;
|
|
}) nets
|
|
);
|
|
|
|
shares = [ {
|
|
source = "/nix/store";
|
|
mountPoint = "/nix/.ro-store";
|
|
tag = "store";
|
|
proto = "virtiofs";
|
|
socket = "store.socket";
|
|
} ]
|
|
++ map (dir:
|
|
if lib.hasPrefix "/" dir
|
|
then throw "${dir} starts with a leading /. Just don't!"
|
|
else let
|
|
tag = builtins.replaceStrings ["/"] ["_"] dir;
|
|
in {
|
|
source = "${config.c3d2.deployment.mountBase}/${dir}";
|
|
mountPoint = "/${dir}";
|
|
inherit tag;
|
|
proto = "virtiofs";
|
|
socket = "${tag}.socket";
|
|
}) config.c3d2.deployment.mounts;
|
|
};
|
|
|
|
networking = {
|
|
# required that sysctl contains net.netfilter.nf_conntrack_max on boot
|
|
firewall.autoLoadConntrackHelpers = true;
|
|
} // lib.optionalAttrs config.c3d2.deployment.autoNetSetup {
|
|
useDHCP = false;
|
|
dhcpcd.enable = false;
|
|
useNetworkd = true;
|
|
};
|
|
|
|
# nix store is mounted read only
|
|
nix.gc.automatic = false;
|
|
|
|
systemd.network = lib.mkIf config.c3d2.deployment.autoNetSetup {
|
|
links = builtins.foldl' (links: net: links // {
|
|
"30-${net}" = {
|
|
# enable = true;
|
|
matchConfig.MACAddress = generateMacAddress net;
|
|
# rename interface to net name
|
|
linkConfig.Name = net;
|
|
};
|
|
}) {} nets;
|
|
|
|
networks = builtins.foldl' (networks: net: networks // {
|
|
"30-${net}" =
|
|
let
|
|
zwNet = zentralwerk.lib.config.site.net.${net};
|
|
addresses =
|
|
lib.optional (zwNet.hosts4 ? ${hostName}) "${zwNet.hosts4.${hostName}}/${toString zwNet.subnet4Len}"
|
|
++
|
|
map (hosts6: "${hosts6.${hostName}}/64") (
|
|
builtins.filter (hosts6: hosts6 ? ${hostName}) (
|
|
builtins.attrValues zwNet.hosts6
|
|
)
|
|
);
|
|
in {
|
|
matchConfig.MACAddress = generateMacAddress net;
|
|
addresses = map (Address: {
|
|
addressConfig = { inherit Address; };
|
|
}) addresses;
|
|
gateway = lib.mkIf (defaultGateways ? ${net}) (
|
|
let
|
|
gw = defaultGateways.${net};
|
|
in
|
|
[ zwNet.hosts4.${gw} ]
|
|
++ map (hosts6: hosts6.${gw}) (
|
|
builtins.filter (hosts6: hosts6 ? ${gw}) (
|
|
builtins.attrValues zwNet.hosts6
|
|
)
|
|
)
|
|
);
|
|
};
|
|
}) {} nets;
|
|
};
|
|
|
|
simd.arch = arch-to-host.${config.c3d2.deployment.server};
|
|
|
|
system.build = {
|
|
copyToServer = pkgs.writeShellScript "copy-to-${server}" ''
|
|
nix copy --no-check-sigs --to ssh-ng://root@${serverFQDN} $@
|
|
'';
|
|
|
|
runOnServer = pkgs.writeShellScript "run-on-${server}" ''
|
|
ssh root@${serverFQDN} -- $@
|
|
'';
|
|
};
|
|
|
|
systemd.tmpfiles.rules = [
|
|
"d /home/root 0700 root root -" # createHome does not create it
|
|
];
|
|
|
|
users = {
|
|
mutableUsers = false;
|
|
# store root users files persistent, especially .bash_history
|
|
users."root" = {
|
|
createHome = true;
|
|
home = lib.mkForce "/home/root";
|
|
};
|
|
};
|
|
};
|
|
}
|