mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-07-06 17:13:24 -05:00
nixos/reaction: test core plugins
Co-authored-by: ppom <38916722+ppom0@users.noreply.github.com> Signed-off-by: phanirithvij <phanirithvij2000@gmail.com>
This commit is contained in:
parent
94cf274c92
commit
4d4b662ab1
4 changed files with 200 additions and 6 deletions
|
|
@ -12,12 +12,6 @@
|
|||
stopForFirewall = false;
|
||||
# example.jsonnet or example.yml can be copied and modified from ${pkgs.reaction}/share/examples
|
||||
settingsFiles = [ "${pkgs.reaction}/share/examples/example.jsonnet" ];
|
||||
settings = {
|
||||
# In the qemu vm `run0 ls` as root prints nothing, so we can't use it
|
||||
# see https://reaction.ppom.me/reference.html#systemd
|
||||
plugins.ipset.systemd = false;
|
||||
plugins.virtual.systemd = false;
|
||||
};
|
||||
runAsRoot = false;
|
||||
};
|
||||
services.openssh.enable = true;
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
lib.recurseIntoAttrs {
|
||||
basic = runTest ./basic.nix;
|
||||
firewall = runTest ./firewall.nix;
|
||||
plugins = runTest ./plugins.nix;
|
||||
}
|
||||
|
|
|
|||
125
nixos/tests/reaction/plugins.nix
Normal file
125
nixos/tests/reaction/plugins.nix
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
name = "reaction-core-plugins";
|
||||
|
||||
nodes.server = args: {
|
||||
services.reaction = {
|
||||
enable = true;
|
||||
stopForFirewall = false;
|
||||
runAsRoot = false;
|
||||
settings = import ./settings.nix args;
|
||||
/*
|
||||
# NOTE: When runAsRoot is true, disable run0
|
||||
settings = {
|
||||
# In the qemu vm `run0 ls` as root prints nothing, so we can't use it
|
||||
# see https://reaction.ppom.me/reference.html#systemd
|
||||
plugins.ipset.systemd = false;
|
||||
plugins.virtual.systemd = false;
|
||||
};
|
||||
*/
|
||||
};
|
||||
/*
|
||||
NOTE:
|
||||
- if reaction is run as non-root, the plugins need these capabilities, remove these if runAsRoot is true
|
||||
- CAP_DAC_READ_SEARCH is for journalctl for accessing ssh logs
|
||||
- useful tools: capable (from package bcc), captree, getpcaps (from libpcap)
|
||||
*/
|
||||
systemd.services.reaction.serviceConfig = {
|
||||
CapabilityBoundingSet = [
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW"
|
||||
"CAP_DAC_READ_SEARCH"
|
||||
];
|
||||
AmbientCapabilities = [
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW"
|
||||
"CAP_DAC_READ_SEARCH"
|
||||
];
|
||||
};
|
||||
services.openssh.enable = true;
|
||||
|
||||
users.users.nixos.isNormalUser = true; # neeeded to establish a ssh connection, by default root login is succeeding without any password
|
||||
};
|
||||
|
||||
nodes.client = _: {
|
||||
environment.systemPackages = [
|
||||
pkgs.sshpass
|
||||
pkgs.libressl.nc
|
||||
];
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ nodes, ... }: # py
|
||||
''
|
||||
start_all()
|
||||
|
||||
# Wait for everything to be ready.
|
||||
server.wait_for_unit("multi-user.target")
|
||||
server.wait_for_unit("reaction")
|
||||
server.wait_for_unit("sshd")
|
||||
|
||||
client_addr = "${(lib.head nodes.client.networking.interfaces.eth1.ipv4.addresses).address}"
|
||||
server_addr = "${(lib.head nodes.server.networking.interfaces.eth1.ipv4.addresses).address}"
|
||||
|
||||
# Verify there is not ban and the port is reachable from the client.
|
||||
server.succeed(f"reaction show | grep -q {client_addr} || test $? -eq 1")
|
||||
client.succeed(f"nc -w3 -z {server_addr} 22")
|
||||
|
||||
# Cause authentication failure log entries.
|
||||
for _ in range(2):
|
||||
client.fail(f"""
|
||||
sshpass -p 'wrongpassword' \
|
||||
ssh -o StrictHostKeyChecking=no \
|
||||
-o User=nixos \
|
||||
-o ServerAliveInterval=1 \
|
||||
-o ServerAliveCountMax=2 \
|
||||
{server_addr}
|
||||
""")
|
||||
|
||||
# Verify there is a ban and the port is unreachable from the client.
|
||||
server.sleep(2)
|
||||
output = server.succeed("reaction show")
|
||||
print(output)
|
||||
assert client_addr in output, f"client did not get banned, {client_addr}"
|
||||
|
||||
client.fail(f"nc -w3 -z {server_addr} 22")
|
||||
|
||||
# Check that unbanning works
|
||||
output = server.succeed("reaction flush")
|
||||
print(output)
|
||||
|
||||
client.succeed(f"nc -w3 -z {server_addr} 22")
|
||||
'';
|
||||
|
||||
# Debug interactively with:
|
||||
# - nix run .#nixosTests.reaction.driverInteractive -L
|
||||
# - run_tests()
|
||||
# ssh -o User=root vsock%3 (can also do vsock/3, but % works with scp etc.)
|
||||
# ssh -o User=root vsock%4
|
||||
interactive.sshBackdoor.enable = true;
|
||||
|
||||
interactive.nodes.server =
|
||||
{ config, ... }:
|
||||
{
|
||||
# not needed, only for manual interactive debugging
|
||||
virtualisation.memorySize = 4096;
|
||||
virtualisation.graphics = false;
|
||||
environment.systemPackages = with pkgs; [
|
||||
btop
|
||||
sysz
|
||||
sshpass
|
||||
libressl.nc
|
||||
];
|
||||
};
|
||||
|
||||
meta.maintainers =
|
||||
with lib.maintainers;
|
||||
[
|
||||
ppom
|
||||
]
|
||||
++ lib.teams.ngi.members;
|
||||
}
|
||||
74
nixos/tests/reaction/settings.nix
Normal file
74
nixos/tests/reaction/settings.nix
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
{ config, ... }:
|
||||
let
|
||||
banFor = name: duration: {
|
||||
ban = {
|
||||
type = "ipset";
|
||||
options = {
|
||||
set = "reaction-${name}";
|
||||
action = "add";
|
||||
};
|
||||
};
|
||||
unban = {
|
||||
after = duration;
|
||||
type = "ipset";
|
||||
options = {
|
||||
set = "reaction-${name}";
|
||||
action = "del";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
journalctl = "${config.systemd.package}/bin/journalctl";
|
||||
in
|
||||
{
|
||||
patterns = {
|
||||
ip = {
|
||||
type = "ip";
|
||||
ipv6mask = 64;
|
||||
ignore = [
|
||||
"127.0.0.1"
|
||||
"::1"
|
||||
];
|
||||
ignorecidr = [
|
||||
"10.1.1.0/24"
|
||||
"2a01:e0a:b3a:1dd0::/64"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
streams = {
|
||||
ssh = {
|
||||
cmd = [
|
||||
journalctl
|
||||
"-fn0"
|
||||
"-o"
|
||||
"cat"
|
||||
"-u"
|
||||
"sshd.service"
|
||||
];
|
||||
filters = {
|
||||
failedlogin = {
|
||||
regex = [
|
||||
"authentication failure;.*rhost=<ip>(?: |$)"
|
||||
"Failed password for .* from <ip> port"
|
||||
"Invalid user .* from <ip> "
|
||||
"Connection (?:reset|closed) by invalid user .* <ip> port"
|
||||
];
|
||||
retry = 2;
|
||||
retryperiod = "6h";
|
||||
actions = banFor "ssh" "48h";
|
||||
};
|
||||
connectionreset = {
|
||||
regex = [
|
||||
"Connection (?:reset|closed) by(?: authenticating user .*)? <ip> port"
|
||||
"Received disconnect from <ip> port .*[preauth]"
|
||||
"Timeout before authentication for connection from <ip> to"
|
||||
];
|
||||
retry = 2;
|
||||
retryperiod = "6h";
|
||||
actions = banFor "sshreset" "48h";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue