From 68bbd2e7e08f1f556f83131b8000224c8ba218b5 Mon Sep 17 00:00:00 2001 From: anti Date: Sat, 18 Apr 2026 06:07:22 -0400 Subject: [PATCH 1/2] Add Environment Variables and Teardown and State wiki pages --- Environment-Variables.md | 190 +++++++++++++++++++++++++++++++++++++++ Teardown-and-State.md | 177 ++++++++++++++++++++++++++++++++++++ 2 files changed, 367 insertions(+) create mode 100644 Environment-Variables.md create mode 100644 Teardown-and-State.md diff --git a/Environment-Variables.md b/Environment-Variables.md new file mode 100644 index 0000000..ab34641 --- /dev/null +++ b/Environment-Variables.md @@ -0,0 +1,190 @@ +# Environment Variables + +DECNET reads configuration from process environment. On import, `decnet/env.py` +loads `.env.local` first (preferred, git-ignored) then `.env` from the project +root. Any variable already present in the shell environment wins over both +files. + +Only the variables listed below are recognised. Anything else is noise. + +- Source of truth: [`decnet/env.py`](https://git.resacachile.cl/anti/DECNET/src/branch/main/decnet/env.py) +- Starter template: [`env.config.example`](https://git.resacachile.cl/anti/DECNET/src/branch/main/env.config.example) + +See also: [DB drivers](Database-Drivers), [Logging](Logging-and-Syslog), +[Systemd](Systemd-Setup), [Tracing](Tracing-and-Profiling). + +## Validation rules + +Two validators live in `decnet/env.py`: + +- `_port(name, default)` — integer in `[1, 65535]`. Applies to + `DECNET_API_PORT`, `DECNET_WEB_PORT`, `DECNET_DB_PORT`. +- `_require_env(name)` — variable must be set, and must not be a known-bad + default. Under pytest (`PYTEST*` env var present) the bad-value check is + skipped so test fixtures can use sentinel values. + +### Known-bad-values block list + +`_require_env` rejects these case-insensitive literals: + +- `admin` +- `secret` +- `password` +- `changeme` +- `fallback-secret-key-change-me` + +### JWT secret length rule + +When `name == "DECNET_JWT_SECRET"`, the value must be at least **32 bytes**. +This matches HS256's minimum key length (RFC 7518 §3.2 — "A key of the same +size as the hash output [...] or larger MUST be used"). The check is relaxed +when `DECNET_DEVELOPER=true`. + +## System logging + +| Name | Type | Default | Required | Consequence | +|------|------|---------|----------|-------------| +| `DECNET_SYSTEM_LOGS` | path | `decnet.system.log` | No | Destination for the RFC 5424 `RotatingFileHandler` installed by `decnet/config.py`. All microservice daemons (api, sniffer, profiler, collector) append here. Skipped under pytest. | + +## Embedded workers + +These are escape hatches — leave them unset in normal deployments. `decnet +deploy` always spawns standalone daemons, and embedding the same worker inside +the API duplicates DB writes and sniffer packets. + +| Name | Type | Default | Required | Consequence | +|------|------|---------|----------|-------------| +| `DECNET_EMBED_PROFILER` | bool (`true`/other) | `false` | No | Embed profiler in API process. Do not combine with `decnet profiler --daemon`. | +| `DECNET_EMBED_SNIFFER` | bool | `false` | No | Embed MACVLAN sniffer in API process. Do not combine with `decnet sniffer --daemon`. | + +## Request profiling (Pyinstrument) + +| Name | Type | Default | Required | Consequence | +|------|------|---------|----------|-------------| +| `DECNET_PROFILE_REQUESTS` | bool | `false` | No | Mount Pyinstrument ASGI middleware on the FastAPI app. Writes per-request HTML flamegraphs. | +| `DECNET_PROFILE_DIR` | path | `profiles` | No | Output directory for flamegraphs. Relative paths are relative to `$PWD`. | + +## API server + +| Name | Type | Default | Required | Consequence | +|------|------|---------|----------|-------------| +| `DECNET_API_HOST` | str | `127.0.0.1` | No | Bind address for the FastAPI server. | +| `DECNET_API_PORT` | int (1–65535) | `8000` | No | TCP port for the API. | +| `DECNET_JWT_SECRET` | str (≥32 chars) | — | **Yes** | HS256 signing secret. Missing, known-bad, or short values abort startup unless `DECNET_DEVELOPER=true` (and even then, known-bad is still rejected). | +| `DECNET_INGEST_LOG_FILE` | path | `/var/log/decnet/decnet.log` | No | File the ingester tails for honeypot events. | + +## Ingester batching + +| Name | Type | Default | Required | Consequence | +|------|------|---------|----------|-------------| +| `DECNET_BATCH_SIZE` | int | `100` | No | Rows accumulated per DB commit. Larger batches reduce SQLite write-lock contention. | +| `DECNET_BATCH_MAX_WAIT_MS` | int | `250` | No | Maximum milliseconds to wait before flushing a partial batch. Bounds latency during idle periods. | + +## Web dashboard + +| Name | Type | Default | Required | Consequence | +|------|------|---------|----------|-------------| +| `DECNET_WEB_HOST` | str | `127.0.0.1` | No | Bind address for the web dashboard. | +| `DECNET_WEB_PORT` | int (1–65535) | `8080` | No | Web dashboard port. | +| `DECNET_ADMIN_USER` | str | `admin` | No* | Admin login. `admin` is a known-bad default and is rejected at startup outside pytest. | +| `DECNET_ADMIN_PASSWORD` | str | `admin` | No* | Admin password. Rejected if set to a known-bad value. Change both. | +| `DECNET_DEVELOPER` | bool | `false` | No | `true` enables DEBUG logging and relaxes the JWT length check. Does not enable tracing. | + +*The defaults exist so imports do not crash, but the web API refuses to start +with them in non-pytest environments. + +## Tracing (OpenTelemetry) + +Independent from `DECNET_DEVELOPER` so tracing can be toggled on its own. + +| Name | Type | Default | Required | Consequence | +|------|------|---------|----------|-------------| +| `DECNET_DEVELOPER_TRACING` | bool | `false` | No | Enable OpenTelemetry tracing for the API and workers. | +| `DECNET_OTEL_ENDPOINT` | URL | `http://localhost:4317` | No | OTLP gRPC collector endpoint. | + +See [Tracing and Profiling](Tracing-and-Profiling). + +## Database + +See [Database Drivers](Database-Drivers) for the full driver matrix. + +| Name | Type | Default | Required | Consequence | +|------|------|---------|----------|-------------| +| `DECNET_DB_TYPE` | `sqlite` \| `mysql` | `sqlite` | No | Selects the repository subclass. Lower-cased automatically. | +| `DECNET_DB_URL` | SQLAlchemy URL | unset | No | Full URL, e.g. `mysql+asyncmy://user:pass@host:3306/decnet`. **When set, all component vars below are ignored.** | +| `DECNET_DB_HOST` | str | `localhost` | No | MySQL host. | +| `DECNET_DB_PORT` | int (1–65535) | `3306` | No | MySQL port. Validated only when explicitly set. | +| `DECNET_DB_NAME` | str | `decnet` | No | Database name. | +| `DECNET_DB_USER` | str | `decnet` | No | DB user. | +| `DECNET_DB_PASSWORD` | str | unset | No | DB password. `None` when unset. | + +## CORS + +| Name | Type | Default | Required | Consequence | +|------|------|---------|----------|-------------| +| `DECNET_CORS_ORIGINS` | CSV of URLs | `http://:` | No | Allowed origins for the dashboard API. Wildcard bind addresses (`0.0.0.0`, `127.0.0.1`, `::`) resolve to `localhost` in the default. | + +Example override: + +```bash +DECNET_CORS_ORIGINS=http://192.168.1.50:9090,https://dashboard.example.com +``` + +## Starter `.env.local` + +Copy this to the project root as `.env.local`, change every placeholder, and +keep it out of git. + +```bash +# System logging +DECNET_SYSTEM_LOGS=decnet.system.log + +# Embedded workers (leave off unless you know why) +DECNET_EMBED_PROFILER=false +DECNET_EMBED_SNIFFER=false + +# Request profiling +DECNET_PROFILE_REQUESTS=false +DECNET_PROFILE_DIR=profiles + +# API +DECNET_API_HOST=127.0.0.1 +DECNET_API_PORT=8000 +# Generate with: python -c 'import secrets; print(secrets.token_urlsafe(48))' +DECNET_JWT_SECRET=REPLACE_WITH_A_64_BYTE_URLSAFE_TOKEN_NOT_IN_THE_BAD_LIST +DECNET_INGEST_LOG_FILE=/var/log/decnet/decnet.log + +# Ingester batching +DECNET_BATCH_SIZE=100 +DECNET_BATCH_MAX_WAIT_MS=250 + +# Web dashboard +DECNET_WEB_HOST=127.0.0.1 +DECNET_WEB_PORT=8080 +DECNET_ADMIN_USER=anti +DECNET_ADMIN_PASSWORD=REPLACE_ME_WITH_A_LONG_PASSPHRASE +DECNET_DEVELOPER=false + +# Tracing +DECNET_DEVELOPER_TRACING=false +DECNET_OTEL_ENDPOINT=http://localhost:4317 + +# Database (sqlite is the default; uncomment the mysql block to switch) +DECNET_DB_TYPE=sqlite +# DECNET_DB_TYPE=mysql +# DECNET_DB_URL=mysql+asyncmy://decnet:REPLACE_ME@db.internal:3306/decnet +# DECNET_DB_HOST=db.internal +# DECNET_DB_PORT=3306 +# DECNET_DB_NAME=decnet +# DECNET_DB_USER=decnet +# DECNET_DB_PASSWORD=REPLACE_ME + +# CORS (only needed when the browser is not on the same host:port as the API) +# DECNET_CORS_ORIGINS=http://192.168.1.50:9090,https://dashboard.example.com +``` + +## Notes + +`decnet/config.py` re-reads `DECNET_DEVELOPER` and `DECNET_SYSTEM_LOGS` during +logging setup. Those are the same variables documented above — there are no +others. diff --git a/Teardown-and-State.md b/Teardown-and-State.md new file mode 100644 index 0000000..9fbef23 --- /dev/null +++ b/Teardown-and-State.md @@ -0,0 +1,177 @@ +# Teardown and State + +DECNET keeps the whole fleet picture in a single file, `decnet-state.json`, +at the project root. Every command that touches a running deployment +(`decnet status`, `decnet teardown`, the web dashboard, the sniffer, the +collector) loads it; `decnet deploy` writes it. + +Without this file, teardown cannot find the compose project, the sniffer +cannot map IPs to deckies, and the collector does not know which containers +to tail. + +See also: [Environment Variables](Environment-Variables), +[Database Drivers](Database-Drivers), [Systemd](Systemd-Setup). + +## Layout + +`decnet-state.json` has exactly two top-level keys: + +```json +{ + "config": { ... DecnetConfig.model_dump() ... }, + "compose_path": "/absolute/path/to/decnet-compose.yml" +} +``` + +- `config` — the serialised `DecnetConfig` pydantic model + (`decnet/models.py`): `mode`, `interface`, `subnet`, `gateway`, `ipvlan`, + `mutate_interval`, `log_file`, and the full `deckies[]` list. Each + `DeckyConfig` entry carries name, IP, services, distro, base image, + hostname, archetype, per-service config, `nmap_os`, and rotation timestamps. +- `compose_path` — absolute path to the generated + `decnet-compose.yml`. Teardown uses it as the `-f` argument to + `docker compose`. + +### Example `decnet-state.json` + +```json +{ + "config": { + "mode": "unihost", + "interface": "eth0", + "subnet": "192.168.1.0/24", + "gateway": "192.168.1.1", + "ipvlan": false, + "mutate_interval": 30, + "log_file": "/var/log/decnet/decnet.log", + "deckies": [ + { + "name": "decky-01", + "ip": "192.168.1.201", + "services": ["ssh", "smb"], + "distro": "debian", + "base_image": "debian:bookworm-slim", + "build_base": "debian:bookworm-slim", + "hostname": "fileserver-02", + "archetype": "office-fileshare", + "service_config": {}, + "nmap_os": "linux", + "mutate_interval": null, + "last_mutated": 0.0, + "last_login_attempt": 0.0 + }, + { + "name": "decky-02", + "ip": "192.168.1.202", + "services": ["rdp"], + "distro": "ubuntu22", + "base_image": "ubuntu:22.04", + "build_base": "debian:bookworm-slim", + "hostname": "WIN-DESK01", + "archetype": null, + "service_config": {}, + "nmap_os": "windows", + "mutate_interval": null, + "last_mutated": 0.0, + "last_login_attempt": 0.0 + } + ] + }, + "compose_path": "/home/anti/Tools/DECNET/decnet-compose.yml" +} +``` + +## API + +All three helpers live in `decnet/config.py`: + +### `save_state(config: DecnetConfig, compose_path: Path) -> None` + +Dumps `{"config": config.model_dump(), "compose_path": str(compose_path)}` +as pretty-printed JSON (`indent=2`) to `STATE_FILE` +(`/decnet-state.json`). Overwrites any existing file. + +Called by `decnet/engine/deployer.py::deploy` after the compose file is +written and before `docker compose up`. + +### `load_state() -> tuple[DecnetConfig, Path] | None` + +Returns `None` when the file does not exist. Otherwise parses the JSON, +re-hydrates `DecnetConfig`, and returns `(config, Path(compose_path))`. + +Callers: + +- `decnet/engine/deployer.py` — `teardown()` and `status()`. +- `decnet/sniffer/worker.py` — builds the IP-to-decky-name map. +- `decnet/collector/worker.py` — resolves the exact set of service container + names to tail. Wrapped in `asyncio.to_thread()` to keep the event loop clean. +- `decnet/web/db/sqlmodel_repo.py` — uses `asyncio.to_thread(load_state)` to + surface deployment metadata through the dashboard API. + +### `clear_state() -> None` + +`unlink()`s the state file if present. A no-op otherwise. Called once by +`teardown()` after `docker compose down` and host-interface cleanup succeed. + +## How teardown cleans host interfaces + +`decnet/engine/deployer.py::teardown(decky_id=None)` runs, in order: + +1. `load_state()`. If it returns `None`, prints + `No active deployment found (no decnet-state.json).` and exits. +2. If `decky_id` is given, `docker compose stop -...` then + `docker compose rm -f ...` for that decky only. **No host-interface + cleanup and no state clear** — the rest of the fleet is still alive. +3. If no `decky_id` (full teardown): + 1. `docker compose down` with the `compose_path` from state. + 2. Compute the decky IP range with `ips_to_range([d.ip for d in config.deckies])`. + 3. Remove the host-side L2 interface: + - `teardown_host_ipvlan(decky_range)` when `config.ipvlan` is `true`, or + - `teardown_host_macvlan(decky_range)` otherwise. + 4. `remove_macvlan_network(client)` drops the docker network. + 5. `clear_state()` deletes `decnet-state.json`. + 6. Logs `teardown complete` and prints the driver that was removed. + +If step 3 never runs (you ctrl-C'd, or one of the subprocess calls errored), +`decnet-state.json` stays on disk and so do the host interfaces. Re-running +`sudo decnet teardown --all` is idempotent and safe. + +## When you need `sudo` + +Anything that touches host networking — creating or removing a MACVLAN / +IPvlan parent interface, opening a raw socket for the sniffer — needs +`CAP_NET_ADMIN`, which in practice means `sudo`: + +- `sudo decnet deploy ...` — creates the host interface, writes + `decnet-state.json`, brings up the compose project. +- `sudo decnet teardown` / `sudo decnet teardown --all` — removes host + interfaces, clears state. Without `sudo` the ip-link calls fail and the + state file is left behind. +- `sudo decnet teardown --id decky-01` — still needs `sudo` if the compose + project was created by root. +- `sudo decnet sniffer --daemon` — raw packet capture on the parent iface. + +Read-only commands that only consult `decnet-state.json` and the dashboard +DB do not need root: + +- `decnet status` +- `decnet services` +- `decnet deploy --dry-run` (generates the compose file only) +- `decnet api` / `decnet web` once the deployment is up — as long as the + state file and `DECNET_SYSTEM_LOGS` are readable by the invoking user. + `decnet/config.py` drops root ownership of the system log when invoked via + `sudo` precisely so the follow-up non-root commands can append to it. + +## Troubleshooting + +- **`No active deployment found`** — `decnet-state.json` is missing. + Either the deploy never completed, or a previous teardown already ran. +- **Orphan host interfaces after a crash** — re-run + `sudo decnet teardown --all`. If state is gone, remove them manually with + `ip link del decnet-mv0` (or the ipvlan equivalent) and delete the docker + network. +- **`PermissionError` writing the state file** — you ran `decnet deploy` + without `sudo` on a fresh checkout; the project root is not writable by + the current user. Either `chmod` the directory or run as root. +- **Stale `compose_path`** — moving the project directory after deploy + breaks teardown. Tear down first, move, redeploy. From ad34cc68810d3b810c685834f6a7546afb6054c1 Mon Sep 17 00:00:00 2001 From: anti Date: Sat, 18 Apr 2026 06:07:29 -0400 Subject: [PATCH 2/2] docs(wiki): add Unit 18 project-meta pages Sponsors, Support-the-Project, Security-and-Stealth, Roadmap-and-Known-Debt, Troubleshooting. --- Roadmap-and-Known-Debt.md | 29 ++++++++++++++++++ Security-and-Stealth.md | 56 ++++++++++++++++++++++++++++++++++ Sponsors.md | 30 +++++++++++++++++++ Support-the-Project.md | 49 ++++++++++++++++++++++++++++++ Troubleshooting.md | 63 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 227 insertions(+) create mode 100644 Roadmap-and-Known-Debt.md create mode 100644 Security-and-Stealth.md create mode 100644 Sponsors.md create mode 100644 Support-the-Project.md create mode 100644 Troubleshooting.md diff --git a/Roadmap-and-Known-Debt.md b/Roadmap-and-Known-Debt.md new file mode 100644 index 0000000..9c9368e --- /dev/null +++ b/Roadmap-and-Known-Debt.md @@ -0,0 +1,29 @@ +# Roadmap and Known Debt + +DECNET keeps its forward-looking and backward-looking planning docs inside the main repo under `development/`. This page is an index — no duplication. + +## Roadmap and Future Work + +- `development/FUTURE.md` — planned features and direction. +- `development/ICS_SCADA.md` — ICS/SCADA decoy work. +- `development/IMAP_BAIT.md` — IMAP bait service design. +- `development/SMTP_RELAY.md` — SMTP relay decoy work. + +## Known Debt and Bugs + +- `development/DEBT.md` — accepted tech debt. +- `development/BUGS.md` — known open bugs. +- `development/BUG_FIXES.md` — recently fixed, for history. +- `development/HARDENING.md` — hardening backlog. + +## Audits and Coverage + +- `development/REALISM_AUDIT.md` — decoy realism audit notes. +- `development/COVERAGE.md` — test coverage state. +- `development/EVENTS.md` — event pipeline and schema notes. + +Each of these files lives in the DECNET repo, not this wiki. Follow the links above from a working checkout. + +--- + +See also: [[Home]] · [[Developer-Guide]] · [[Troubleshooting]] diff --git a/Security-and-Stealth.md b/Security-and-Stealth.md new file mode 100644 index 0000000..9d75d99 --- /dev/null +++ b/Security-and-Stealth.md @@ -0,0 +1,56 @@ +# Security and Stealth + +DECNET sits on the attacker-facing edge of a network, so its own posture matters as much as the decoys it deploys. + +## Authentication + +### JWT + +- Algorithm: **HS256** (see `decnet/web/auth.py`). +- Secret: `DECNET_JWT_SECRET` — must be **≥ 32 characters**. Anything shorter is rejected at startup with an explicit error referencing RFC 7518 §3.2 (see `decnet/env.py`). +- No fallback: the env var is required, not optional. + +### Admin Credentials + +- `DECNET_ADMIN_USER` / `DECNET_ADMIN_PASSWORD` seed the initial admin on first boot (`decnet/web/db/sqlmodel_repo.py`). +- The combination `admin/admin` is rejected at startup. Deployments must pick a real password. +- Passwords are hashed with **bcrypt** — plaintext is never persisted. + +### RBAC + +- All admin endpoints are gated server-side via `require_admin` / `require_role("admin")` dependencies (`decnet/web/dependencies.py`). +- **Contributor rule (ANTI)**: the admin UI must be server-gated, never client-side only. A hidden button is not access control. + +## Stealth in Active Probes + +**Contributor rule (ANTI)**: active probes and health checks must never reveal DECNET's identity. + +- No `User-Agent: DECNET/...`. +- No banners, headers, or log lines that leak the framework name to a decoy or an external target. +- Probe traffic should be indistinguishable from ordinary tooling (curl, nmap, python-requests). If you're adding a probe and unsure, ask before merging. + +## Network Architecture + +- Decoy network is attacker-facing by design. +- Logging / aggregation network (Logstash → ELK → SIEM) is **isolated** from the decoy network. +- A publicly accessible real server bridges the two; deckies never talk to the SIEM directly. + +See the top-level `README.md` for the full diagram. + +## OS Fingerprint Spoofing + +Deckies rotate service banners, TTLs, TCP options, and OS hints to look heterogeneous. Mutation is time-based and randomized per decky. + +- Details: [[Mutation-and-Randomization]] + +## Responsible Disclosure + +Found a security issue in DECNET itself (not a decoy)? Email: + +- `TODO: add security@ disclosure address` + +Please do not file public issues for exploitable bugs. + +--- + +See also: [[Troubleshooting]] · [[Environment-Variables]] · [[Web-Dashboard]] diff --git a/Sponsors.md b/Sponsors.md new file mode 100644 index 0000000..7957884 --- /dev/null +++ b/Sponsors.md @@ -0,0 +1,30 @@ +# Sponsors + +DECNET is built and maintained with the help of a small number of generous sponsors. Without their backing the project would not exist in its current form. + +## Current Sponsors + +### SecureJump + +- Website: https://securejump.cl +- Offensive-security and adversary-simulation outfit based in Chile. SecureJump's red-team crew has contributed threat-model input that shaped DECNET's decoy-service realism and fingerprint spoofing. + +### Xmartlab + +- Website: https://xmartlab.com +- Engineering lab sponsoring infrastructure, test hardware, and maintainer time. Xmartlab hosts the build and integration environment used for DECNET's swarm-mode testing. + +## Logos + +> Note: logo images must be uploaded to the wiki repo separately; the paths below are placeholders. + +- ![SecureJump](sponsor-logos/securejump.png) +- ![Xmartlab](sponsor-logos/xmartlab.png) + +## Thank You + +To SecureJump and Xmartlab — thank you for keeping the lights on, the containers running, and the decoys convincing. + +--- + +See also: [[Support-the-Project]] · [[Home]] diff --git a/Support-the-Project.md b/Support-the-Project.md new file mode 100644 index 0000000..d3643af --- /dev/null +++ b/Support-the-Project.md @@ -0,0 +1,49 @@ +# Support the Project + +DECNET is open-source, maintained in the open, and not cheap to keep running. If your team benefits from decoy-network research, please consider sponsoring. + +## Why Sponsor DECNET + +- **Maintenance**: keeping decoy services realistic means chasing CVEs, banner drift, and fingerprint tells on a rolling basis. +- **Infrastructure**: multi-host swarm testing, SIEM/ELK rigs, and realistic NIC hardware cost money. +- **Time**: the maintainer's hours are finite. Sponsorship buys focused, dedicated effort on roadmap items. + +## Tiers + +### Bronze + +- Small logo on the [[Sponsors]] page. +- Mention in release notes. + +### Silver + +- Medium logo on the [[Sponsors]] page. +- Feature-request priority in the issue tracker. +- Quarterly office-hours call with the maintainer. + +### Gold + +- Large logo on the [[Sponsors]] page. +- Roadmap co-design input. +- Advisory access to the maintainer. +- Private-channel support. + +## How to Sponsor + +Corporate sponsorships, invoicing, and tier selection: + +- **Contact**: samuel.paschuan@xmartlab.com + +Payment channels: + +- Stripe: `TODO: add Stripe link` +- BTC: `TODO: add BTC address` +- ETH: `TODO: add ETH address` + +## Individual Donors + +Not a company? No problem. If DECNET saved you a weekend of honeypot plumbing, drop a coffee's worth into the tip jar — small donations genuinely keep the project moving, and they accumulate. Use the Stripe link above (once live) or reach out by email for a one-off transfer. No tier, no logo, just appreciation. + +--- + +See also: [[Sponsors]] · [[Security-and-Stealth]] · [[Roadmap-and-Known-Debt]] diff --git a/Troubleshooting.md b/Troubleshooting.md new file mode 100644 index 0000000..d506828 --- /dev/null +++ b/Troubleshooting.md @@ -0,0 +1,63 @@ +# Troubleshooting + +Common gotchas when deploying and running DECNET. + +## Networking + +### MACVLAN fails on WSL + +WSL does not play nicely with MACVLAN drivers. Options: + +- Run DECNET on bare metal or inside a proper VM (preferred). +- Fall back to IPVLAN by passing `--ipvlan` on the deploy command. + +See [[Home]] for supported environments. + +### NIC not in promiscuous mode + +Deckies and the sniffer need the host NIC in promiscuous mode to see decoy-directed traffic. If captures look empty: + +```bash +sudo ip link set promisc on +``` + +## Auth and Startup + +### `admin/admin` rejected at startup + +Intentional. DECNET refuses to boot with the trivial default. Set `DECNET_ADMIN_USER` and `DECNET_ADMIN_PASSWORD` to real values. + +### JWT secret too short + +`DECNET_JWT_SECRET` must be at least **32 bytes** for HS256 (RFC 7518 §3.2). Shorter secrets are rejected at startup with an explicit error. See `decnet/env.py`. + +## Embedded vs Standalone Workers + +Running both the embedded profiler/sniffer **and** a standalone instance causes duplicate or skipped events. + +Fix: pick one. Unset the embed flags when running standalone workers: + +```bash +unset DECNET_EMBED_PROFILER +unset DECNET_EMBED_SNIFFER +``` + +See [[Environment-Variables]]. + +## Python Runtime + +### Python 3.14 GC instability under load + +The 3.14 GC has surfaced crashes under DECNET's load profile. Pin to **Python 3.11 – 3.13** until upstream stabilizes. + +## Database + +### SQLite write contention + +Under heavy concurrent event ingestion, SQLite can hit writer-lock contention. Switch the backend to MySQL. + +See [[Database-Drivers]]. + +--- + +See also: [[Security-and-Stealth]] · [[Environment-Variables]] · [[Roadmap-and-Known-Debt]]