more or less real structure

nixos-config-re
Alexander Tomokhov 2023-06-23 05:48:13 +04:00
parent 062f512df2
commit 6e6e164c11
1 changed files with 28 additions and 25 deletions

View File

@ -1,4 +1,4 @@
# systemd services in NixOS and hardening of them
# systemd services in NixOS and tips for hardening of them
## introduction
@ -6,7 +6,7 @@ When it comes to security, we care about limiting access of each entity of a sys
Generally, it's better to implement as many layers of security as possible. Although, there is no way to make a server 100% bullet proof - it's a huge endless topic, this article covers some feasible essential `systemd` tunables that give us a layer of protection.
Systemd is the standard software suite for organizing and running services/daemons in a modern GNU/Linux distribution, including NixOS. Systemd provides means to secure services. And in many ways, the isolation level of a systemd service can be similar to that of containers (by the means of sandboxing, namespaces, cgroups, etc; interestingly, [systemd even allows running](https://www.stevenrombauts.be/2019/01/run-multiple-instances-of-the-same-systemd-unit/) [multiple instances of the same service](https://opensource.com/article/20/12/multiple-service-instances-systemctl)). However, systemd hardening defaults are quite loose (perhaps, not to disturb the operation of newly written services and their administrators in any way).
Systemd is the standard software suite for organizing and running services/daemons in a modern GNU/Linux distribution, including NixOS. Systemd provides means to secure services. And in many ways, the isolation level of a systemd service can be similar to that of containers (by the means of sandboxing, namespaces and cgroups, which Docker also uses; interestingly, [systemd even allows running](https://www.stevenrombauts.be/2019/01/run-multiple-instances-of-the-same-systemd-unit/) [multiple instances of the same service](https://opensource.com/article/20/12/multiple-service-instances-systemctl)). However, systemd hardening defaults are quite loose (perhaps, not to disturb the operation of newly written services and their administrators in any way).
What NixOS does - it generates systemd configuration files in accordance to NixOS configuration given, written in Nix language. To some extent, Nix acts as a macro language and NixOS configuration module system acts as a unified control center, so that you don't bother about location of systemd files, their syntax and common stuff, which NixOS generates for you. Also, NixOS manages runtime switching between systemd configurations, conducting services restarts when required, and whole system rollbacks from GRUB/systemd-boot/extlinux.
@ -45,26 +45,19 @@ Be aware that systemd directives (options) are case sensitive! But NixOS doesn't
Also, keep in mind that mutable operations like `systemd SERVICE enable` are useless, because they would deviate the system from declarative reproducible configuration and NixOS won't let or will stubbornly resist you doing so at the design level. And there is no need, since each permanent setting is in the hands of NixOS.
## hardening
## tips for hardening
NixOS provides many services, available as `services.<name>.*`, which already have more or less hardening implemented by the means of systemd. For example, `services.nginx`, `services.gitea`, `services.jitsi-meet`, `services.redis`. At least, these services run under specific system non-root users without access to spawn a shell.
There is [no universal way](https://github.com/NixOS/nixpkgs/pull/87661#issuecomment-698945283) in configuring systemd services options sandboxing/hardening for all services. Each service requires individual approach.
There are, however, services like `services.dovecot2`, `services.postfix` and `services.nextcloud`, which use their own means to spawn sub-processes under a specific user by a master process. Such master process is run under `root`. For example, nextcloud uses `php:fpm` ([PHP FastCGI Process Manager](https://php-fpm.org/)). Obviously, shell can be spawned by such processes and a lot more, but they do not have network connections outside world and intended specifically for process/workers management and logging. Ideally, we would want them to be run under non-root user regardless, but usually [it's not easy to do](https://github.com/docker-library/php/issues/70#issuecomment-1386729923) and upstream might not expect such usage.
NixOS provides many services, available as `services.<name>.*`, which already have more or less hardening implemented by the means of systemd. For example, `services.nginx`, `services.gitea`, `services.jitsi-meet`, `services.redis`. At least, these services run under specific system non-`root` users without access to spawn a shell.
There are, however, services like `services.dovecot2`, `services.postfix` and `services.nextcloud`, which use their own means to spawn sub-processes under a specific user by a master process. Such master process is run under `root`. For example, nextcloud uses `php:fpm` ([PHP FastCGI Process Manager](https://php-fpm.org/)). Obviously, shell can be spawned by such processes and a lot more, but they do not have network connections outside world and intended specifically for process/workers management and logging. Ideally, we would want them to be run under non-`root` user regardless, but usually [it's not easy](https://github.com/docker-library/php/issues/70#issuecomment-1386729923) [to do](https://github.com/NixOS/nixpkgs/pull/93305/files#r456125288) and upstream might not expect such usage.
_Btw, if your systemd service code gets large and you want to wrap it into something more esthetic, you [can](https://nixos.wiki/wiki/Extend_NixOS) [write your own NixOS service module](https://scvalex.net/posts/58/)._
### cgroups
### some important systemd options and their implications
[`cgroup`](https://en.wikipedia.org/wiki/Cgroups) - control group.
_Docker's isolation implementation is also based on cgroups._
Enabling `netdata` service in NixOS enables `systemd.enableCgroupAccounting`, which in turn [enables these options in `systemd.conf`](https://github.com/NixOS/nixpkgs/blob/c223f49e6d4b4684286b8d2f9b2325930a4f62ff/nixos/modules/system/boot/systemd.nix#L493):
```
DefaultCPUAccounting=yes
DefaultIOAccounting=yes
DefaultBlockIOAccounting=yes
DefaultIPAccounting=yes
```
TODO
### resources control (limits) for a systemd service
@ -101,9 +94,7 @@ systemd.services.netdata.serviceConfig = {
### blocking outgoing internet connections
When it comes to a more sophisticated firewall, unfortunatelly systemd is not capable of such granular control. So, `iptables` configuration will be:
The idea here is to keep responding to incoming requests to some service, but forbid any outgoing connections, initiated by itself.
The idea here is to keep responding to incoming requests for a service, but forbid any outgoing connections, initiated by itself. When it comes to a more sophisticated firewall, unfortunatelly systemd is not capable of such granular control. So, `iptables` configuration will be aimed at a specific user, which runs the service:
```nix
networking.firewall = {
@ -116,10 +107,10 @@ networking.firewall = {
};
```
### list of systemd options and their implications
_By specifying `1`, we're instructing `iptables` to insert the rule at the beginning of the chain (pushing any existing rules down by one position)._
## testing
## testing, monitoring, analyzing
### basic systemd commands for diagnostics
@ -127,6 +118,22 @@ networking.firewall = {
`systemd-analyze`'s words "`SAFE`", "`EXPOSED`" and "`UNSAFE`" do not mean the factual situation, rather whether various systemd hardedning features are in use or not.
To monitor systemd service output in real time, you can use `journalctl -u nginx -f` (by analogy with `tail -f`).
In case you want to see logs only for previous boot, use `-1`, like here `journalctl -b-1 -u nginx`.
### cgroups
[`cgroups`](https://en.wikipedia.org/wiki/Cgroups) (control groups) linux feature powers systemd. And it allows to have unified control over a collection of processes within a single service. `systemd-ctop` shows top control groups by their resource usage (output can be sorted by utilization of CPU, memory, IO load, number of tasks). It can be a good alternative to `top`/`htop`, because on a server we often care about service entities as a whole, rather than numerous processes, which stats are hard to sum up in mind.
Just in case, note that enabling `netdata` service in NixOS enables `systemd.enableCgroupAccounting`, which in turn [enables these options in `systemd.conf`](https://github.com/NixOS/nixpkgs/blob/c223f49e6d4b4684286b8d2f9b2325930a4f62ff/nixos/modules/system/boot/systemd.nix#L493):
```
DefaultCPUAccounting=yes
DefaultIOAccounting=yes
DefaultBlockIOAccounting=yes
DefaultIPAccounting=yes
```
### when trying systemd options alone
You can manually test various systemd options without writing service files with the help of `systemd-run`, for example:
@ -162,10 +169,6 @@ With the help of [`tmux`](https://github.com/tmux/tmux/wiki/Getting-Started) you
# nix-shell -p tmux --run "tmux -S /run/example-service/tmux.socket attach"
```
## existing practices and solutions within NixOS
There is [no universal way](https://github.com/NixOS/nixpkgs/pull/87661#issuecomment-698945283) in configuring systemd services options sandboxing/hardening for all services.
## unsolved problems
`systemd.services.<name>.confinement.enable` NixOS option is not compatible with systemd's `ProtectSystem`.