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