refactor: strip DECNET tokens from container-visible surface

Rename the container-side logging module decnet_logging → syslog_bridge
(canonical at templates/syslog_bridge.py, synced into each template by
the deployer). Drop the stale per-template copies; setuptools find was
picking them up anyway. Swap useradd/USER/chown "decnet" for "logrelay"
so no obvious token appears in the rendered container image.

Apply the same cloaking pattern to the telnet template that SSH got:
syslog pipe moves to /run/systemd/journal/syslog-relay and the relay
is cat'd via exec -a "systemd-journal-fwd". rsyslog.d conf rename
99-decnet.conf → 50-journal-forward.conf. SSH capture script:
/var/decnet/captured → /var/lib/systemd/coredump (real systemd path),
logger tag decnet-capture → systemd-journal. Compose volume updated
to match the new in-container quarantine path.

SD element ID shifts decnet@55555 → relay@55555; synced across
collector, parser, sniffer, prober, formatter, tests, and docs so the
host-side pipeline still matches what containers emit.
This commit is contained in:
2026-04-17 22:57:53 -04:00
parent 69510fb880
commit 8dd4c78b33
114 changed files with 220 additions and 2712 deletions

View File

@@ -18,8 +18,8 @@ _FUZZ_SETTINGS = dict(
)
def make_fake_decnet_logging() -> ModuleType:
mod = ModuleType("decnet_logging")
def make_fake_syslog_bridge() -> ModuleType:
mod = ModuleType("syslog_bridge")
mod.syslog_line = MagicMock(return_value="")
mod.write_syslog_file = MagicMock()
mod.forward_syslog = MagicMock()

View File

