Unverified Commit 1e03b82c authored by numinit's avatar numinit Committed by GitHub
Browse files

nixos/nebula: enable reloadable configuration (#460779)

parents 186b25ab cf07ac9e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -446,6 +446,8 @@ and [release notes for v18](https://goteleport.com/docs/changelog/#1800-070325).

- `linux_libre` & `linux_latest_libre` have been removed due to a lack of maintenance.

- `services.nebula.networks.<name>` will now store configuration files in `/etc/nebula/<name>.yml` and supports config reloading.

- `services.pds` has been renamed to `services.bluesky-pds`.

- `services.xserver.desktopManager.deepin` and associated packages have been removed due to being unmaintained. See issue [#422090](https://github.com/NixOS/nixpkgs/issues/422090) for more details.
+81 −41
Original line number Diff line number Diff line
@@ -9,8 +9,54 @@ let
  cfg = config.services.nebula;
  enabledNetworks = lib.filterAttrs (n: v: v.enable) cfg.networks;

  genSettings =
    netName: netCfg:
    lib.recursiveUpdate {
      pki = {
        ca = netCfg.ca;
        cert = netCfg.cert;
        key = netCfg.key;
      };
      static_host_map = netCfg.staticHostMap;
      lighthouse = {
        am_lighthouse = netCfg.isLighthouse;
        hosts = netCfg.lighthouses;
        serve_dns = netCfg.lighthouse.dns.enable;
        dns.host = netCfg.lighthouse.dns.host;
        dns.port = netCfg.lighthouse.dns.port;
      };
      relay = {
        am_relay = netCfg.isRelay;
        relays = netCfg.relays;
        use_relays = true;
      };
      listen = {
        host = netCfg.listen.host;
        port = resolveFinalPort netCfg;
      };
      tun = {
        disabled = netCfg.tun.disable;
        dev = if (netCfg.tun.device != null) then netCfg.tun.device else "nebula.${netName}";
      };
      firewall = {
        inbound = netCfg.firewall.inbound;
        outbound = netCfg.firewall.outbound;
      };
    } netCfg.settings;
  format = pkgs.formats.yaml { };

  genConfigFile =
    netName: settings:
    format.generate "nebula-config-${netName}.yml" (
      lib.warnIf
        ((settings.lighthouse.am_lighthouse || settings.relay.am_relay) && settings.listen.port == 0)
        ''
          Nebula network '${netName}' is configured as a lighthouse or relay, and its port is ${builtins.toString settings.listen.port}.
          You will likely experience connectivity issues: https://nebula.defined.net/docs/config/listen/#listenport
        ''
        settings
    );

  nameToId = netName: "nebula-${netName}";

  resolveFinalPort =
@@ -60,6 +106,16 @@ in
                example = "/etc/nebula/host.key";
              };

              enableReload = lib.mkOption {
                type = lib.types.bool;
                default = false;
                description = ''
                  Enable automatic config reload on config change.
                  This setting is not enabled by default as nix cannot determine if the config change is reloadable.
                  Please refer to the [config reference](https://nebula.defined.net/docs/config/) for documentation on reloadable changes.
                '';
              };

              staticHostMap = lib.mkOption {
                type = lib.types.attrsOf (lib.types.listOf (lib.types.str));
                default = { };
@@ -212,47 +268,13 @@ in
        netName: netCfg:
        let
          networkId = nameToId netName;
          settings = lib.recursiveUpdate {
            pki = {
              ca = netCfg.ca;
              cert = netCfg.cert;
              key = netCfg.key;
            };
            static_host_map = netCfg.staticHostMap;
            lighthouse = {
              am_lighthouse = netCfg.isLighthouse;
              hosts = netCfg.lighthouses;
              serve_dns = netCfg.lighthouse.dns.enable;
              dns.host = netCfg.lighthouse.dns.host;
              dns.port = netCfg.lighthouse.dns.port;
            };
            relay = {
              am_relay = netCfg.isRelay;
              relays = netCfg.relays;
              use_relays = true;
            };
            listen = {
              host = netCfg.listen.host;
              port = resolveFinalPort netCfg;
            };
            tun = {
              disabled = netCfg.tun.disable;
              dev = if (netCfg.tun.device != null) then netCfg.tun.device else "nebula.${netName}";
            };
            firewall = {
              inbound = netCfg.firewall.inbound;
              outbound = netCfg.firewall.outbound;
            };
          } netCfg.settings;
          configFile = format.generate "nebula-config-${netName}.yml" (
            lib.warnIf
              ((settings.lighthouse.am_lighthouse || settings.relay.am_relay) && settings.listen.port == 0)
              ''
                Nebula network '${netName}' is configured as a lighthouse or relay, and its port is ${builtins.toString settings.listen.port}.
                You will likely experience connectivity issues: https://nebula.defined.net/docs/config/listen/#listenport
              ''
              settings
          );
          settings = genSettings netName netCfg;
          generatedConfigFile = genConfigFile netName settings;
          configFile =
            if ((lib.versionAtLeast config.system.stateVersion "25.11") || netCfg.enableReload) then
              "/etc/nebula/${netName}.yml"
            else
              generatedConfigFile;
          capabilities =
            let
              nebulaPort = if !settings.tun.disabled then settings.listen.port else 0;
@@ -278,6 +300,8 @@ in
            ];
            before = [ "sshd.service" ];
            wantedBy = [ "multi-user.target" ];
            restartTriggers = lib.optional (!netCfg.enableReload) generatedConfigFile;
            reloadTriggers = lib.optional netCfg.enableReload generatedConfigFile;
            serviceConfig = {
              Type = "notify";
              Restart = "always";
@@ -313,6 +337,22 @@ in
      ) enabledNetworks
    );

    environment.etc = lib.mkMerge (
      lib.mapAttrsToList
        (netName: netCfg: {
          "nebula/${netName}.yml" = {
            source = genConfigFile netName (genSettings netName netCfg);
            mode = "0440";
            user = nameToId netName;
          };
        })
        (
          lib.filterAttrs (
            _: netCfg: netCfg.enableReload || (lib.versionAtLeast config.system.stateVersion "25.11")
          ) enabledNetworks
        )
    );

    # Open the chosen ports for UDP.
    networking.firewall.allowedUDPPorts = lib.unique (
      lib.filter (port: port > 0) (
+2 −1
Original line number Diff line number Diff line
@@ -1011,7 +1011,8 @@ in
    defaults.services.ncps.cache.dataPath = "/path/to/ncps";
  };
  ndppd = runTest ./ndppd.nix;
  nebula = runTest ./nebula.nix;
  nebula.connectivity = runTest ./nebula/connectivity.nix;
  nebula.reload = runTest ./nebula/reload.nix;
  neo4j = runTest ./neo4j.nix;
  netbird = runTest ./netbird.nix;
  netbox-upgrade = runTest ./web-apps/netbox-upgrade.nix;
+1 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
let

  # We'll need to be able to trade cert files between nodes via scp.
  inherit (import ./ssh-keys.nix pkgs)
  inherit (import ../ssh-keys.nix pkgs)
    snakeOilPrivateKey
    snakeOilPublicKey
    ;
+92 −0
Original line number Diff line number Diff line
{ pkgs, lib, ... }:
let

  inherit (import ../ssh-keys.nix pkgs)
    snakeOilPrivateKey
    snakeOilPublicKey
    ;

in
{
  name = "nebula";

  nodes = {
    lighthouse =
      {
        pkgs,
        lib,
        config,
        ...
      }:
      {
        environment.systemPackages = [ pkgs.nebula ];
        environment.etc."nebula-key" = {
          user = "nebula-smoke";
          group = "nebula-smoke";
          source = snakeOilPrivateKey;
          mode = "0600";
        };

        services.nebula.networks.smoke = {
          # Note that these paths won't exist when the machine is first booted.
          ca = "/etc/nebula/ca.crt";
          cert = "/etc/nebula/lighthouse.crt";
          key = "/etc/nebula/lighthouse.key";
          isLighthouse = true;
          listen = {
            host = "0.0.0.0";
            port = 4242;
          };
          enableReload = true;
          settings.sshd = {
            enabled = true;
            listen = "127.0.0.1:2222";
            host_key = "/etc/nebula-key";
          };
        };

        # We will test that nebula is reloaded by switching specialisations.
        specialisation.sshd-off.configuration = {
          services.nebula.networks.smoke.settings.sshd.enabled = lib.mkForce false;
        };
        specialisation.sshd-on.configuration = {
          services.nebula.networks.smoke.settings.sshd.enabled = lib.mkForce true;
        };
      };
  };

  testScript =
    { nodes, ... }:
    let
      sshd-on = "${nodes.lighthouse.system.build.toplevel}/specialisation/sshd-on";
      sshd-off = "${nodes.lighthouse.system.build.toplevel}/specialisation/sshd-off";
    in
    ''
      # Create the certificate and sign the lighthouse's keys.
      lighthouse.succeed(
          "mkdir -p /etc/nebula",
          'nebula-cert ca -duration $((10*365*24*60))m -name "Smoke Test" -out-crt /etc/nebula/ca.crt -out-key /etc/nebula/ca.key',
          'nebula-cert sign -duration $((365*24*60))m -ca-crt /etc/nebula/ca.crt -ca-key /etc/nebula/ca.key -name "lighthouse" -groups "lighthouse" -ip "10.0.100.1/24" -out-crt /etc/nebula/lighthouse.crt -out-key /etc/nebula/lighthouse.key',
          'chown -R nebula-smoke:nebula-smoke /etc/nebula'
      )

      # Restart nebula to pick up the keys.
      lighthouse.systemctl("restart nebula@smoke.service")
      lighthouse.succeed("ping -c5 10.0.100.1")

      # Verify that nebula's ssh interface is up.
      lighthouse.succeed("${pkgs.nmap}/bin/nmap 127.0.0.1 | grep 2222/tcp")

      # Switch configuration, verify nebula was reloaded and not restarted.
      lighthouse.succeed("${sshd-off}/bin/switch-to-configuration test 2>&1 | grep 'nebula' | grep 'reload'")

      # Verify that nebula's ssh interface is no longer up.
      lighthouse.fail("${pkgs.nmap}/bin/nmap 127.0.0.1 | grep 2222/tcp")

      # Switch configuration, verify reload again.
      lighthouse.succeed("${sshd-on}/bin/switch-to-configuration test 2>&1 | grep 'nebula' | grep 'reload'")

      # Verify that ssh is back.
      lighthouse.succeed("${pkgs.nmap}/bin/nmap 127.0.0.1 | grep 2222/tcp")
    '';
}
Loading