CIS490/etc/cis490-bootstrap.service
max 265f3ad313 Tier-4 sample source: theZoo (no auth, no operator action)
Replaces MalwareBazaar with theZoo (https://github.com/ytisf/theZoo).
theZoo is a public security-research repo with hundreds of malware
samples organized by family, password-protected with the well-known
'infected'. No API key, no signup, nothing for an operator to do —
which is what zero-touch tier-4 actually means.

Changes:

- tools/auto_fetch_samples.py: rewrite. Clones theZoo (shallow, ~500 MB)
  to /var/lib/cis490/theZoo on first run, then for each manifest
  family without a sha256 it locates a matching Binaries/<Name>
  dir, extracts the .zip with password 'infected', picks the largest
  non-text payload as the binary, sha256s it, stages at
  samples/store/<sha256>, and rewrites manifest.toml in place
  (atomic tempfile + os.replace, stat preserved). Mandatory exit
  semantic: non-zero if no real samples landed.

- scripts/install-tier-3-4.sh: dropped the MB-key resolution chain
  (env var → local file → bootstrap.wg fetch). Now just runs
  auto_fetch_samples.py and dies if zero samples land. SKIP_TIER4
  remains as the explicit override but is documented as defeating
  the project.

- bootstrap/app.py + __main__.py + etc/cis490-bootstrap.service:
  removed the /v1/secret/<name> endpoint and the --secrets-root flag.
  Dead code now that no API key needs distributing. Live-rolled
  back on the Pi (404 verified post-restart, stale /etc/cis490/secrets
  dir removed).

- scripts/set-malwarebazaar-key.sh: deleted. No MB key means no
  one-time operator step.

- tests/test_bootstrap_secrets.py: deleted (route removed).

- AGENTS.md: rewrote tier-4 section to reflect zero-operator model.

148/148 tests pass. Bootstrap service rolled back live.
2026-05-01 01:17:50 -05:00

44 lines
1.4 KiB
Desktop File

[Unit]
Description=CIS490 mTLS bootstrap endpoint (auto-issue client certs to enrolled lab hosts)
Documentation=https://maxgit.wg/spectral/CIS490
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
# Runs as root because the wg-pki CA private key is root-only. The
# service shells out to issue-cis490-client-cert.sh per mint and
# never touches anything else under /var/lib.
User=root
Group=root
WorkingDirectory=/opt/cis490
ExecStart=/opt/cis490/.venv/bin/python -m bootstrap \
--listen-host 127.0.0.1 \
--listen-port 8446 \
--issuer-script /opt/wg-pki/scripts/issue-cis490-client-cert-wrapper.sh \
--issued-root /var/lib/wg-pki/issued
Restart=on-failure
RestartSec=5
# Hardening — narrower than receiver because this binary's only job
# is to call openssl + tar via the issuer script, then serve files.
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
# /home/max/.env/wg-pki/scripts/ holds the issuer script the wrapper
# exec's. ProtectHome={read-only,tmpfs} both *hide* /home contents
# instead of restricting them to read-only — so we leave /home
# accessible. ProtectSystem=strict still keeps everything outside
# /var/lib/wg-pki write-protected.
ProtectHome=no
ReadWritePaths=/var/lib/wg-pki
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
LockPersonality=true
RestrictNamespaces=true
RestrictRealtime=true
SystemCallArchitectures=native
[Install]
WantedBy=multi-user.target