diff options
Diffstat (limited to 'nixos/modules/services/networking')
-rw-r--r-- | nixos/modules/services/networking/dnscrypt-proxy.nix | 321 | ||||
-rw-r--r-- | nixos/modules/services/networking/dnscrypt-proxy.xml | 69 | ||||
-rw-r--r-- | nixos/modules/services/networking/dnscrypt-wrapper.nix | 10 | ||||
-rw-r--r-- | nixos/modules/services/networking/kresd.nix | 21 | ||||
-rw-r--r-- | nixos/modules/services/networking/mosquitto.nix | 14 | ||||
-rw-r--r-- | nixos/modules/services/networking/openvpn.nix | 28 | ||||
-rw-r--r-- | nixos/modules/services/networking/ssh/sshd.nix | 12 |
7 files changed, 458 insertions, 17 deletions
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix new file mode 100644 index 000000000000..857657eea4db --- /dev/null +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -0,0 +1,321 @@ +{ config, lib, pkgs, ... }: +with lib; + +let + cfg = config.services.dnscrypt-proxy; + + stateDirectory = "/var/lib/dnscrypt-proxy"; + + # The minisign public key used to sign the upstream resolver list. + # This is somewhat more flexible than preloading the key as an + # embedded string. + upstreamResolverListPubKey = pkgs.fetchurl { + url = https://raw.githubusercontent.com/dyne/dnscrypt-proxy/master/minisign.pub; + sha256 = "18lnp8qr6ghfc2sd46nn1rhcpr324fqlvgsp4zaigw396cd7vnnh"; + }; + + # Internal flag indicating whether the upstream resolver list is used. + useUpstreamResolverList = cfg.customResolver == null; + + # The final local address. + localAddress = "${cfg.localAddress}:${toString cfg.localPort}"; + + # The final resolvers list path. + resolverList = "${stateDirectory}/dnscrypt-resolvers.csv"; + + # Build daemon command line + + resolverArgs = + if (cfg.customResolver == null) + then + [ "-L ${resolverList}" + "-R ${cfg.resolverName}" + ] + else with cfg.customResolver; + [ "-N ${name}" + "-k ${key}" + "-r ${address}:${toString port}" + ]; + + daemonArgs = + [ "-a ${localAddress}" ] + ++ resolverArgs + ++ cfg.extraArgs; +in + +{ + meta = { + maintainers = with maintainers; [ joachifm ]; + doc = ./dnscrypt-proxy.xml; + }; + + options = { + # Before adding another option, consider whether it could + # equally well be passed via extraArgs. + + services.dnscrypt-proxy = { + enable = mkOption { + default = false; + type = types.bool; + description = "Whether to enable the DNSCrypt client proxy"; + }; + + localAddress = mkOption { + default = "127.0.0.1"; + type = types.str; + description = '' + Listen for DNS queries to relay on this address. The only reason to + change this from its default value is to proxy queries on behalf + of other machines (typically on the local network). + ''; + }; + + localPort = mkOption { + default = 53; + type = types.int; + description = '' + Listen for DNS queries to relay on this port. The default value + assumes that the DNSCrypt proxy should relay DNS queries directly. + When running as a forwarder for another DNS client, set this option + to a different value; otherwise leave the default. + ''; + }; + + resolverName = mkOption { + default = "random"; + example = "dnscrypt.eu-nl"; + type = types.nullOr types.str; + description = '' + The name of the DNSCrypt resolver to use, taken from + <filename>${resolverList}</filename>. The default is to + pick a random non-logging resolver that supports DNSSEC. + ''; + }; + + customResolver = mkOption { + default = null; + description = '' + Use an unlisted resolver (e.g., a private DNSCrypt provider). For + advanced users only. If specified, this option takes precedence. + ''; + type = types.nullOr (types.submodule ({ ... }: { options = { + address = mkOption { + type = types.str; + description = "IP address"; + example = "208.67.220.220"; + }; + + port = mkOption { + type = types.int; + description = "Port"; + default = 443; + }; + + name = mkOption { + type = types.str; + description = "Fully qualified domain name"; + example = "2.dnscrypt-cert.example.com"; + }; + + key = mkOption { + type = types.str; + description = "Public key"; + example = "B735:1140:206F:225D:3E2B:D822:D7FD:691E:A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79"; + }; + }; })); + }; + + extraArgs = mkOption { + default = []; + type = types.listOf types.str; + description = '' + Additional command-line arguments passed verbatim to the daemon. + See <citerefentry><refentrytitle>dnscrypt-proxy</refentrytitle> + <manvolnum>8</manvolnum></citerefentry> for details. + ''; + example = [ "-X libdcplugin_example_cache.so,--min-ttl=60" ]; + }; + }; + }; + + config = mkIf cfg.enable (mkMerge [{ + assertions = [ + { assertion = (cfg.customResolver != null) || (cfg.resolverName != null); + message = "please configure upstream DNSCrypt resolver"; + } + ]; + + users.users.dnscrypt-proxy = { + description = "dnscrypt-proxy daemon user"; + isSystemUser = true; + group = "dnscrypt-proxy"; + }; + users.groups.dnscrypt-proxy = {}; + + systemd.sockets.dnscrypt-proxy = { + description = "dnscrypt-proxy listening socket"; + documentation = [ "man:dnscrypt-proxy(8)" ]; + + wantedBy = [ "sockets.target" ]; + + socketConfig = { + ListenStream = localAddress; + ListenDatagram = localAddress; + }; + }; + + systemd.services.dnscrypt-proxy = { + description = "dnscrypt-proxy daemon"; + documentation = [ "man:dnscrypt-proxy(8)" ]; + + before = [ "nss-lookup.target" ]; + after = [ "network.target" ]; + requires = [ "dnscrypt-proxy.socket "]; + + serviceConfig = { + NonBlocking = "true"; + ExecStart = "${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + + User = "dnscrypt-proxy"; + + PrivateTmp = true; + PrivateDevices = true; + ProtectHome = true; + }; + }; + } + + (mkIf config.security.apparmor.enable { + systemd.services.dnscrypt-proxy.after = [ "apparmor.service" ]; + + security.apparmor.profiles = singleton (pkgs.writeText "apparmor-dnscrypt-proxy" '' + ${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy { + /dev/null rw, + /dev/urandom r, + + /etc/passwd r, + /etc/group r, + ${config.environment.etc."nsswitch.conf".source} r, + + ${getLib pkgs.glibc}/lib/*.so mr, + ${pkgs.tzdata}/share/zoneinfo/** r, + + network inet stream, + network inet6 stream, + network inet dgram, + network inet6 dgram, + + ${getLib pkgs.dnscrypt-proxy}/lib/dnscrypt-proxy/libdcplugin*.so mr, + + ${getLib pkgs.gcc.cc}/lib/libssp.so.* mr, + ${getLib pkgs.libsodium}/lib/libsodium.so.* mr, + ${getLib pkgs.systemd}/lib/libsystemd.so.* mr, + ${getLib pkgs.xz}/lib/liblzma.so.* mr, + ${getLib pkgs.libgcrypt}/lib/libgcrypt.so.* mr, + ${getLib pkgs.libgpgerror}/lib/libgpg-error.so.* mr, + ${getLib pkgs.libcap}/lib/libcap.so.* mr, + ${getLib pkgs.lz4}/lib/liblz4.so.* mr, + ${getLib pkgs.attr}/lib/libattr.so.* mr, # */ + + ${resolverList} r, + + /run/systemd/notify rw, + } + ''); + }) + + (mkIf useUpstreamResolverList { + systemd.services.init-dnscrypt-proxy-statedir = { + description = "Initialize dnscrypt-proxy state directory"; + + wantedBy = [ "dnscrypt-proxy.service" ]; + before = [ "dnscrypt-proxy.service" ]; + + script = '' + mkdir -pv ${stateDirectory} + chown -c dnscrypt-proxy:dnscrypt-proxy ${stateDirectory} + cp -uv \ + ${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv \ + ${stateDirectory} + ''; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + + systemd.services.update-dnscrypt-resolvers = { + description = "Update list of DNSCrypt resolvers"; + + requires = [ "init-dnscrypt-proxy-statedir.service" ]; + after = [ "init-dnscrypt-proxy-statedir.service" ]; + + path = with pkgs; [ curl diffutils dnscrypt-proxy minisign ]; + script = '' + cd ${stateDirectory} + domain=raw.githubusercontent.com + get="curl -fSs --resolve $domain:443:$(hostip -r 8.8.8.8 $domain | head -1)" + $get -o dnscrypt-resolvers.csv.tmp \ + https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv + $get -o dnscrypt-resolvers.csv.minisig.tmp \ + https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv.minisig + mv dnscrypt-resolvers.csv.minisig{.tmp,} + if ! minisign -q -V -p ${upstreamResolverListPubKey} \ + -m dnscrypt-resolvers.csv.tmp -x dnscrypt-resolvers.csv.minisig ; then + echo "failed to verify resolver list!" >&2 + exit 1 + fi + [[ -f dnscrypt-resolvers.csv ]] && mv dnscrypt-resolvers.csv{,.old} + mv dnscrypt-resolvers.csv{.tmp,} + if cmp dnscrypt-resolvers.csv{,.old} ; then + echo "no change" + else + echo "resolver list updated" + fi + ''; + + serviceConfig = { + PrivateTmp = true; + PrivateDevices = true; + ProtectHome = true; + ProtectSystem = "strict"; + ReadWritePaths = "${dirOf stateDirectory} ${stateDirectory}"; + SystemCallFilter = "~@mount"; + }; + }; + + systemd.timers.update-dnscrypt-resolvers = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = "5min"; + OnUnitActiveSec = "6h"; + }; + }; + }) + ]); + + imports = [ + (mkRenamedOptionModule [ "services" "dnscrypt-proxy" "port" ] [ "services" "dnscrypt-proxy" "localPort" ]) + + (mkChangedOptionModule + [ "services" "dnscrypt-proxy" "tcpOnly" ] + [ "services" "dnscrypt-proxy" "extraArgs" ] + (config: + let val = getAttrFromPath [ "services" "dnscrypt-proxy" "tcpOnly" ] config; in + optional val "-T")) + + (mkChangedOptionModule + [ "services" "dnscrypt-proxy" "ephemeralKeys" ] + [ "services" "dnscrypt-proxy" "extraArgs" ] + (config: + let val = getAttrFromPath [ "services" "dnscrypt-proxy" "ephemeralKeys" ] config; in + optional val "-E")) + + (mkRemovedOptionModule [ "services" "dnscrypt-proxy" "resolverList" ] '' + The current resolver listing from upstream is always used + unless a custom resolver is specified. + '') + ]; +} diff --git a/nixos/modules/services/networking/dnscrypt-proxy.xml b/nixos/modules/services/networking/dnscrypt-proxy.xml new file mode 100644 index 000000000000..555c6df4d551 --- /dev/null +++ b/nixos/modules/services/networking/dnscrypt-proxy.xml @@ -0,0 +1,69 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="sec-dnscrypt-proxy"> + + <title>DNSCrypt client proxy</title> + + <para> + The DNSCrypt client proxy relays DNS queries to a DNSCrypt enabled + upstream resolver. The traffic between the client and the upstream + resolver is encrypted and authenticated, mitigating the risk of MITM + attacks, DNS poisoning attacks, and third-party snooping (assuming the + upstream is trustworthy). + </para> + + <sect1><title>Basic configuration</title> + + <para> + To enable the client proxy, set + <programlisting> + services.dnscrypt-proxy.enable = true; + </programlisting> + </para> + + <para> + Enabling the client proxy does not alter the system nameserver; to + relay local queries, prepend <literal>127.0.0.1</literal> to + <option>networking.nameservers</option>. + </para> + + </sect1> + + <sect1><title>As a forwarder for another DNS client</title> + + <para> + To run the DNSCrypt proxy client as a forwarder for another + DNS client, change the default proxy listening port to a + non-standard value and point the other client to it: + <programlisting> + services.dnscrypt-proxy.localPort = 43; + </programlisting> + </para> + + <sect2><title>dnsmasq</title> + <para> + <programlisting> + { + services.dnsmasq.enable = true; + services.dnsmasq.servers = [ "127.0.0.1#43" ]; + } + </programlisting> + </para> + </sect2> + + <sect2><title>unbound</title> + <para> + <programlisting> + { + services.unbound.enable = true; + services.unbound.forwardAddresses = [ "127.0.0.1@43" ]; + } + </programlisting> + </para> + </sect2> + + </sect1> + +</chapter> diff --git a/nixos/modules/services/networking/dnscrypt-wrapper.nix b/nixos/modules/services/networking/dnscrypt-wrapper.nix index 23cc92946e41..bf13d5c6f5fe 100644 --- a/nixos/modules/services/networking/dnscrypt-wrapper.nix +++ b/nixos/modules/services/networking/dnscrypt-wrapper.nix @@ -145,6 +145,16 @@ in { }; users.groups.dnscrypt-wrapper = { }; + security.polkit.extraConfig = '' + // Allow dnscrypt-wrapper user to restart dnscrypt-wrapper.service + polkit.addRule(function(action, subject) { + if (action.id == "org.freedesktop.systemd1.manage-units" && + action.lookup("unit") == "dnscrypt-wrapper.service" && + subject.user == "dnscrypt-wrapper") { + return polkit.Result.YES; + } + }); + ''; systemd.services.dnscrypt-wrapper = { description = "dnscrypt-wrapper daemon"; diff --git a/nixos/modules/services/networking/kresd.nix b/nixos/modules/services/networking/kresd.nix index 18e2ab9aebf1..011a9b2f58ea 100644 --- a/nixos/modules/services/networking/kresd.nix +++ b/nixos/modules/services/networking/kresd.nix @@ -72,6 +72,7 @@ in (iface: if elem ":" (stringToCharacters iface) then "[${iface}]:53" else "${iface}:53") cfg.interfaces; socketConfig.ListenDatagram = listenStreams; + socketConfig.FreeBind = true; }; systemd.sockets.kresd-control = rec { @@ -82,20 +83,11 @@ in socketConfig = { FileDescriptorName = "control"; Service = "kresd.service"; - SocketMode = "0660"; # only root user/group may connect + SocketMode = "0660"; # only root user/group may connect and control kresd }; }; - # Create the cacheDir; tmpfiles don't work on nixos-rebuild switch. - systemd.services.kresd-cachedir = { - serviceConfig.Type = "oneshot"; - script = '' - if [ ! -d '${cfg.cacheDir}' ]; then - mkdir -p '${cfg.cacheDir}' - chown kresd:kresd '${cfg.cacheDir}' - fi - ''; - }; + systemd.tmpfiles.rules = [ "d '${cfg.cacheDir}' 0770 kresd kresd - -" ]; systemd.services.kresd = { description = "Knot-resolver daemon"; @@ -104,16 +96,15 @@ in User = "kresd"; Type = "notify"; WorkingDirectory = cfg.cacheDir; + Restart = "on-failure"; }; script = '' exec '${package}/bin/kresd' --config '${configFile}' \ - -k '${cfg.cacheDir}/root.key' + -k '${pkgs.dns-root-data}/root.key' ''; - after = [ "kresd-cachedir.service" ]; - requires = [ "kresd.socket" "kresd-cachedir.service" ]; - wantedBy = [ "sockets.target" ]; + requires = [ "kresd.socket" ]; }; }; } diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix index 81915b5a2ef8..273ca797b98d 100644 --- a/nixos/modules/services/networking/mosquitto.nix +++ b/nixos/modules/services/networking/mosquitto.nix @@ -12,6 +12,10 @@ let keyfile ${cfg.ssl.keyfile} ''; + passwordConf = optionalString cfg.checkPasswords '' + password_file ${cfg.dataDir}/passwd + ''; + mosquittoConf = pkgs.writeText "mosquitto.conf" '' pid_file /run/mosquitto/pid acl_file ${aclFile} @@ -19,6 +23,7 @@ let allow_anonymous ${boolToString cfg.allowAnonymous} bind_address ${cfg.host} port ${toString cfg.port} + ${passwordConf} ${listenerConf} ${cfg.extraConf} ''; @@ -153,6 +158,15 @@ in ''; }; + checkPasswords = mkOption { + default = false; + example = true; + type = types.bool; + description = '' + Refuse connection when clients provide incorrect passwords. + ''; + }; + extraConf = mkOption { default = ""; type = types.lines; diff --git a/nixos/modules/services/networking/openvpn.nix b/nixos/modules/services/networking/openvpn.nix index 3fbf5a9f0227..7a96b673c51e 100644 --- a/nixos/modules/services/networking/openvpn.nix +++ b/nixos/modules/services/networking/openvpn.nix @@ -50,6 +50,11 @@ let "up ${pkgs.writeScript "openvpn-${name}-up" upScript}"} ${optionalString (cfg.down != "" || cfg.updateResolvConf) "down ${pkgs.writeScript "openvpn-${name}-down" downScript}"} + ${optionalString (cfg.authUserPass != null) + "auth-user-pass ${pkgs.writeText "openvpn-credentials-${name}" '' + ${cfg.authUserPass.username} + ${cfg.authUserPass.password} + ''}"} ''; in { @@ -161,6 +166,29 @@ in ''; }; + authUserPass = mkOption { + default = null; + description = '' + This option can be used to store the username / password credentials + with the "auth-user-pass" authentication method. + + WARNING: Using this option will put the credentials WORLD-READABLE in the Nix store! + ''; + type = types.nullOr (types.submodule { + + options = { + username = mkOption { + description = "The username to store inside the credentials file."; + type = types.string; + }; + + password = mkOption { + description = "The password to store inside the credentials file."; + type = types.string; + }; + }; + }); + }; }; }); diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index aa9c0fa1c09f..d9b12d278160 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -21,7 +21,7 @@ let daemon reads in addition to the the user's authorized_keys file. You can combine the <literal>keys</literal> and <literal>keyFiles</literal> options. - Warning: If you are using <literal>NixOps</literal> then don't use this + Warning: If you are using <literal>NixOps</literal> then don't use this option since it will replace the key required for deployment via ssh. ''; }; @@ -137,6 +137,14 @@ in ''; }; + openFirewall = mkOption { + type = types.bool; + default = true; + description = '' + Whether to automatically open the specified ports in the firewall. + ''; + }; + listenAddresses = mkOption { type = with types; listOf (submodule { options = { @@ -302,7 +310,7 @@ in }; - networking.firewall.allowedTCPPorts = cfg.ports; + networking.firewall.allowedTCPPorts = if cfg.openFirewall then cfg.ports else []; security.pam.services.sshd = { startSession = true; |