Nixpkgs: The service interface should abide by the principle of least privilege

Created on 13 Apr 2016  路  18Comments  路  Source: NixOS/nixpkgs

The problem

Currently, services default to running as root with unlimited network & file system access. Service authors must actively take away capabilities, which is error prone and requires extensive knowledge of systemd directives. Writing least privilege services requires the most effort, it should be the other way around.

The solution

The solution is two-fold:

  1. Default to least privilege. User=nobody, enable ProtectHome, PrivateTmp, and ideally also PrivateNetwork and PrivateDevices. We WANT stuff to break if the author hasn't taken the time to enumerate what the service actually needs.
  2. Expose common options for defining privileges/capabilities.
    Examples: capabilities = [ "mknod" "net_admin" ], privateTmp = true

How to get there

  1. Documentation: add a section in the manual about writing services, with helpful tips, things to consider & systemd directives
  2. Slowly introduce new options and migrate existing services to least privilege

Eventually, all existing services should be least privilege and all new services default to least privilege.

See also

https://wiki.archlinux.org/index.php/DeveloperWiki:Security#Service_Isolation contains useful information and links to further reading about service isolation.

enhancement security nixos documentation module (update)

Most helpful comment

All 18 comments

A dump of things that could be included in a hypothetical service writing chapter: https://gist.github.com/joachifm/022ca74fd447bd8bb2f80a133c0ab3a9

Big +1 from me.

We shouldn't default to User=nobody, because then all services which don't specify a user will be running as the same UID, breaking isolation. Instead, we should have no default at all and instead require a value to be set (I'm not 100% sure on how to do this - maybe a required function argument?)

@aneeshusa that is certainly something to consider. It could be solved by a simple assert. I have thought about setting default based on the name of the service; with dynamic users/groups there's no real danger of running out, the only possible issue is encroaching on users and groups created by the user.

That said, User=nobody services would be hamstrung to the point of not having much useful information to leak.

The ideal configuration would have each daemon running with a distinct filesystem, network, device, and process namespace with explicit namespace sharing, so users and groups would mostly be used to regulate access to filesystem state. Any process without CAP_SYS_ADMIN would then be more or less confined, regardless of DAC.

big +1 from me as well.

@joachifm i am worried how would the migration of services be like. we dont want to break every service right? would this be possible to introduce gradually?

@garbas I have a few options in mind.

First is to only do docs + reify some systemd directives to make it more convenient to specify privileges, but not change any defaults.

Second is to change the defaults, but make them conditional on an internal flag that is set for all (or some) existing services, making new services least privilege by default while minimizing disruption. Equivalently, introduce a new service option namespace that's least privilege by default.

Third is to change the defaults and hope that the fallout isn't too bad. It's probably wishful thinking on my part, but I'm convinced that only a minority of services would actually _break_ due to this.

In any event, getting to least privilege is a massive undertaking, so I'm content to close this once we have some docs and have reified the most important systemd directives, anything beyond that isn't realistic, in my opinion.

@joachim +1

I really don't see obsticales here except getting it done. Switching the defaults to restrictive can only be the last step, otherwise lots of modules will break. Maybe a goal for post 16.09?

Has any work been done on this?

I don't think so but I plan on doing so after getting #12895 merged if no one beats me to it.

I have some private patches, but I'm not sure what extent of potential breakage/how invasive changes are going to be accepted, so I've been somewhat hesitant to actually do anything with this.

Looks nice and straightforward. Should be easy for maintainers to handle!

How does this relate to grsec RBAC? Are the capabilities mapped in systemd?

@spacekitteh grsec RBAC might impose stricter controls but is otherwise orthogonal. If we had a declarative RBAC policy interface, perhaps this information could be re-used there to achieve consistency. With policy generated from learning logs, it gets trickier. Most of this stuff is mainly going to benefit non-RBAC users, in any case, I think. For now I'm just doing the stupidest thing that can work ...

It might be worth thinking about how to make an interface which works with both grsec RBAC and SELinux, eventually.

(triage) has there been progress on this front?

Close?

I have cleaned up a few services but progress is slow. We should however, not close IMHO.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fdietze picture fdietze  路  144Comments

Infinisil picture Infinisil  路  146Comments

worldofpeace picture worldofpeace  路  103Comments

globin picture globin  路  65Comments

tfc picture tfc  路  68Comments