Commit Graph

3 Commits

Author SHA1 Message Date
abb4dd9fc0 feat(templates): migrate six cred emitters to native shape
Phase 2/3 of DEBT-039. Switches FTP, POP3, IMAP, SMTP, Redis, and
LDAP from the legacy `username=` + `password=` SD-block shape to the
universal credential shape (`principal=` + `secret_printable=` +
`secret_b64=`) the new Credential storage model expects.

Pattern is uniform across all six services:

    _log("auth_attempt", username=u, principal=u, **encode_secret(pw))

Each service emits the canonical SD keys. The ingester's native-shape
branch (introduced in 2f47f67) now writes their cred attempts
directly without going through the legacy adapter. Once Phase 3
removes the adapter the contract becomes single-shape.

Per-service notes:
- POP3 / IMAP — `status="success"|"failed"` renamed to
  `outcome="success"|"failure"` to match Credential.outcome's
  vocabulary; the ingester reads outcome directly.
- SMTP — AUTH path migrated; in addition the existing mail_from
  event now exposes a parsed `domain=` field alongside the original
  `value=` so future "what domains do attackers spoof from" analytics
  have an indexed field. Not stored in Credential — regular Log row.
- Redis — was silently dropped by the legacy adapter (no `username`
  field). Native branch handles `principal=None` correctly. BONUS
  FIX: the Redis 6+ ACL syntax `AUTH <user> <pw>` now captures the
  ACL username as principal (was previously discarded).
- LDAP — was silently dropped by the legacy adapter (no `password`
  recognition for the `bind` event). Now lands as
  `principal=<dn>`. BONUS FIX.

Tests (tests/services/test_cred_emitters.py, 9 cases):
- per-service native-shape ingest path produces correct Credential
  rows; outcome maps for POP3/IMAP; principal=None for legacy Redis
  AUTH; principal=dn for LDAP.
- mail_from event does NOT trigger a credential write (it's a
  Log-only observation, not auth).
- 0xff/NUL/ANSI bytes in passwords survive losslessly through
  secret_b64 even when secret_printable is sanitized.

Phase 3 deletes the legacy adapter once all migrations land — the
adapter has no live emitters to handle anymore.
2026-04-25 05:43:51 -04:00
3fb84ac5d0 feat(templates): per-instance stealth via instance_seed in service servers
Every service template now pulls version strings, cluster/node UUIDs, auth
salts, greeting banners, and uptime from the seeded per-instance RNG instead
of hard-coded defaults. Scanners sweeping the fleet now see legitimately
diverging fingerprints per decky while each decky's own responses stay
internally consistent across restarts.

Covers elasticsearch, ftp, http, https, ldap, mongodb, mqtt, mssql, mysql,
postgres, redis, and smtp templates.
2026-04-22 09:24:16 -04:00
6708f26e6b fix(packaging): move templates/ into decnet/ package so they ship with pip install
The docker build contexts and syslog_bridge.py lived at repo root, which
meant setuptools (include = ["decnet*"]) never shipped them. Agents
installed via `pip install $RELEASE_DIR` got site-packages/decnet/** but no
templates/, so every deploy blew up in deployer._sync_logging_helper with
FileNotFoundError on templates/syslog_bridge.py.

Move templates/ -> decnet/templates/ and declare it as setuptools
package-data. Path resolutions in services/*.py and engine/deployer.py drop
one .parent since templates now lives beside the code. Test fixtures,
bandit exclude path, and coverage omit glob updated to match.
2026-04-19 19:30:04 -04:00