mirror of
https://github.com/oddlama/nix-config.git
synced 2025-10-11 07:10:39 +02:00
feat(guests): derive stable machine-id for containers; always start sshd in containers
This commit is contained in:
parent
054103a004
commit
eafe3b673c
6 changed files with 74 additions and 43 deletions
|
@ -109,7 +109,9 @@ in {
|
||||||
environment.persistence."/persist" = {
|
environment.persistence."/persist" = {
|
||||||
hideMounts = true;
|
hideMounts = true;
|
||||||
files = [
|
files = [
|
||||||
"/etc/machine-id"
|
# For ephemeral nixos-containers we cannot link the /etc/machine-id file,
|
||||||
|
# because it will be generated based on a stable container uuid.
|
||||||
|
(lib.mkIf (!config.boot.isContainer) "/etc/machine-id")
|
||||||
"/etc/ssh/ssh_host_ed25519_key"
|
"/etc/ssh/ssh_host_ed25519_key"
|
||||||
"/etc/ssh/ssh_host_ed25519_key.pub"
|
"/etc/ssh/ssh_host_ed25519_key.pub"
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
{lib, ...}: {
|
{lib, ...}: {
|
||||||
services.openssh = {
|
services.openssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
# In containers, this is true by default, but we don't want that
|
||||||
|
# because we rely on ssh key generation for agenix
|
||||||
|
startWhenNeeded = lib.mkForce false;
|
||||||
authorizedKeysFiles = lib.mkForce ["/etc/ssh/authorized_keys.d/%u"];
|
authorizedKeysFiles = lib.mkForce ["/etc/ssh/authorized_keys.d/%u"];
|
||||||
settings = {
|
settings = {
|
||||||
PasswordAuthentication = false;
|
PasswordAuthentication = false;
|
||||||
|
|
|
@ -12,6 +12,7 @@ in {
|
||||||
|
|
||||||
systemd.network.networks = {
|
systemd.network.networks = {
|
||||||
"10-${guestCfg.networking.mainLinkName}" = {
|
"10-${guestCfg.networking.mainLinkName}" = {
|
||||||
|
matchConfig.Name = guestCfg.networking.mainLinkName;
|
||||||
DHCP = "yes";
|
DHCP = "yes";
|
||||||
dhcpV4Config.UseDNS = false;
|
dhcpV4Config.UseDNS = false;
|
||||||
dhcpV6Config.UseDNS = false;
|
dhcpV6Config.UseDNS = false;
|
||||||
|
|
|
@ -17,10 +17,13 @@ guestName: guestCfg: {
|
||||||
|
|
||||||
initialLinkName = "mv-${(substring 0 12 (builtins.hashString "sha256" guestName))}";
|
initialLinkName = "mv-${(substring 0 12 (builtins.hashString "sha256" guestName))}";
|
||||||
in {
|
in {
|
||||||
autoStart = guestCfg.autostart;
|
|
||||||
macvlans = ["${guestCfg.container.macvlan}:${initialLinkName}"];
|
|
||||||
ephemeral = true;
|
ephemeral = true;
|
||||||
privateNetwork = true;
|
privateNetwork = true;
|
||||||
|
autoStart = guestCfg.autostart;
|
||||||
|
macvlans = ["${guestCfg.container.macvlan}:${initialLinkName}"];
|
||||||
|
extraFlags = [
|
||||||
|
"--uuid=${builtins.substring 0 32 (builtins.hashString "sha256" guestName)}"
|
||||||
|
];
|
||||||
bindMounts = flip mapAttrs' guestCfg.zfs (
|
bindMounts = flip mapAttrs' guestCfg.zfs (
|
||||||
_: zfsCfg:
|
_: zfsCfg:
|
||||||
nameValuePair zfsCfg.guestMountpoint {
|
nameValuePair zfsCfg.guestMountpoint {
|
||||||
|
@ -64,7 +67,7 @@ in {
|
||||||
# Rename the network interface to our liking
|
# Rename the network interface to our liking
|
||||||
systemd.network.links = {
|
systemd.network.links = {
|
||||||
"01-${guestCfg.networking.mainLinkName}" = {
|
"01-${guestCfg.networking.mainLinkName}" = {
|
||||||
matchConfig.OriginalName = initialLinkName;
|
matchConfig.Name = initialLinkName;
|
||||||
linkConfig.Name = guestCfg.networking.mainLinkName;
|
linkConfig.Name = guestCfg.networking.mainLinkName;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,23 +9,30 @@
|
||||||
inherit
|
inherit
|
||||||
(lib)
|
(lib)
|
||||||
attrValues
|
attrValues
|
||||||
any
|
attrsToList
|
||||||
disko
|
disko
|
||||||
escapeShellArg
|
escapeShellArg
|
||||||
makeBinPath
|
|
||||||
mapAttrsToList
|
|
||||||
mkMerge
|
|
||||||
mergeToplevelConfigs
|
|
||||||
flip
|
flip
|
||||||
|
groupBy
|
||||||
|
listToAttrs
|
||||||
|
makeBinPath
|
||||||
|
mapAttrs
|
||||||
|
mapAttrsToList
|
||||||
|
mergeToplevelConfigs
|
||||||
mkIf
|
mkIf
|
||||||
|
mkMerge
|
||||||
mkOption
|
mkOption
|
||||||
types
|
types
|
||||||
;
|
;
|
||||||
|
|
||||||
|
backends = ["microvm" "container"];
|
||||||
nodeName = config.node.name;
|
nodeName = config.node.name;
|
||||||
|
guestsByBackend =
|
||||||
|
lib.genAttrs backends (_: {})
|
||||||
|
// mapAttrs (_: listToAttrs) (groupBy (x: x.value.backend) (attrsToList config.guests));
|
||||||
|
|
||||||
# Configuration required on the host for a specific guest
|
# Configuration required on the host for a specific guest
|
||||||
defineGuest = guestName: guestCfg: {
|
defineGuest = _guestName: guestCfg: {
|
||||||
# Add the required datasets to the disko configuration of the machine
|
# Add the required datasets to the disko configuration of the machine
|
||||||
disko.devices.zpool = mkMerge (flip map (attrValues guestCfg.zfs) (zfsCfg: {
|
disko.devices.zpool = mkMerge (flip map (attrValues guestCfg.zfs) (zfsCfg: {
|
||||||
${zfsCfg.pool}.datasets.${zfsCfg.dataset} =
|
${zfsCfg.pool}.datasets.${zfsCfg.dataset} =
|
||||||
|
@ -56,33 +63,43 @@
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
# Ensure that the zfs dataset has the correct permissions when mounted
|
|
||||||
"zfs-chown-${utils.escapeSystemdPath zfsCfg.hostMountpoint}" = {
|
|
||||||
after = [fsMountUnit];
|
|
||||||
unitConfig.DefaultDependencies = "no";
|
|
||||||
serviceConfig.Type = "oneshot";
|
|
||||||
script = ''
|
|
||||||
chmod 700 ${escapeShellArg zfsCfg.hostMountpoint}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
"microvm@${guestName}" = mkIf (guestCfg.backend == "microvm") {
|
|
||||||
requires = [fsMountUnit "zfs-chown-${utils.escapeSystemdPath zfsCfg.hostMountpoint}.service"];
|
|
||||||
after = [fsMountUnit "zfs-chown-${utils.escapeSystemdPath zfsCfg.hostMountpoint}.service"];
|
|
||||||
};
|
|
||||||
|
|
||||||
"container@${guestName}" = mkIf (guestCfg.backend == "container") {
|
|
||||||
requires = [fsMountUnit "zfs-chown-${utils.escapeSystemdPath zfsCfg.hostMountpoint}.service"];
|
|
||||||
after = [fsMountUnit "zfs-chown-${utils.escapeSystemdPath zfsCfg.hostMountpoint}.service"];
|
|
||||||
};
|
|
||||||
}));
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
microvm.vms.${guestName} =
|
defineMicrovm = guestName: guestCfg: {
|
||||||
mkIf (guestCfg.backend == "microvm") (import ./microvm.nix guestName guestCfg attrs);
|
# Ensure that the zfs dataset exists before it is mounted.
|
||||||
|
systemd.services."microvm@${guestName}" = let
|
||||||
|
fsMountUnits =
|
||||||
|
map
|
||||||
|
(x: "${utils.escapeSystemdPath x.hostMountpoint}.mount")
|
||||||
|
(attrValues guestCfg.zfs);
|
||||||
|
in {
|
||||||
|
requires = fsMountUnits;
|
||||||
|
after = fsMountUnits;
|
||||||
|
};
|
||||||
|
|
||||||
containers.${guestName} =
|
microvm.vms.${guestName} = import ./microvm.nix guestName guestCfg attrs;
|
||||||
mkIf (guestCfg.backend == "container") (import ./container.nix guestName guestCfg attrs);
|
};
|
||||||
|
|
||||||
|
defineContainer = guestName: guestCfg: {
|
||||||
|
# Ensure that the zfs dataset exists before it is mounted.
|
||||||
|
systemd.services."container@${guestName}" = let
|
||||||
|
fsMountUnits =
|
||||||
|
map
|
||||||
|
(x: "${utils.escapeSystemdPath x.hostMountpoint}.mount")
|
||||||
|
(attrValues guestCfg.zfs);
|
||||||
|
in {
|
||||||
|
requires = fsMountUnits;
|
||||||
|
after = fsMountUnits;
|
||||||
|
# Don't use the notify service type. Using exec will always consider containers
|
||||||
|
# started immediately and donesn't wait until the container is fully booted.
|
||||||
|
# Containers should behave like independent machines, and issues inside the container
|
||||||
|
# will unnecessarily lock up the service on the host otherwise.
|
||||||
|
# This causes issues on system activation.
|
||||||
|
serviceConfig.Type = lib.mkForce "exec";
|
||||||
|
};
|
||||||
|
|
||||||
|
containers.${guestName} = import ./container.nix guestName guestCfg attrs;
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
|
@ -90,10 +107,7 @@ in {
|
||||||
inputs.microvm.nixosModules.host
|
inputs.microvm.nixosModules.host
|
||||||
# This is opt-out, so we can't put this into the mkIf below
|
# This is opt-out, so we can't put this into the mkIf below
|
||||||
{
|
{
|
||||||
microvm.host.enable =
|
microvm.host.enable = guestsByBackend.microvm != {};
|
||||||
any
|
|
||||||
(guestCfg: guestCfg.backend == "microvm")
|
|
||||||
(attrValues config.guests);
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -132,7 +146,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
backend = mkOption {
|
backend = mkOption {
|
||||||
type = types.enum ["microvm" "container"];
|
type = types.enum backends;
|
||||||
description = ''
|
description = ''
|
||||||
Determines how the guest will be hosted. You can currently choose
|
Determines how the guest will be hosted. You can currently choose
|
||||||
between microvm based deployment, or nixos containers.
|
between microvm based deployment, or nixos containers.
|
||||||
|
@ -216,7 +230,16 @@ in {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
config =
|
config = mkIf (config.guests != {}) (
|
||||||
mkIf (config.guests != {})
|
mkMerge [
|
||||||
(mergeToplevelConfigs ["containers" "disko" "microvm" "systemd"] (mapAttrsToList defineGuest config.guests));
|
{
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /guests 0700 root root -"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(mergeToplevelConfigs ["disko" "systemd"] (mapAttrsToList defineGuest config.guests))
|
||||||
|
(mergeToplevelConfigs ["containers" "systemd"] (mapAttrsToList defineContainer guestsByBackend.container))
|
||||||
|
(mergeToplevelConfigs ["microvm" "systemd"] (mapAttrsToList defineMicrovm guestsByBackend.microvm))
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
PTlU+qtfddz0ZfcHcfZmSxZ4Abe8UCpWV2FBJQswzBk=
|
|
Loading…
Add table
Add a link
Reference in a new issue