forked from alexoundos/articles
initial
commit
8e24d268fd
|
@ -0,0 +1,79 @@
|
||||||
|
# hardening of systemd services in NixOS
|
||||||
|
## introduction, threat landscape and risks
|
||||||
|
Protection against outside threats: potential vulnerabilities and unauthorized access.
|
||||||
|
Generally it's better to implement as many layers of security as possible. Although, there is no way to make server 100% bullet proof - it's a huge endless topic, we can implement some feasible essential things that gives us a layer or protection.
|
||||||
|
### security principles and strategy
|
||||||
|
1. define desired security requirements
|
||||||
|
2. apply systemd hardening options, suggested by `systemd-analyze` (until they harm service functionality)
|
||||||
|
3. vulnerability scanning, penetration testing, and security audits
|
||||||
|
4. monitor and respond
|
||||||
|
|
||||||
|
Take advantage of monitoring tools.
|
||||||
|
Have a rescue plan to mitigate the impact of incidents. This might include restoring system from backups, keys and passwords reset.
|
||||||
|
Business continuity plan.
|
||||||
|
|
||||||
|
While there are many areas of server protection, like keeping the running software up to date and respond to CVEs ([deploying software with patches is easy in NixOS](https://nixos.wiki/wiki/Overlays#Adding_patches) in case it hasn't been already patched), we will focus on `systemd` means (and a bit more, where `systemd` is not sophisticated enough).
|
||||||
|
|
||||||
|
In order for the actions (measures?) taken not to be ad-hoc, but rather systematic.
|
||||||
|
|
||||||
|
## overview of systemd integration within NixOS
|
||||||
|
- configuring systemd service units in NixOS step by step (edit, rebuild (maybe in VM), `systemd status`, `systemd restart`, `systemd cat`, `htop` tree)
|
||||||
|
## resources limits strategy
|
||||||
|
## existing practices and solutions within NixOS
|
||||||
|
- https://nixos.wiki/wiki/Systemd_Hardening
|
||||||
|
- https://github.com/fort-nix/nix-bitcoin#security
|
||||||
|
- some explanation that there is no universal way: https://github.com/NixOS/nixpkgs/pull/87661#issuecomment-698945283
|
||||||
|
|
||||||
|
## list of systemd options and their implications
|
||||||
|
|
||||||
|
|
||||||
|
## cgroups
|
||||||
|
|
||||||
|
`cgroup` - 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
|
||||||
|
```
|
||||||
|
|
||||||
|
## hardening in available services provided by NixOS upstream
|
||||||
|
|
||||||
|
NixOS already provides more or less isolation for many services, which are available as `services.NAME_OF_SERVICE` options.
|
||||||
|
|
||||||
|
## hardening in your own systemd services
|
||||||
|
|
||||||
|
## blocking outgoing internet connections
|
||||||
|
|
||||||
|
The idea is to keep responding to incoming requests to some 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:
|
||||||
|
```nix
|
||||||
|
networking.firewall = {
|
||||||
|
extraCommands = ''
|
||||||
|
iptables -t filter -I OUTPUT 1 -m owner --uid-owner ${user} -m state --state NEW -j REJECT
|
||||||
|
'';
|
||||||
|
extraStopCommands = ''
|
||||||
|
iptables -t filter -D OUTPUT 1 -m owner --uid-owner ${user} -m state --state NEW
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### testing
|
||||||
|
|
||||||
|
[example-systemd-service.nix](example-systemd-service.nix) features a way to run a shell inside a systemd service in order to test our isolation in practice. You can just add path to the file to the `imports` list in `configuration.nix` and execute `nixos-rebuild switch` or `nixos-rebuild test` _(if you don't want new configuration to be permanent; however, it creates `./result` symbolic link in current directory)_.
|
||||||
|
|
||||||
|
## unsolved problems
|
||||||
|
|
||||||
|
`confinement.enable` is not compatible with systemd's `ProtectSystem`.
|
||||||
|
|
||||||
|
## related resources
|
||||||
|
|
||||||
|
- [discourse thread about systemd services hardening](https://discourse.nixos.org/t/hardening-systemd-services/17147)
|
||||||
|
- [systemd.resource-control man page](https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html)
|
||||||
|
- [systemd.exec - execution environment configuration](https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html)
|
||||||
|
- [NixOS systemd hardening wiki page](https://nixos.wiki/wiki/Systemd_Hardening)
|
||||||
|
- https://nixos.wiki/wiki/Security
|
|
@ -0,0 +1,62 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
service-name = "example-service";
|
||||||
|
user = "example-service-user";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
users.users = {
|
||||||
|
${user} = {
|
||||||
|
group = user;
|
||||||
|
isNormalUser = true;
|
||||||
|
createHome = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
users.groups.${user} = { };
|
||||||
|
|
||||||
|
systemd.services.${service-name} = {
|
||||||
|
serviceConfig = {
|
||||||
|
User = user;
|
||||||
|
Group = user;
|
||||||
|
|
||||||
|
# Runtime directory and mode
|
||||||
|
RuntimeDirectory = service-name;
|
||||||
|
RuntimeDirectoryMode = "0750";
|
||||||
|
# State directory and mode
|
||||||
|
StateDirectory = service-name;
|
||||||
|
StateDirectoryMode = "0750";
|
||||||
|
# Cache directory and mode
|
||||||
|
CacheDirectory = service-name;
|
||||||
|
CacheDirectoryMode = "0750";
|
||||||
|
# Logs directory and mode
|
||||||
|
LogsDirectory = service-name;
|
||||||
|
LogsDirectoryMode = "0750";
|
||||||
|
# Configuration directory and mode
|
||||||
|
ConfigurationDirectory = service-name;
|
||||||
|
ConfigurationDirectoryMode = "0755";
|
||||||
|
|
||||||
|
# Sandboxing
|
||||||
|
ProtectSystem = "full";
|
||||||
|
ProtectHome = "read-only";
|
||||||
|
PrivateTmp = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
PrivateMounts = true;
|
||||||
|
|
||||||
|
ExecStart = "${pkgs.tmux}/bin/tmux -S /run/${service-name}/tmux.socket new-session -s my-session -d";
|
||||||
|
ExecStop = "${pkgs.tmux}/bin/tmux -S /run/${service-name}/tmux.socket kill-session -t my-session";
|
||||||
|
Type = "forking";
|
||||||
|
};
|
||||||
|
|
||||||
|
#confinement.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking = {
|
||||||
|
firewall = {
|
||||||
|
extraCommands = ''
|
||||||
|
iptables -t filter -I OUTPUT 1 -m owner --uid-owner ${user} -m state --state NEW -j REJECT
|
||||||
|
'';
|
||||||
|
extraStopCommands = ''
|
||||||
|
iptables -t filter -D OUTPUT 1 -m owner --uid-owner ${user} -m state --state NEW
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue