New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add stubby
DNS-over-TLS service module
#38586
Add stubby
DNS-over-TLS service module
#38586
Conversation
stubby
DNS-over-TLS service module
tls_pubkey_pinset: | ||
- digest: "sha256" | ||
value: foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9Q= | ||
''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make a comment on where to find these values?
users.extraUsers.stubby = { | ||
description = "stubby daemon user"; | ||
isSystemUser = true; | ||
group = "root"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a system user and in group root?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This service could also use systemd's DynamicUser
, but using stubby
as a group would be also a good start.
|
||
systemd.services.stubby = { | ||
description = "Stubby local DNS resolver"; | ||
wantedBy = [ "multi-user.target" ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think after = [ "network.target" ]
should be here as well, not entirely sure though, since this module does DNS..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
network.target is correct, since there might be static ip addresses, the service should bind to.
preStart = '' | ||
if [ ! -d ${stateDir} ]; then | ||
mkdir ${stateDir} | ||
fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you set the users home directory and createHome = true
then you won't need this, the tmpfiles. and the WorkingDirectory
attribute. Default permissions for a home directory are 700 though. Why did you use 750 with the root group? root can always read everything anyways.
''; | ||
|
||
serviceConfig = { | ||
ExecStart = "${pkgs.stubby}/bin/stubby -C ${stateDir}/stubby.yml"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the man page it seems that stateDir
is not even needed actually. Just using ${pkgs.stubby}/bin/stubby -C ${confFile}
should work too, without any of the directory set up commands.
${cfg.extraConfig} | ||
upstream_recursive_servers: | ||
${cfg.upstreamServers} | ||
''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a good case to use the toYAML function in lib. You could have a single option services.stubby.config
of type attrsOf unspecified
, set a default value of { resolution_type = "GETDNS_RESOLUTION_STUB"; ... }
and then users can override this config with their own values without removing all others (not 100% sure about that though). Then you can use toYAML
to generate the config. This has the benefit of not messing up string formatting in any, being easier to enter in Nix, and also being able to override all default settings (the edns_client_subnet_private: 1
can't be overridden here, and every overridable option would need its own option). extraConfig
also becomes irrelevant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To still enable the user to pass their own config file without having to convert it to Nix, you could have another option configFile
which would be set to the generated yaml file from config
by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh and you could even still keep all the options with the descriptions if you want, using such a config
option backed by toYAML
can do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I seem to be having some trouble using toYAML
for this. Right now, toYAML
just calls builtin.toJSON
, which produces a JSON configuration file. The trouble is, stubby
has an altogether different (and more complex) JSON format that it also accepts, and so they don't line up quite right. It also seems to expect a complete configuration file in the JSON case, rather than merging explicitly set values with the defaults the way it does with YAML.
I will keep experimenting. It's possible I'm still doing something wrong. Are there plans to produce proper YAML with toYAML
in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well that's not good what they're doing.. Because YAML is a superset of JSON, every JSON is also a valid YAML.
From their source I found that they use the YAML processing when the file ends with .yml
or .yaml
though (see https://github.com/getdnsapi/stubby/blob/4b9b0362f97d8db61cd0294c57f583437a5f47b4/src/stubby.c#L280-L281), so I think it should work if you do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, so it still seems something about their parser isn't happy with JSON. I took a confirmed-valid YAML configuration (the default), yaml.load
ed and json.dump
ed to JSON, and started the daemon by pointing it at that config file, and I still got the following:
Apr 08 18:30:28 nixos stubby[14459]: Error parsing config file "/var/lib/stubby/.stubby.yml": Did not update the context
To be fair, their parser also occasionally has trouble with even valid YAML (IPv6 addresses with leading and trailing colons).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh god, they're rolling their own YAML parser and it doesn't even work correctly :/ (yes YAML parsers are hard but JSON compatibility is the least they could do)
Can you file an issue at their repo for this? If they don't fix this soon this module will just have to roll with the inflexible configuration method. I don't think adjusting our toYAML
function for this is reasonable, as it does indeed work correctly (and since it outputs JSON, Nix can easily parse it again with builtins.fromJSON
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
totally agree regarding the functionality of toYAML
vs them rolling their own parser. I will open that issue. In the meantime, I add in your suggestions to the previous way.
In any case, thank you for making me aware of toYAML
, as it's bound to come in handy sooner than later.
Hey @infinisil, thanks for all the great feedback! I'll incorporate your suggestions. In particular I hadn't seen the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Round 2, still some stuff left, but it's getting there :D
ExecStart = "${pkgs.stubby}/bin/stubby -C ${confFile}"; | ||
AmbientCapabilities = "CAP_NET_BIND_SERVICE"; | ||
CapabilitiesBoundingSet = "CAP_NET_BIND_SERVICE"; | ||
User = "stubby"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the user now doesn't require any directory, you can remove the whole users.extraUsers..
part, and as suggested by @Mic92 use systemd's DynamicUser feature (documented in man systemd.exec
). Just setting serviceConfig.DynamicUser = true;
should do it. Then this User =
can also be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works very well, thanks.
serviceConfig = { | ||
ExecStart = "${pkgs.stubby}/bin/stubby -C ${confFile}"; | ||
AmbientCapabilities = "CAP_NET_BIND_SERVICE"; | ||
CapabilitiesBoundingSet = "CAP_NET_BIND_SERVICE"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never played around with capabilities in systemd, are both of these required for the unprivileged user to bind to ports < 1024?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, stubby
(and DNS-over-TLS in general, I think) binds by default to 853. It's possible to listen on higher ports, however. I am working on a function in the let
expression using lib.splitString
that should allow this capability to be set only when absolutely necessary (i.e., if the listening port is < 1024).
stateDir = "/var/lib/stubby"; | ||
fallbacks = concatMapStringsSep "\n " (x: "- ${x}") cfg.fallbackProtocols; | ||
listeners = concatMapStringsSep "\n " (x: "- ${x}") cfg.listenAddresses; | ||
extraConfig = optionalString (cfg.extraConfig != "") '' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This value doesn't seem to be used anywhere
|
||
queryPaddingBlocksize = mkOption { | ||
default = "128"; | ||
type = types.str; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This option and a few others should probably be of types.int
instead of types.str
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this results in a coercion error, because these values are interpolated into the configuration file string. Does it make more sense to coerce them beforehand in the let
expression, or should we just declare them as types.str
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use the function toString
to convert them: tls_query_padding_blocksize: ${toString cfg.queryPaddingBlocksize}
|
||
roundRobinUpstreams = mkOption { | ||
default = "1"; | ||
type = types.str; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be types.bool
, also for subnetPrivate
(and update option descriptions accordingly)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And for booleans you can use a simple if cfg.roundRobinUpstreams then "1" else "0"
}; | ||
|
||
upstreamServers = mkOption { | ||
default = "${defaultUpstream}"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the same as default = defaultUpstream;
listeners = concatMapStringsSep "\n " (x: "- ${x}") cfg.listenAddresses; | ||
|
||
# split string at @ to get the listening port. | ||
getPort = x: toInt (builtins.elemAt (splitString "@" x) 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I only specify:
{}: {
services.stubby.enable = true;
}
I get:
error: list index 1 is out of bounds, at /home/joerg/git/nixpkgs/nixos/modules/services/networking/stubby.nix:13:23
(use '--show-trace' to show detailed location information)
make: *** [Makefile:7: test] Error 1
make: Leaving directory '/home/joerg/git/nixos-shell'
}; | ||
|
||
listenAddresses = mkOption { | ||
default = [ "127.0.0.1" "0::1" ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the default values still work here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oof! good catch. thanks.
You have opened the pull request against |
@baroncharlus you should rebase your changes onto the master branch with git-rebase. If you don't know how to do this, just readd your changes on the checkout master branch and open a new pull request. |
(cherry picked from commit f9bb730)
(cherry picked from commit ee1896d)
(cherry picked from commit b9bde5b)
(cherry picked from commit 804789e)
(cherry picked from commit c8e2312)
(cherry picked from commit 32e47b1)
(cherry picked from commit 2dfaf69)
(cherry picked from commit 6545d15)
(cherry picked from commit e0fbaaa)
This reverts commit 48856a9.
This reverts commit 2d2ab94.
(cherry picked from commit 72e8987)
(cherry picked from commit e8ad790)
service-runner had a backwards incompatible update, and parsoid 0.9.0 doesn't work with current stable MediaWiki. Instead use as a source a repository with 0.8.0 and pinned service-runner version. (cherry picked from commit 37546be)
Based on how ISO images are added to the release. (cherry picked from commit 181e067)
because of a change in #36850. spotted by @jtojnar b7a2333#commitcomment-28134992 (cherry picked from commit 33b0ad8)
https://hydra.nixos.org/build/70699663 This package is already dropped on master, after the 18.03 cut-off.
… future commits. (cherry picked from commit fccddb2)
(cherry picked from commit c011843)
(cherry picked from commit 650aec3)
(cherry picked from commit b9e5aea)
(cherry picked from commit 4df34f8)
- Rectifies diverging CSS by combining nixos/nixpkgs docs CSS - Moves our custom Highlight.js loader in to the hljs package - Switches the nixos docs to use SVG callouts too (cherry picked from commit 8f33464)
stubby This change allows a user to declare a configuration for stubby in /etc/nixos/configuration.nix. nixos/modules/module-list.nix: adding stubby.nix to module-list Enabling module. nixos/modules/services/networking/stubby.nix: Adding documentation Adding documentation to each mkOption. networking/stubby.nix: changing daemon user permissions This change normalizes some of the directory permissions and conf file creation processes. networking/stubby.nix: Removing unneeded systemd cruft WorkingDir and tempfile are no longer needed when the user has a homedir. networking/stubby.nix: adding more detailed resolver docs Adding more detailed information on where to find your own upstream resolver settings. Also adding wants = network.target to the systemd configuration. networking/stubby.nix: updating docs and adding edns option. Fixing an issue where the default docs were breaking docs compilation. Adding a mkOption for EDNS private subnet settings. networking/stubby.nix: Boolean-izing string values Changes the two 0|1 settings in stubby.yml to booleans from strings. networking/stubby.nix: adding capabilities toggle for high/low ports This change automatically applies or removes capabilities to the service based upon the ports selected by the user.
Whoops, that didn't work. Closing and reopening a bit later. |
Motivation for this change
This change provides a module wrapper for the
stubby
package maintained by @leenaars. it allows the user to customize the service configuration. This was prompted by my wish to rununbound
andstubby
in tandem on my NixOS machine.Things done
This change implements the systemd service and ability to easily declare certain common
stubby
settings fromconfiguration.nix
.build-use-sandbox
innix.conf
on non-NixOS)nix-shell -p nox --run "nox-review wip"
./result/bin/
)I tested this by building and running the service successfully on my system. In particular, I tested passing in custom values the listening addresses.
Example configuration with
unbound
: