From 42f2a9b23a7f3edd4befacc27b83247880ac85ba Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 29 Nov 2019 13:05:30 +0100 Subject: [PATCH] Fix yggdrasil service module The configFile option was broken. --- lib/yggdrasil-service.nix | 185 ++++++++++++++++++++++++++++++++++++++ lib/yggdrasil.nix | 9 +- 2 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 lib/yggdrasil-service.nix diff --git a/lib/yggdrasil-service.nix b/lib/yggdrasil-service.nix new file mode 100644 index 00000000..33d1f093 --- /dev/null +++ b/lib/yggdrasil-service.nix @@ -0,0 +1,185 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.yggdrasil; + configProvided = (cfg.config != { }); + configAsFile = (if configProvided then + toString (pkgs.writeTextFile { + name = "yggdrasil-conf"; + text = builtins.toJSON cfg.config; + }) + else + null); + configFileProvided = (cfg.configFile != null); + generateConfig = (if configProvided && configFileProvided then + "${pkgs.jq}/bin/jq -s add ${configAsFile} ${cfg.configFile}" + else if configProvided then + "cat ${configAsFile}" + else if configFileProvided then + "cat ${cfg.configFile}" + else + "${cfg.package}/bin/yggdrasil -genconf"); + +in { + options = with types; { + services.yggdrasil = { + enable = mkEnableOption "the yggdrasil system service"; + + configFile = mkOption { + type = nullOr str; + default = null; + example = "/run/keys/yggdrasil.conf"; + description = '' + A file which contains JSON configuration for yggdrasil. + + You do not have to supply a complete configuration, as + yggdrasil will use default values for anything which is + omitted. If the encryption and signing keys are omitted, + yggdrasil will generate new ones each time the service is + started, resulting in a random IPv6 address on the yggdrasil + network each time. + + If both this option and are + supplied, they will be combined, with values from + taking precedence. + + You can use the command nix-shell -p yggdrasil --run + "yggdrasil -genconf -json" to generate a default + JSON configuration. + ''; + }; + + config = mkOption { + type = attrs; + default = { }; + example = { + Peers = [ + "tcp://aa.bb.cc.dd:eeeee" + "tcp://[aaaa:bbbb:cccc:dddd::eeee]:fffff" + ]; + Listen = [ "tcp://0.0.0.0:xxxxx" ]; + }; + description = '' + Configuration for yggdrasil, as a Nix attribute set. + + Warning: this is stored in the WORLD-READABLE Nix store! + Therefore, it is not appropriate for private keys. If you + do not specify the keys, yggdrasil will generate a new set + each time the service is started, creating a random IPv6 + address on the yggdrasil network each time. + + If you wish to specify the keys, use + . If both + and are + supplied, they will be combined, with values from + taking precedence. + + You can use the command nix-shell -p yggdrasil --run + "yggdrasil -genconf" to generate default + configuration values with documentation. + ''; + }; + + openMulticastPort = mkOption { + type = bool; + default = false; + description = '' + 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 ( or + ) to a port number other than 0, + and then add that port to + . + ''; + }; + + denyDhcpcdInterfaces = mkOption { + type = listOf str; + default = [ ]; + example = [ "tap*" ]; + description = '' + Disable the DHCP client for any interface whose name matches + any of the shell glob patterns in this list. Use this + option to prevent the DHCP client from broadcasting requests + on the yggdrasil network. It is only necessary to do so + when yggdrasil is running in TAP mode, because TUN + interfaces do not support broadcasting. + ''; + }; + + package = mkOption { + type = package; + default = pkgs.yggdrasil; + defaultText = "pkgs.yggdrasil"; + description = "Yggdrasil package to use."; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = [{ + assertion = config.networking.enableIPv6; + message = "networking.enableIPv6 must be true for yggdrasil to work"; + }]; + + systemd.services.yggdrasil = { + description = "Yggdrasil Network Service"; + path = [ cfg.package ] + ++ optional (configProvided && configFileProvided) pkgs.jq; + bindsTo = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + preStart = '' + ${generateConfig} | yggdrasil -normaliseconf -useconf > /run/yggdrasil/yggdrasil.conf + ''; + + serviceConfig = { + ExecStart = + "${cfg.package}/bin/yggdrasil -useconffile /run/yggdrasil/yggdrasil.conf"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + Restart = "always"; + + RuntimeDirectory = "yggdrasil"; + RuntimeDirectoryMode = "0700"; + BindReadOnlyPaths = mkIf configFileProvided [ "${cfg.configFile}" ]; + + # TODO: as of yggdrasil 0.3.8 and systemd 243, yggdrasil fails + # to set up the network adapter when DynamicUser is set. See + # github.com/yggdrasil-network/yggdrasil-go/issues/557. The + # following options are implied by DynamicUser according to + # the systemd.exec documentation, and can be removed if the + # upstream issue is fixed and DynamicUser is set to true: + PrivateTmp = true; + RemoveIPC = true; + NoNewPrivileges = true; + ProtectSystem = "strict"; + RestrictSUIDSGID = true; + # End of list of options implied by DynamicUser. + + AmbientCapabilities = "CAP_NET_ADMIN"; + CapabilityBoundingSet = "CAP_NET_ADMIN"; + MemoryDenyWriteExecute = true; + ProtectControlGroups = true; + ProtectHome = "tmpfs"; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = + "~@clock @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @resources"; + }; + }; + + networking.dhcpcd.denyInterfaces = cfg.denyDhcpcdInterfaces; + networking.firewall.allowedUDPPorts = mkIf cfg.openMulticastPort [ 9001 ]; + + # Make yggdrasilctl available on the command line. + environment.systemPackages = [ cfg.package ]; + }; + meta.maintainers = with lib.maintainers; [ gazally ]; +} diff --git a/lib/yggdrasil.nix b/lib/yggdrasil.nix index 8897294d..f497dc6e 100644 --- a/lib/yggdrasil.nix +++ b/lib/yggdrasil.nix @@ -1,14 +1,9 @@ { config, ... }: { - imports = [ - - ]; - - networking.firewall.extraCommands = - "ip6tables -A INPUT -s fe80::/10 -j ACCEPT"; + imports = [ ./yggdrasil-service.nix ]; services.yggdrasil = { enable = true; - package = (import {}).yggdrasil; + package = (import { }).yggdrasil; openMulticastPort = true; config.NodeInfo = { name = config.networking.hostName + ".c3d2";