@@ -17,8 +17,8 @@ import pytest
# ── Helpers ───────────────────────────────────────────────────────────────────
def _make_fake_decnet_logging() -> ModuleType:
mod = ModuleType("decnet_logging")
def _make_fake_syslog_bridge() -> ModuleType:
mod = ModuleType("syslog_bridge")
mod.syslog_line = MagicMock(return_value="")
mod.write_syslog_file = MagicMock()
mod.forward_syslog = MagicMock()
@@ -28,17 +28,17 @@ def _make_fake_decnet_logging() -> ModuleType:
def _load_imap():
"""Import imap server module, injecting a stub decnet_logging."""
"""Import imap server module, injecting a stub syslog_bridge."""
env = {
"NODE_NAME": "testhost",
"IMAP_USERS": "admin:admin123,root:toor",
"IMAP_BANNER": "* OK [testhost] Dovecot ready.",
}
for key in list(sys.modules):
if key in ("imap_server", "decnet_logging"):
if key in ("imap_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = _make_fake_decnet_logging()
sys.modules["syslog_bridge"] = _make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location(
"imap_server", "templates/imap/server.py"

View File

@@ -14,16 +14,16 @@ import pytest
from hypothesis import given, settings
from hypothesis import strategies as st
from .conftest import _FUZZ_SETTINGS, make_fake_decnet_logging, run_with_timeout
from .conftest import _FUZZ_SETTINGS, make_fake_syslog_bridge, run_with_timeout
# ── Helpers ───────────────────────────────────────────────────────────────────
def _load_mongodb():
for key in list(sys.modules):
if key in ("mongodb_server", "decnet_logging"):
if key in ("mongodb_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = make_fake_decnet_logging()
sys.modules["syslog_bridge"] = make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location("mongodb_server", "templates/mongodb/server.py")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)

View File

@@ -16,8 +16,8 @@ import pytest
# ── Helpers ───────────────────────────────────────────────────────────────────
def _make_fake_decnet_logging() -> ModuleType:
mod = ModuleType("decnet_logging")
def _make_fake_syslog_bridge() -> ModuleType:
mod = ModuleType("syslog_bridge")
mod.syslog_line = MagicMock(return_value="")
mod.write_syslog_file = MagicMock()
mod.forward_syslog = MagicMock()
@@ -34,10 +34,10 @@ def _load_mqtt(accept_all: bool = True, custom_topics: str = "", persona: str =
"MQTT_CUSTOM_TOPICS": custom_topics,
}
for key in list(sys.modules):
if key in ("mqtt_server", "decnet_logging"):
if key in ("mqtt_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = _make_fake_decnet_logging()
sys.modules["syslog_bridge"] = _make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location("mqtt_server", "templates/mqtt/server.py")
mod = importlib.util.module_from_spec(spec)

View File

@@ -15,16 +15,16 @@ import pytest
from hypothesis import given, settings
from hypothesis import strategies as st
from .conftest import _FUZZ_SETTINGS, make_fake_decnet_logging, run_with_timeout
from .conftest import _FUZZ_SETTINGS, make_fake_syslog_bridge, run_with_timeout
# ── Helpers ───────────────────────────────────────────────────────────────────
def _load_mqtt():
for key in list(sys.modules):
if key in ("mqtt_server", "decnet_logging"):
if key in ("mqtt_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = make_fake_decnet_logging()
sys.modules["syslog_bridge"] = make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location("mqtt_server", "templates/mqtt/server.py")
mod = importlib.util.module_from_spec(spec)
with patch.dict("os.environ", {"MQTT_ACCEPT_ALL": "1", "MQTT_PERSONA": "water_plant"}, clear=False):

View File

@@ -14,16 +14,16 @@ import pytest
from hypothesis import given, settings
from hypothesis import strategies as st
from .conftest import _FUZZ_SETTINGS, make_fake_decnet_logging, run_with_timeout
from .conftest import _FUZZ_SETTINGS, make_fake_syslog_bridge, run_with_timeout
# ── Helpers ───────────────────────────────────────────────────────────────────
def _load_mssql():
for key in list(sys.modules):
if key in ("mssql_server", "decnet_logging"):
if key in ("mssql_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = make_fake_decnet_logging()
sys.modules["syslog_bridge"] = make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location("mssql_server", "templates/mssql/server.py")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)

View File

@@ -14,16 +14,16 @@ import pytest
from hypothesis import given, settings
from hypothesis import strategies as st
from .conftest import _FUZZ_SETTINGS, make_fake_decnet_logging, run_with_timeout
from .conftest import _FUZZ_SETTINGS, make_fake_syslog_bridge, run_with_timeout
# ── Helpers ───────────────────────────────────────────────────────────────────
def _load_mysql():
for key in list(sys.modules):
if key in ("mysql_server", "decnet_logging"):
if key in ("mysql_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = make_fake_decnet_logging()
sys.modules["syslog_bridge"] = make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location("mysql_server", "templates/mysql/server.py")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
@@ -89,7 +89,7 @@ def test_login_packet_returns_access_denied(mysql_mod):
def test_login_logs_username():
mod = _load_mysql()
log_mock = sys.modules["decnet_logging"]
log_mock = sys.modules["syslog_bridge"]
proto, _, _ = _make_protocol(mod)
proto.data_received(_login_packet(username="hacker"))
calls_str = str(log_mock.syslog_line.call_args_list)

View File

@@ -17,8 +17,8 @@ import pytest
# ── Helpers ───────────────────────────────────────────────────────────────────
def _make_fake_decnet_logging() -> ModuleType:
mod = ModuleType("decnet_logging")
def _make_fake_syslog_bridge() -> ModuleType:
mod = ModuleType("syslog_bridge")
mod.syslog_line = MagicMock(return_value="")
mod.write_syslog_file = MagicMock()
mod.forward_syslog = MagicMock()
@@ -34,10 +34,10 @@ def _load_pop3():
"IMAP_BANNER": "+OK [testhost] Dovecot ready.",
}
for key in list(sys.modules):
if key in ("pop3_server", "decnet_logging"):
if key in ("pop3_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = _make_fake_decnet_logging()
sys.modules["syslog_bridge"] = _make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location(
"pop3_server", "templates/pop3/server.py"

View File

@@ -14,16 +14,16 @@ import pytest
from hypothesis import given, settings
from hypothesis import strategies as st
from .conftest import _FUZZ_SETTINGS, make_fake_decnet_logging, run_with_timeout
from .conftest import _FUZZ_SETTINGS, make_fake_syslog_bridge, run_with_timeout
# ── Helpers ───────────────────────────────────────────────────────────────────
def _load_postgres():
for key in list(sys.modules):
if key in ("postgres_server", "decnet_logging"):
if key in ("postgres_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = make_fake_decnet_logging()
sys.modules["syslog_bridge"] = make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location("postgres_server", "templates/postgres/server.py")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
@@ -80,7 +80,7 @@ def test_startup_sends_auth_challenge(postgres_mod):
def test_startup_logs_username():
mod = _load_postgres()
log_mock = sys.modules["decnet_logging"]
log_mock = sys.modules["syslog_bridge"]
proto, _, _ = _make_protocol(mod)
proto.data_received(_startup_msg(user="attacker"))
log_mock.syslog_line.assert_called()

View File

@@ -6,8 +6,8 @@ from unittest.mock import MagicMock, patch
import pytest
def _make_fake_decnet_logging() -> ModuleType:
mod = ModuleType("decnet_logging")
def _make_fake_syslog_bridge() -> ModuleType:
mod = ModuleType("syslog_bridge")
mod.syslog_line = MagicMock(return_value="")
mod.write_syslog_file = MagicMock()
mod.forward_syslog = MagicMock()
@@ -19,10 +19,10 @@ def _make_fake_decnet_logging() -> ModuleType:
def _load_redis():
env = {"NODE_NAME": "testredis"}
for key in list(sys.modules):
if key in ("redis_server", "decnet_logging"):
if key in ("redis_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = _make_fake_decnet_logging()
sys.modules["syslog_bridge"] = _make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location("redis_server", "templates/redis/server.py")
mod = importlib.util.module_from_spec(spec)

View File

@@ -19,9 +19,9 @@ import pytest
# ── Helpers ───────────────────────────────────────────────────────────────────
def _make_fake_decnet_logging() -> ModuleType:
"""Return a stub decnet_logging module that does nothing."""
mod = ModuleType("decnet_logging")
def _make_fake_syslog_bridge() -> ModuleType:
"""Return a stub syslog_bridge module that does nothing."""
mod = ModuleType("syslog_bridge")
mod.syslog_line = MagicMock(return_value="")
mod.write_syslog_file = MagicMock()
mod.forward_syslog = MagicMock()
@@ -33,15 +33,15 @@ def _make_fake_decnet_logging() -> ModuleType:
def _load_smtp(open_relay: bool):
"""Import smtp server module with desired OPEN_RELAY value.
Injects a stub decnet_logging into sys.modules so the template can import
Injects a stub syslog_bridge into sys.modules so the template can import
it without needing the real file on sys.path.
"""
env = {"SMTP_OPEN_RELAY": "1" if open_relay else "0", "NODE_NAME": "testhost"}
for key in list(sys.modules):
if key in ("smtp_server", "decnet_logging"):
if key in ("smtp_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = _make_fake_decnet_logging()
sys.modules["syslog_bridge"] = _make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location("smtp_server", "templates/smtp/server.py")
mod = importlib.util.module_from_spec(spec)

View File

@@ -15,8 +15,8 @@ import pytest
# ── Helpers ───────────────────────────────────────────────────────────────────
def _make_fake_decnet_logging() -> ModuleType:
mod = ModuleType("decnet_logging")
def _make_fake_syslog_bridge() -> ModuleType:
mod = ModuleType("syslog_bridge")
def syslog_line(*args, **kwargs):
print("LOG:", args, kwargs)
return ""
@@ -34,10 +34,10 @@ def _load_snmp(archetype: str = "default"):
"SNMP_ARCHETYPE": archetype,
}
for key in list(sys.modules):
if key in ("snmp_server", "decnet_logging"):
if key in ("snmp_server", "syslog_bridge"):
del sys.modules[key]
sys.modules["decnet_logging"] = _make_fake_decnet_logging()
sys.modules["syslog_bridge"] = _make_fake_syslog_bridge()
spec = importlib.util.spec_from_file_location("snmp_server", "templates/snmp/server.py")
mod = importlib.util.module_from_spec(spec)