diff --git a/deploy/decnet-campaign-clusterer.service.j2 b/deploy/decnet-campaign-clusterer.service.j2 new file mode 100644 index 00000000..8bc128d8 --- /dev/null +++ b/deploy/decnet-campaign-clusterer.service.j2 @@ -0,0 +1,52 @@ +[Unit] +Description=DECNET Campaign Clusterer (identities → campaigns / operations) +Documentation=https://git.resacachile.cl/anti/DECNET/wiki/Workers#campaign-clusterer +After=network-online.target decnet-bus.service decnet-clusterer.service +Wants=network-online.target decnet-bus.service decnet-clusterer.service + +[Service] +Type=simple +User={{ user }} +Group={{ group }} +WorkingDirectory={{ install_dir }} +EnvironmentFile=-{{ install_dir }}/.env.local +Environment=DECNET_SYSTEM_LOGS=/var/log/decnet/decnet.campaign-clusterer.log +# Subscribes to identity.>; falls back to a 60s slow-tick poll when +# the bus is idle or unavailable. Reads AttackerIdentity rows, +# projects them into the campaign-level similarity graph +# (phase-handoff / shared-infra / temporal overlap / cohort), runs +# union-find, writes campaigns rows + sets +# attacker_identities.campaign_id, and publishes campaign.formed / +# campaign.identity.assigned / campaign.merged / campaign.unmerged +# plus the cross-family identity.campaign.assigned for identity-side +# subscribers. +# +# Master-only: gated via MASTER_ONLY_COMMANDS in decnet/cli/gating.py. +# Sits one layer above decnet-clusterer (the After=/Wants= ensures the +# identity layer is up first; the campaign clusterer then wakes on +# identity.> events fired by it). +ExecStart={{ venv_dir }}/bin/decnet campaign-clusterer +StandardOutput=append:/var/log/decnet/decnet.campaign-clusterer.log +StandardError=append:/var/log/decnet/decnet.campaign-clusterer.log + +CapabilityBoundingSet= +AmbientCapabilities= + +# Security Hardening +NoNewPrivileges=yes +ProtectSystem=full +ProtectHome=read-only +PrivateTmp=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +RestrictSUIDSGID=yes +LockPersonality=yes +ReadWritePaths={{ install_dir }} /var/log/decnet + +Restart=on-failure +RestartSec=5 +TimeoutStopSec=15 + +[Install] +WantedBy=multi-user.target diff --git a/deploy/decnet-clusterer.service.j2 b/deploy/decnet-clusterer.service.j2 new file mode 100644 index 00000000..22e8d990 --- /dev/null +++ b/deploy/decnet-clusterer.service.j2 @@ -0,0 +1,47 @@ +[Unit] +Description=DECNET Identity Clusterer (per-IP observations → identities) +Documentation=https://git.resacachile.cl/anti/DECNET/wiki/Workers#identity-clusterer +After=network-online.target decnet-bus.service +Wants=network-online.target decnet-bus.service + +[Service] +Type=simple +User={{ user }} +Group={{ group }} +WorkingDirectory={{ install_dir }} +EnvironmentFile=-{{ install_dir }}/.env.local +Environment=DECNET_SYSTEM_LOGS=/var/log/decnet/decnet.clusterer.log +# Subscribes to attacker.observed and attacker.scored; falls back to a +# 60s slow-tick poll when the bus is idle or unavailable. Reads +# Attacker rows, projects per-IP observations into the similarity +# graph (JA3 / HASSH / payload-hash / C2-endpoint), runs union-find, +# writes attacker_identities rows + sets attackers.identity_id, and +# publishes identity.formed / identity.observation.linked / +# identity.merged / identity.unmerged. +# +# Master-only: gated via MASTER_ONLY_COMMANDS in decnet/cli/gating.py. +ExecStart={{ venv_dir }}/bin/decnet clusterer +StandardOutput=append:/var/log/decnet/decnet.clusterer.log +StandardError=append:/var/log/decnet/decnet.clusterer.log + +CapabilityBoundingSet= +AmbientCapabilities= + +# Security Hardening +NoNewPrivileges=yes +ProtectSystem=full +ProtectHome=read-only +PrivateTmp=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +RestrictSUIDSGID=yes +LockPersonality=yes +ReadWritePaths={{ install_dir }} /var/log/decnet + +Restart=on-failure +RestartSec=5 +TimeoutStopSec=15 + +[Install] +WantedBy=multi-user.target diff --git a/deploy/decnet.target b/deploy/decnet.target index 3fbf4f8f..d4fb8e33 100644 --- a/deploy/decnet.target +++ b/deploy/decnet.target @@ -15,6 +15,8 @@ Wants=decnet-bus.service \ decnet-mutator.service \ decnet-reuse-correlator.service \ decnet-enrich.service \ + decnet-clusterer.service \ + decnet-campaign-clusterer.service \ decnet-webhook.service After=decnet-bus.service