Skip to content
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

The service interface should abide by the principle of least privilege #14645

Closed
joachifm opened this issue Apr 13, 2016 · 20 comments
Closed

The service interface should abide by the principle of least privilege #14645

joachifm opened this issue Apr 13, 2016 · 20 comments

Comments

@joachifm
Copy link
Contributor

joachifm commented Apr 13, 2016

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.

@joachifm
Copy link
Contributor Author

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

@aneeshusa
Copy link
Contributor

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?)

@joachifm
Copy link
Contributor Author

@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.

@joachifm joachifm self-assigned this Apr 15, 2016
@garbas
Copy link
Member

garbas commented May 12, 2016

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?

@joachifm
Copy link
Contributor Author

@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.

@garbas
Copy link
Member

garbas commented May 13, 2016

@joachim +1

@domenkozar
Copy link
Member

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?

@spacekitteh
Copy link
Contributor

Has any work been done on this?

@globin
Copy link
Member

globin commented Aug 14, 2016

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

@joachifm
Copy link
Contributor Author

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.

@joachifm
Copy link
Contributor Author

Some work in progress stuff here: https://github.com/joachifm/nixpkgs/tree/capable-services

@spacekitteh
Copy link
Contributor

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

@spacekitteh
Copy link
Contributor

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

@joachifm
Copy link
Contributor Author

@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 ...

@spacekitteh
Copy link
Contributor

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

@Profpatsch
Copy link
Member

(triage) has there been progress on this front?

@tomberek
Copy link
Contributor

Close?

@peterhoeg
Copy link
Member

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

aszlig added a commit to aszlig/nixpkgs that referenced this issue Mar 15, 2019
My implementation was relying on PrivateDevices, PrivateTmp,
PrivateUsers and others to be false by default if chroot-only mode is
used.

However there is an ongoing effort[1] to change these defaults, which
then will actually increase the attack surface in chroot-only mode,
because it is expected that there is no /dev, /sys or /proc.

If for example PrivateDevices is enabled by default, there suddenly will
be a mounted /dev in the chroot and we wouldn't detect it.

Fortunately, our tests cover that, but I'm preparing for this anyway so
that we have a smoother transition without the need to fix our
implementation again.

Thanks to @infinisil for the heads-up.

[1]: NixOS#14645

Signed-off-by: aszlig <aszlig@nix.build>
@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/half-a-presentation-i-had-in-my-company-about-nixos/16467/36

@Profpatsch
Copy link
Member

Closing for now, there are no real action items. If somebody wants to shepherd this into something more focused, feel free to reopen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

10 participants