I think it’s vague, a network-service class could have programs such as
unbound
nsd
samba
you can’t really have the same hardening for them, unbound could work without persistent data requirement, nsd could use only an user defined configuration, samba would need to access the filesystem.
Emphasis on default - nix allows overriding these things really easily for the specific service you need already. This proposal just reduces boilerplate, makes it easier for contributors with less experience to know what they should be setting, and advertises that these things are possible to those who don’t know yet.
Your mixins-alike approach is similar, and probably matches the underlying setting types better, but this one fits better within the existing nixpkgs module system. I think both are good suggestions.
only works if I have the service already installed, which if I’m considering whether I should be using one I probably don’t - and installing it for the sake of checking is about as much effort as looking at its module (perhaps less, considering download times vs my existing local copy of nixpkgs).
But yes, systemd-analyze security is very handy for checking the state of my running system
Nginx has a bunch of recommended* options around security. These options set the defaults for other options. Maybe such a scheme is applicable to systems services as well?
systemd.services.<name>.recommendedHardening or splitting it up into multiple recommendations. Because this only sets defaults of other options, you can still easily override it for a specific service.
I had an idea for something similar in form of additional attrset within systemd service specification:
harden = {
basic = true; # basic setup, like RPC, no SUID, etc.
execOnlyNix = true; # allow executing only binaries from `/nix/store`
protectKernel = true; # disable access to kernel logs, modules and tunables
proc = true; # limit unit view into `/proc`
systemCall = true; # limit system calls and allow only native system call facilities (important on x86-64
onlyLocalhost = true; # allow listening only on localhost
}
I am not 100% sure about the naming of the hardening parts, but the idea is there to discuss.
I have created draft PR with implementation of such options
That’s a lot better than my idea. And you even have a prototype!
What I find critical is that it’s opt-in rather than opt-out. I think it should be the other way around. Rather than enumerating the things it shouldn’t do, you should enumerate the things the service depends on for its function and block everything else by default.
Your “basic” set of hardening allows networking and unix sockets for instance but some services shouldn’t even have access to that. It’d be great if I could declare such a service simply by saying harden.enable = true;.
If I had a similarly basic service but it needs network access, I would then be able to say:
Yes, but I wanted to start without breaking everything in this PR, as for example sshd in most cases will require almost all of these options disabled.
EDIT: I got what you meant. I have changed the PR to address that and now it uses harden.enable to enable everything and then you can opt-out of some hardening options.
Yeah, but I am still learning Nixpkgs modules type system and I haven’t yet checked if this accepts sum types like that.
Yeah, that would be reasonable. And by default we could allow only AF_UNIX sockets or none at all.