Unverified Commit 5b88469c authored by Ryan Lahfa's avatar Ryan Lahfa Committed by GitHub
Browse files

Merge pull request #217366 from puppe/fix-yggdrasil

nixos/yggdrasil: fix configFile option
parents 54de698c 8bc615d0
Loading
Loading
Loading
Loading
+114 −86
Original line number Diff line number Diff line
@@ -8,7 +8,8 @@ let
  configFileProvided = cfg.configFile != null;

  format = pkgs.formats.json { };
in {
in
{
  imports = [
    (mkRenamedOptionModule
      [ "services" "yggdrasil" "config" ]
@@ -45,7 +46,7 @@ in {

          If no keys are specified then ephemeral keys are generated
          and the Yggdrasil interface will have a random IPv6 address
          each time the service is started, this is the default.
          each time the service is started. This is the default.

          If both {option}`configFile` and {option}`settings`
          are supplied, they will be combined, with values from
@@ -61,8 +62,13 @@ in {
        default = null;
        example = "/run/keys/yggdrasil.conf";
        description = lib.mdDoc ''
          A file which contains JSON configuration for yggdrasil.
          See the {option}`settings` option for more information.
          A file which contains JSON or HJSON configuration for yggdrasil. See
          the {option}`settings` option for more information.

          Note: This file must not be larger than 1 MB because it is passed to
          the yggdrasil process via systemd‘s LoadCredential mechanism. For
          details, see <https://systemd.io/CREDENTIALS/> and `man 5
          systemd.exec`.
        '';
      };

@@ -77,14 +83,14 @@ in {
        type = bool;
        default = false;
        description = lib.mdDoc ''
          Whether to open the UDP port used for multicast peer
          discovery. The NixOS firewall blocks link-local
          communication, so in order to make local peering work you
          will also need to set `LinkLocalTCPPort` in your
          yggdrasil configuration ({option}`settings` or
          {option}`configFile`) to a port number other than 0,
          and then add that port to
          {option}`networking.firewall.allowedTCPPorts`.
          Whether to open the UDP port used for multicast peer discovery. The
          NixOS firewall blocks link-local communication, so in order to make
          incoming local peering work you will also need to configure
          `MulticastInterfaces` in your Yggdrasil configuration
          ({option}`settings` or {option}`configFile`). You will then have to
          add the ports that you configure there to your firewall configuration
          ({option}`networking.firewall.allowedTCPPorts` or
          {option}`networking.firewall.interfaces.<name>.allowedTCPPorts`).
        '';
      };

@@ -118,8 +124,12 @@ in {
    };
  };

  config = mkIf cfg.enable (let binYggdrasil = cfg.package + "/bin/yggdrasil";
  in {
  config = mkIf cfg.enable (
    let
      binYggdrasil = "${cfg.package}/bin/yggdrasil";
      binHjson = "${pkgs.hjson-go}/bin/hjson-cli";
    in
    {
      assertions = [{
        assertion = config.networking.enableIPv6;
        message = "networking.enableIPv6 must be true for yggdrasil to work";
@@ -143,21 +153,38 @@ in {
        before = [ "network.target" ];
        wantedBy = [ "multi-user.target" ];

      preStart =
        (if settingsProvided || configFileProvided || cfg.persistentKeys then
        # This script first prepares the config file, then it starts Yggdrasil.
        # The preparation could also be done in ExecStartPre/preStart but only
        # systemd versions >= v252 support reading credentials in ExecStartPre. As
        # of February 2023, systemd v252 is not yet in the stable branch of NixOS.
        #
        # This could be changed in the future once systemd version v252 has
        # reached NixOS but it does not have to be. Config file preparation is
        # fast enough, it does not need elevated privileges, and `set -euo
        # pipefail` should make sure that the service is not started if the
        # preparation fails. Therefore, it is not necessary to move the
        # preparation to ExecStartPre.
        script = ''
          set -euo pipefail

          # prepare config file
          ${(if settingsProvided || configFileProvided || cfg.persistentKeys then
            "echo "

            + (lib.optionalString settingsProvided
              "'${builtins.toJSON cfg.settings}'")
          + (lib.optionalString configFileProvided "$(cat ${cfg.configFile})")
            + (lib.optionalString configFileProvided
              "$(${binHjson} -c \"$CREDENTIALS_DIRECTORY/yggdrasil.conf\")")
            + (lib.optionalString cfg.persistentKeys "$(cat ${keysPath})")
            + " | ${pkgs.jq}/bin/jq -s add | ${binYggdrasil} -normaliseconf -useconf"
          else
          "${binYggdrasil} -genconf") + " > /run/yggdrasil/yggdrasil.conf";
            "${binYggdrasil} -genconf") + " > /run/yggdrasil/yggdrasil.conf"}

          # start yggdrasil
          ${binYggdrasil} -useconffile /run/yggdrasil/yggdrasil.conf
        '';

        serviceConfig = {
        ExecStart =
          "${binYggdrasil} -useconffile /run/yggdrasil/yggdrasil.conf";
          ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
          Restart = "always";

@@ -165,9 +192,9 @@ in {
          StateDirectory = "yggdrasil";
          RuntimeDirectory = "yggdrasil";
          RuntimeDirectoryMode = "0750";
        BindReadOnlyPaths = lib.optional configFileProvided cfg.configFile
          ++ lib.optional cfg.persistentKeys keysPath;
        ReadWritePaths = "/run/yggdrasil";
          BindReadOnlyPaths = lib.optional cfg.persistentKeys keysPath;
          LoadCredential =
            mkIf configFileProvided "yggdrasil.conf:${cfg.configFile}";

          AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
          CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
@@ -191,7 +218,8 @@ in {

      # Make yggdrasilctl available on the command line.
      environment.systemPackages = [ cfg.package ];
  });
    }
  );
  meta = {
    doc = ./yggdrasil.md;
    maintainers = with lib.maintainers; [ gazally ehmry ];