Remove Suricata/ELK; add SSH key auth and disable password login

Adds authorised keys for FredOS-Gaming and phone. Disables SSH password
authentication on FredOS-Mediaserver — key auth only going forward.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ediblerope 2026-04-06 21:48:08 +01:00
parent ddb208b95d
commit 39450ca786
5 changed files with 8 additions and 173 deletions

View file

@ -30,8 +30,6 @@
./services/bazarr.nix
./services/cloudflare-ddns.nix
./services/fail2ban.nix
./services/suricata.nix
./services/elk.nix
];
### Make build time quicker

View file

@ -28,7 +28,10 @@
networking.firewall.allowedTCPPorts = [ 22 ];
services.openssh = {
enable = true;
settings.PermitRootLogin = "no";
settings = {
PermitRootLogin = "no";
PasswordAuthentication = false;
};
};
};
}

View file

@ -1,104 +0,0 @@
{ config, lib, pkgs, ... }:
let
# Pin all three to the same version — mismatches between ES/Kibana/Filebeat cause errors
# Check https://www.docker.elastic.co for latest 8.x tag
elasticVersion = "8.17.0";
filebeatConfig = pkgs.writeText "filebeat.yml" ''
filebeat.modules:
- module: suricata
eve:
enabled: true
var.paths: ["/var/log/suricata/eve.json"]
# Auto-install Kibana dashboards on first run
setup.dashboards.enabled: true
setup.kibana:
host: "kibana:5601"
output.elasticsearch:
hosts: ["elasticsearch:9200"]
# Reduce logging noise
logging.level: warning
'';
in
{
config = lib.mkIf (config.networking.hostName == "FredOS-Mediaserver") {
virtualisation.oci-containers.containers = {
elasticsearch = {
image = "docker.elastic.co/elasticsearch/elasticsearch:${elasticVersion}";
environment = {
# Single-node cluster — no replica shards needed
"discovery.type" = "single-node";
# Security disabled — ES is not exposed externally
"xpack.security.enabled" = "false";
# Disable enrollment flow (ES 8.x auto-enables this when security is on)
"xpack.security.enrollment.enabled" = "false";
# Keep heap at 1g; ES default is 50% of RAM which is excessive here
"ES_JAVA_OPTS" = "-Xms1g -Xmx1g";
};
volumes = [ "elasticsearch-data:/usr/share/elasticsearch/data" ];
extraOptions = [ "--network=elk" ];
};
kibana = {
image = "docker.elastic.co/kibana/kibana:${elasticVersion}";
environment = {
"ELASTICSEARCH_HOSTS" = "http://elasticsearch:9200";
# Tell Kibana security is off — suppresses the enrollment token screen
"xpack.security.enabled" = "false";
# Cap Node.js heap — default is uncapped
"NODE_OPTIONS" = "--max-old-space-size=512";
};
ports = [ "5601:5601" ];
extraOptions = [ "--network=elk" ];
dependsOn = [ "elasticsearch" ];
};
filebeat = {
image = "docker.elastic.co/beats/filebeat:${elasticVersion}";
extraOptions = [
"--network=elk"
# root so it can read /var/log/suricata owned by the suricata user
"--user=root"
# Filebeat refuses to start if config file is group/world writable
"--security-opt=no-new-privileges:true"
];
volumes = [
"/var/log/suricata:/var/log/suricata:ro"
"${filebeatConfig}:/usr/share/filebeat/filebeat.yml:ro"
];
dependsOn = [ "elasticsearch" "kibana" ];
};
};
# Create the elk bridge network before any container starts
systemd.services.init-elk-docker-network = {
description = "Create elk Docker network";
after = [ "docker.service" ];
requires = [ "docker.service" ];
before = [
"docker-elasticsearch.service"
"docker-kibana.service"
"docker-filebeat.service"
];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
${pkgs.docker}/bin/docker network inspect elk >/dev/null 2>&1 \
|| ${pkgs.docker}/bin/docker network create elk
'';
};
# Kibana accessible on the LAN
networking.firewall.allowedTCPPorts = [ 5601 ];
};
}

View file

@ -1,66 +0,0 @@
{ config, lib, pkgs, ... }:
{
config = lib.mkIf (config.networking.hostName == "FredOS-Mediaserver") {
services.suricata = {
enable = true;
# DNP3 and Modbus are industrial SCADA protocols disabled in this build.
# Use regex patterns to suppress all rules for both protocols so the
# config test does not fail with parse errors.
disabledRules = [
"re:modbus"
"re:dnp3"
];
settings = {
vars.address-groups = {
# Your local networks — Suricata won't alert on traffic within these
HOME_NET = "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,127.0.0.0/8]";
EXTERNAL_NET = "!$HOME_NET";
};
# IDS mode: passive monitoring (read-only, no blocking)
# To enable IPS later, swap this for nfqueue mode
af-packet = [
{ interface = "eno1"; }
];
# Structured JSON log — useful for dashboards and log aggregation
outputs = [
{
eve-log = {
enabled = true;
filetype = "regular";
filename = "eve.json";
community-id = true;
types = [
{ alert = { tagged-packets = "yes"; }; }
{ anomaly = {}; }
{ drop = {}; }
];
};
}
# Human-readable alert log for quick inspection
{
fast = {
enabled = true;
filename = "fast.log";
append = "yes";
};
}
];
# Enable unix socket so suricatasc can query running state
unix-command.enabled = true;
classification-file = "${pkgs.suricata}/etc/suricata/classification.config";
reference-config-file = "${pkgs.suricata}/etc/suricata/reference.config";
};
};
# Make suricata CLI tools available (suricatasc, suricata-update)
environment.systemPackages = [ pkgs.suricata ];
};
}

View file

@ -10,5 +10,9 @@
packages = with pkgs; [
bazaar
];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEOgQQ9aO8Ri5oL2c3QntSk05PkryfLNsJQqIcjfKFqL fredrik@nordhammer.it" # FredOS-Gaming
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILTLAr9hSWW5PerZJmDZwmB5sa0DBTe2mM4IwTtcCfX3 fredrik@nordhammer.it" # phone
];
};
}