mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-28 15:28:24 +00:00
feat(profiles): package waker/sleeper + lifecycle policy, v0.8.0 (ref #896)
Wires the scale-to-zero services into debian/ packaging: secubox-wakectl entry point (/usr/sbin), templates/waking.html now ships, secubox-waker and secubox-sleeper systemd units registered via dh_installsystemd --name=, enabled/restarted (try-restart, preserving runtime state) in postinst alongside secubox-profiles.service. postinst now also runs secubox-wakectl waf-sync/health-sync so sbxwaf and the health monitor have their lists from first install (nginx-sync stays unwired per the 2026-07-20 pivot). Hardens secubox-sleeper.service with ProtectSystem=strict and an explicit ReadWritePaths covering the actuator's real write set, traced through api/actuate.py/snapshot.py/audit.py: /run/secubox, /var/lib/secubox/profiles/rollback, /var/log/secubox, /data/lxc, and /etc/secubox/waf (haproxy-routes.json, written on a routed module's STOP — missed by a naive reading of the write set). Documents the lifecycle/wake_class policy, the waker/sleeper mechanism and a pilot procedure in README.md, wiki/Architecture.md and .claude/MODULE-COMPLIANCE.md. Bumps changelog to 0.8.0. Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
This commit is contained in:
parent
dc08a8c139
commit
d67e2c03b7
|
|
@ -91,6 +91,24 @@ packages/secubox-<module>/
|
|||
└── README.md # Module documentation
|
||||
```
|
||||
|
||||
### Lifecycle Policy — scale-to-zero (ref #896)
|
||||
|
||||
Every module known to `secubox-profiles` (its manifest under
|
||||
`/etc/secubox/modules.d/<id>.toml`) declares a `lifecycle`: `always-on`
|
||||
(never stopped — forced for any `protected` module regardless of what it
|
||||
declares), `eager` (starts at boot, may be idled), `on-demand` (off by
|
||||
default, woken on first access), or `manual` (operator-only, via the
|
||||
`/profiles/` panel). An optional `wake_class` (`normal`/`urgent`) tunes the
|
||||
idle threshold and the wake-splash budget. This is a **module-wide**
|
||||
guideline, not a `secubox-profiles`-internal detail: a module choosing
|
||||
`on-demand`/`eager` is opting into being stopped by `secubox-sleeper.service`
|
||||
and woken via `secubox-waker.service` (fronted by `sbxwaf`, which proxies a
|
||||
request for a routeless on-demand vhost to the waker instead of returning
|
||||
421). See `packages/secubox-profiles/README.md` (§ Scale-to-zero) and
|
||||
`wiki/Architecture.md` (§ Scale-to-zero) for the full policy table, the
|
||||
wake/sleep mechanism, and the pilot procedure for switching a module to
|
||||
`on-demand`.
|
||||
|
||||
### Web UI Requirements (Pattern 12)
|
||||
|
||||
All module frontends MUST include:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# secubox-profiles
|
||||
|
||||
Inventaire et profils des modules SecuBox. **Phase 1 : lecture seule.**
|
||||
**0.4.0+ : actuation (apply/rollback). 0.8.0 (ref #896) : scale-to-zero
|
||||
(lifecycle/wake_class, waker, sleeper).**
|
||||
|
||||
## Commandes
|
||||
|
||||
|
|
@ -68,6 +70,11 @@ toutes les routes (`Depends(require_jwt)`).
|
|||
| GET | `/api/v1/profiles/diff?profile=<nom>` | plan de changements (**n'applique rien**) — 404 si profil inconnu, 409 si `ProtectedViolation` |
|
||||
| POST | `/api/v1/profiles/profiles/{name}/members` | `{"id","on"}` — ajoute/retire un module de la liste `on` d'un profil (404 id/profil inconnu) |
|
||||
| POST | `/api/v1/profiles/pins` | `{"id","pin":"on"\|"off"\|null}` — pose/lève un pin ; **409 et rien d'écrit** si `pin="off"` sur un module protégé |
|
||||
| POST | `/api/v1/profiles/active` | `{"name"}` — change le profil actif (fichier `active`, pas d'actuation) |
|
||||
| POST | `/api/v1/profiles/apply` | applique le profil actif (webui→ctl : sudo `secubox-profilectl apply --yes --json`) — snapshot 4R + audit, rollback auto si échec |
|
||||
| POST | `/api/v1/profiles/rollback` | recharge le dernier snapshot 4R (webui→ctl : `secubox-profilectl rollback --yes --json`) |
|
||||
| POST | `/api/v1/profiles/wake` | `{"id"}` — réveille manuellement UN module on-demand (webui→ctl, **synchrone** : `secubox-wakectl wake <id> --json`) |
|
||||
| POST | `/api/v1/profiles/sleep` | `{"id"}` — endort manuellement UN module sleepable (webui→ctl : `secubox-profilectl apply --only <id> --yes --json`) |
|
||||
|
||||
Écritures limitées à `/etc/secubox/profiles/<nom>.toml` et `pins.toml`
|
||||
(atomique : fichier temporaire + `os.replace`) — c'est ce qui rend Phase 1
|
||||
|
|
@ -82,19 +89,88 @@ Panel webui : `/profiles/` (hybrid-dark, cf. `.claude/WEBUI-PANEL-GUIDELINES.md`
|
|||
|
||||
## Manifeste
|
||||
|
||||
id = "peertube"
|
||||
category = "media" # media|security|network|infra|dev|mesh
|
||||
runtime = "lxc" # native|lxc
|
||||
exposure = "public" # public|lan|internal
|
||||
units = ["secubox-peertube.service"]
|
||||
lxc = "peertube"
|
||||
portal = { domain = "peertube.gk2.secubox.in" }
|
||||
priority = 40 # 0-100
|
||||
protected = false # true = jamais éteignable
|
||||
needs = ["auth"]
|
||||
id = "peertube"
|
||||
category = "media" # media|security|network|infra|dev|mesh
|
||||
runtime = "lxc" # native|lxc
|
||||
exposure = "public" # public|lan|internal
|
||||
units = ["secubox-peertube.service"]
|
||||
lxc = "peertube"
|
||||
portal = { domain = "peertube.gk2.secubox.in" }
|
||||
priority = 40 # 0-100
|
||||
protected = false # true = jamais éteignable
|
||||
needs = ["auth"]
|
||||
lifecycle = "on-demand" # always-on|eager|on-demand|manual (défaut: eager)
|
||||
wake_class = "normal" # normal|urgent (défaut: normal)
|
||||
|
||||
Un manifeste corrigé à la main fait autorité : `scan` ne l'écrase pas sans `--force`.
|
||||
|
||||
## Scale-to-zero — lifecycle, waker, sleeper (ref #896)
|
||||
|
||||
Chaque module déclare un `lifecycle` dans son manifeste
|
||||
(`/etc/secubox/modules.d/<id>.toml`) :
|
||||
|
||||
| `lifecycle` | Démarre au boot ? | Rendormi si idle ? | Réveillé sur accès ? |
|
||||
|---|---|---|---|
|
||||
| `always-on` | oui, toujours | jamais | — (jamais éteint) |
|
||||
| `eager` | oui | oui (si idle et sans réponse `/idle`) | oui (déjà up en général) |
|
||||
| `on-demand` | non | oui | oui — `sbxwaf` proxy vers le waker |
|
||||
| `manual` | non | non | non — opérateur uniquement (`/wake` panel) |
|
||||
|
||||
Un module `protected = true` est **toujours** `always-on`, quoi que déclare
|
||||
son `lifecycle` (`effective_lifecycle`, `api/lifecycle.py`) — le cœur ne dort
|
||||
jamais. `wake_class = "urgent"` multiplie le seuil d'inactivité avant sommeil
|
||||
(×4) et réduit le budget de réveil affiché (15s au lieu de 45s) — pour les
|
||||
modules qu'on préfère garder chauds plus longtemps mais réveiller vite s'ils
|
||||
dorment quand même.
|
||||
|
||||
**Le sommeil (`secubox-sleeper.service`, daemon root, tick 30s)** — construit
|
||||
un plan STOP pour chaque module `eager`/`on-demand` observé up, idle depuis
|
||||
`idle_threshold()`, sans connexion active, et sans verrou de réveil en cours
|
||||
(`/run/secubox/waker-active.json`) — et le confie à l'actionneur 0.7.0
|
||||
(`apply_plan` : snapshot 4R, audit, timeout dérivé, rollback si échec). Ne
|
||||
dort **jamais** sur un signal indéterminé (fichier de signaux absent/vide,
|
||||
sonde `/idle` muette) — l'incertitude protège toujours l'état "up".
|
||||
|
||||
**Le réveil (`secubox-waker.service`, `User=secubox`, socket
|
||||
`/run/secubox/waker.sock`)** — `sbxwaf` (Go, `packages/secubox-toolbox-ng`)
|
||||
proxy une requête vers un vhost on-demand sans route active vers
|
||||
`/_wake/<vhost>` au lieu de répondre 421. Le waker résout vhost→module, pose
|
||||
un verrou par module (une requête déclenche le réveil, N requêtes
|
||||
concurrentes attendent le même réveil), tire `sudo→systemd-run→
|
||||
secubox-wakectl wake <id>` (fire-and-forget, webui→ctl — le waker ne pilote
|
||||
jamais systemd/LXC en direct) et sert le splash `templates/waking.html`
|
||||
(503 + `Retry-After`, palette hybrid-dark, auto-refresh) le temps du réveil.
|
||||
|
||||
**Config générée pour les consommateurs** (`secubox-wakectl waf-sync` /
|
||||
`health-sync`, exécutés au postinst et re-exécutables à la main après un
|
||||
`scan`) :
|
||||
|
||||
| Fichier | Consommateur | Contenu |
|
||||
|---|---|---|
|
||||
| `/etc/secubox/waf/on-demand-vhosts.json` | `sbxwaf` | domaines portail des modules `eager`/`on-demand` routés — décide "proxy vers le waker" vs 421 |
|
||||
| `/etc/secubox/health/sleepable-modules.json` | `secubox-hub` (moniteur santé) | ids des modules sleepables — distingue "volontairement endormi" de "en panne" |
|
||||
|
||||
`api/nginxgen.py`/`nginx-sync` (Tâche 7) restent dans l'arbre mais **ne sont
|
||||
plus câblés** — PIVOT (2026-07-20) : le déclencheur de réveil est `sbxwaf`,
|
||||
pas un `location @waker` nginx.
|
||||
|
||||
**Procédure pilote** (un module `on-demand` à la fois, avant généralisation) :
|
||||
|
||||
1. Éditer `/etc/secubox/modules.d/<id>.toml` : `lifecycle = "on-demand"`
|
||||
(et `wake_class` si le module doit rester chaud plus longtemps).
|
||||
2. `secubox-wakectl waf-sync && secubox-wakectl health-sync` (ou attendre le
|
||||
prochain postinst — mais après une simple édition manuelle du manifeste,
|
||||
régénérer à la main pour que `sbxwaf` voie le nouveau vhost tout de suite).
|
||||
3. `secubox-profilectl apply --only <id> --yes --json` pour l'endormir une
|
||||
première fois (ou attendre le prochain tick idle du sleeper).
|
||||
4. Visiter le vhost à froid : la première requête doit voir le splash 503
|
||||
puis, après `wake_budget()` secondes, le service réel.
|
||||
5. Surveiller `/var/log/secubox/audit.log` (entrées `wake-on-access` /
|
||||
`idle-sleep`) et `journalctl -u secubox-waker -u secubox-sleeper`.
|
||||
6. `lifecycle = "manual"` si le pilote révèle un réveil trop lent/fragile
|
||||
pour un accès non annoncé — le module reste éteignable/allumable
|
||||
seulement depuis le panel.
|
||||
|
||||
## Tests
|
||||
|
||||
python3 -m pytest packages/secubox-profiles/tests -q
|
||||
|
|
|
|||
|
|
@ -1,3 +1,36 @@
|
|||
secubox-profiles (0.8.0-1~bookworm1) bookworm; urgency=medium
|
||||
|
||||
* Scale-to-zero (ref #896): ships the lifecycle/wake_class manifest policy
|
||||
(always-on/eager/on-demand/manual; normal/urgent — api/lifecycle.py),
|
||||
the secubox-waker activator (wake-on-access splash + one-wake lock,
|
||||
webui->ctl via systemd-run) and the secubox-sleeper idle daemon (idle
|
||||
detection off sbxwaf per-vhost signals, apply_plan-driven STOP, never
|
||||
sleeps on an indeterminate signal).
|
||||
* sbxwaf-side wake trigger (packages/secubox-toolbox-ng, packages/secubox-waf-ng):
|
||||
on-demand vhosts without an active route now proxy to the waker instead
|
||||
of 421 — supersedes the nginx `@waker` path (Task 7, now unwired;
|
||||
api/nginxgen.py stays in the tree, dead code, for a possible future
|
||||
dual-front-end). New `secubox-wakectl waf-sync`/`health-sync` write
|
||||
/etc/secubox/waf/on-demand-vhosts.json and
|
||||
/etc/secubox/health/sleepable-modules.json — run at postinst so sbxwaf
|
||||
and the health monitor have their lists from first install.
|
||||
* webui: `/profiles/` panel gains manual sleep/wake buttons (POST
|
||||
/wake, /sleep) alongside the existing lifecycle column in `/status`.
|
||||
* secubox-watchdog awareness: a sleeping eager/on-demand module is a
|
||||
DELIBERATE state, never auto-revived (watchdog_should_manage).
|
||||
* Packaging: new `secubox-waker.service` + `secubox-sleeper.service` units
|
||||
(enable --now + try-restart in postinst, preserving runtime state on
|
||||
upgrade), new `secubox-wakectl` entry point (/usr/sbin), templates/
|
||||
now ships (waking.html — the splash the waker serves). Sudoers grants
|
||||
for the waker/sleeper's webui->ctl calls were already shipped in 0.7.x.
|
||||
secubox-sleeper.service (the one unit that drives the actuator
|
||||
in-process, unlike waker/profiles which delegate via systemd-run) now
|
||||
runs ProtectSystem=strict with an explicit ReadWritePaths= covering the
|
||||
actuator's real write set (snapshot 4R, audit log, LXC autostart config,
|
||||
HAProxy portal routes) instead of an unconfined root process.
|
||||
|
||||
-- Gerald KERMA <devel@cybermind.fr> Mon, 20 Jul 2026 17:03:19 +0200
|
||||
|
||||
secubox-profiles (0.7.0-1~bookworm1) bookworm; urgency=medium
|
||||
|
||||
* apply: observed state (not command return code) arbitrates STOP/START —
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
api/*.py usr/lib/secubox/profiles/api/
|
||||
templates/waking.html usr/lib/secubox/profiles/templates/
|
||||
profiles/*.toml usr/share/secubox/profiles/
|
||||
sbin/secubox-profilectl usr/sbin/
|
||||
sbin/secubox-wakectl usr/sbin/
|
||||
www/profiles/index.html usr/share/secubox/www/profiles/
|
||||
menu.d/11-profiles.json usr/share/secubox/menu.d/
|
||||
nginx/profiles.conf etc/nginx/secubox-routes.d/
|
||||
|
|
|
|||
|
|
@ -25,12 +25,48 @@ case "$1" in
|
|||
fi
|
||||
done
|
||||
|
||||
# secubox-sleeper.service runs ProtectSystem=strict with an explicit
|
||||
# ReadWritePaths= (see debian/secubox-sleeper.service) — every
|
||||
# directory it lists MUST already exist before the unit's first
|
||||
# start, or systemd's sandbox will not make it writable. Pre-create
|
||||
# this package's own two leaves here (shared parents /var/lib/secubox
|
||||
# and /var/log/secubox themselves come from secubox-core, 0755
|
||||
# secubox:secubox — reasserted here matching the repo-wide
|
||||
# shared-parent convention, never narrowed to 0750). /run/secubox
|
||||
# comes from RuntimeDirectory=secubox; /data/lxc and /etc/secubox/waf
|
||||
# are provisioned by lxc/secubox-waf-ng respectively, not here.
|
||||
install -d -o secubox -g secubox -m 0755 /var/log/secubox
|
||||
install -d -o root -g root -m 0750 /var/lib/secubox/profiles/rollback
|
||||
|
||||
# Own dedicated socket, own service — never served by the aggregator
|
||||
# (the profile engine must not depend on something it may later
|
||||
# restart). Restart (not just enable) so an upgrade picks up new code.
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
systemctl enable secubox-profiles.service 2>/dev/null || true
|
||||
systemctl restart secubox-profiles.service 2>/dev/null || true
|
||||
|
||||
# secubox-waker + secubox-sleeper (ref #896, scale-to-zero): `enable
|
||||
# --now` is safe/idempotent (no-op if already enabled+running — the
|
||||
# first-install case starts them), `try-restart` afterwards is a
|
||||
# no-op if inactive and gracefully restarts (not a hard kill) an
|
||||
# ALREADY-running instance so an upgrade picks up new code without
|
||||
# forcibly disrupting an in-flight wake/sleep decision.
|
||||
systemctl enable --now secubox-waker.service secubox-sleeper.service 2>/dev/null || true
|
||||
systemctl try-restart secubox-waker.service secubox-sleeper.service 2>/dev/null || true
|
||||
|
||||
# Config sync for the sbxwaf-side wake trigger + the health monitor
|
||||
# (ref #896 — supersedes the nginx-sync path of Task 7, PIVOT
|
||||
# 2026-07-20): waf-sync writes the on-demand vhost list sbxwaf reads
|
||||
# to decide "proxy to the waker instead of 421"; health-sync writes
|
||||
# the sleepable-module-id set secubox-hub reads to distinguish
|
||||
# "voluntarily asleep" from "down". Both are idempotent, best-effort
|
||||
# (an empty modules.d before the first `scan` just yields an empty
|
||||
# list — never a postinst failure).
|
||||
[ -d /etc/secubox/waf ] || install -d -m 0750 /etc/secubox/waf
|
||||
install -d -o root -g root -m 0755 /etc/secubox/health
|
||||
/usr/sbin/secubox-wakectl waf-sync 2>/dev/null || true
|
||||
/usr/sbin/secubox-wakectl health-sync 2>/dev/null || true
|
||||
|
||||
systemctl reload nginx 2>/dev/null || true
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
if [ "$1" = "remove" ]; then
|
||||
systemctl stop secubox-profiles.service || true
|
||||
systemctl disable secubox-profiles.service || true
|
||||
systemctl stop secubox-profiles.service secubox-waker.service secubox-sleeper.service || true
|
||||
systemctl disable secubox-profiles.service secubox-waker.service secubox-sleeper.service || true
|
||||
systemctl reload nginx 2>/dev/null || true
|
||||
fi
|
||||
#DEBHELPER#
|
||||
|
|
|
|||
|
|
@ -8,3 +8,15 @@
|
|||
override_dh_auto_install:
|
||||
install -d debian/secubox-profiles/etc/sudoers.d
|
||||
install -m 0440 sudoers.d/secubox-profiles debian/secubox-profiles/etc/sudoers.d/secubox-profiles
|
||||
|
||||
# Three distinct units ship in this package (own socket each — see
|
||||
# debian/secubox-profiles.service, debian/secubox-waker.service,
|
||||
# debian/secubox-sleeper.service): dh_installsystemd's default naming only
|
||||
# auto-picks up debian/<pkgname>.service, so the other two need an explicit
|
||||
# --name= each. Default enable+start (no --no-enable) matches how
|
||||
# secubox-profiles.service already behaves (postinst also enables/restarts
|
||||
# it manually — same, deliberately redundant-but-safe pattern kept below).
|
||||
override_dh_installsystemd:
|
||||
dh_installsystemd --name=secubox-profiles
|
||||
dh_installsystemd --name=secubox-waker
|
||||
dh_installsystemd --name=secubox-sleeper
|
||||
|
|
|
|||
|
|
@ -22,19 +22,33 @@ UMask=0027
|
|||
# hands each idle module straight to api.apply.apply_plan, the SAME code
|
||||
# path as secubox-wakectl/secubox-profilectl apply/rollback — same trust
|
||||
# level, just driven by a timer loop instead of an operator or a wake
|
||||
# request. No ProtectSystem=strict either: apply_plan drives
|
||||
# systemctl/lxc-start/lxc-stop AND edits /data/lxc/<container>/config
|
||||
# (lxc.start.auto) and /etc/secubox/waf/haproxy-routes.json directly (see
|
||||
# api/actuate.py) — sandboxing this service would just reproduce, one layer
|
||||
# up, the exact EROFS lesson that motivated wrapping the OTHER two ctls in
|
||||
# systemd-run in the first place.
|
||||
# request.
|
||||
NoNewPrivileges=true
|
||||
RuntimeDirectory=secubox
|
||||
RuntimeDirectoryPreserve=yes
|
||||
RuntimeDirectoryMode=0775
|
||||
|
||||
# ProtectSystem=strict makes / read-only by default; the actuator's actual
|
||||
# write set (traced through api/actuate.py, api/snapshot.py, api/audit.py —
|
||||
# apply_plan's STOP path is the only one the sleeper ever drives) is listed
|
||||
# explicitly below so this sandbox stays FUNCTIONAL, not just hardened:
|
||||
# - /run/secubox — the socket dir + api.sleeper.WAKE_LOCK_FILE
|
||||
# (read, but ReadWritePaths is directory-granular) and waker-active.json
|
||||
# - /var/lib/secubox/profiles/rollback — snapshot.SNAP_DIR, the 4R chain
|
||||
# shared with secubox-profilectl/secubox-wakectl (actuate_paths.py)
|
||||
# - /var/log/secubox — audit.AUDIT_LOG (append-only audit.log)
|
||||
# - /data/lxc — actuate.py::_lxc_autostart edits
|
||||
# <lxcpath>/<container>/config (lxc.start.auto) before lxc-stop
|
||||
# - /etc/secubox/waf — actuate.py::ROUTES_FILE
|
||||
# (haproxy-routes.json): a STOP on a routed module calls
|
||||
# _portal_remove, which rewrites this file (temp+rename in the SAME
|
||||
# directory) — omitting it here would reproduce, one layer up, the
|
||||
# exact EROFS lesson that motivated wrapping the OTHER two ctls in
|
||||
# systemd-run in the first place (secubox-profilectl 0.6.1).
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
ReadWritePaths=/run/secubox /var/lib/secubox/profiles/rollback /var/log/secubox /data/lxc /etc/secubox/waf
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
|||
15
packages/secubox-profiles/sbin/secubox-wakectl
Executable file
15
packages/secubox-profiles/sbin/secubox-wakectl
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LicenseRef-CMSD-1.0
|
||||
# Copyright (c) 2026 CyberMind — Gérald Kerma <devel@cybermind.fr>
|
||||
# Source-Disclosed License — All rights reserved except as expressly granted.
|
||||
# See LICENCE-CMSD-1.0.md for terms.
|
||||
|
||||
# SecuBox-Deb :: secubox-wakectl (ref #896) — réveille un module on-demand
|
||||
# (wake), ou (re)génère les listes de config consommées par sbxwaf/health
|
||||
# (nginx-sync, waf-sync, health-sync). Même motif que secubox-profilectl :
|
||||
# wrapper mince, toute la logique vit dans api/wake.py.
|
||||
set -euo pipefail
|
||||
readonly MODULE="profiles"
|
||||
readonly VERSION="0.8.0"
|
||||
cd /usr/lib/secubox/profiles
|
||||
exec /usr/bin/python3 -m api.wake "$@"
|
||||
|
|
@ -173,6 +173,38 @@ Détails complets : [`docs/MODULE-GUIDELINES.md`](../docs/MODULE-GUIDELINES.md)
|
|||
|
||||
---
|
||||
|
||||
## Scale-to-zero — cycle de vie des modules (ref #896)
|
||||
|
||||
`secubox-profiles` porte, en plus de l'inventaire/apply déjà décrits, une
|
||||
politique de cycle de vie par module (`lifecycle` dans son manifeste
|
||||
`/etc/secubox/modules.d/<id>.toml`) : `always-on` (jamais éteint — un
|
||||
`protected` l'est toujours, quoi qu'il déclare), `eager` (démarre au boot,
|
||||
peut se rendormir), `on-demand` (éteint par défaut, réveillé sur accès) et
|
||||
`manual` (opérateur uniquement).
|
||||
|
||||
Deux services dédiés pilotent le sommeil/réveil :
|
||||
|
||||
- **`secubox-sleeper.service`** (root, tick 30s) — endort tout module
|
||||
`eager`/`on-demand` observé idle (aucune connexion active depuis le seuil
|
||||
configuré, aucun réveil en cours) via le même actionneur `apply_plan` que
|
||||
`secubox-profilectl apply` (snapshot 4R, audit, rollback si échec). Ne dort
|
||||
jamais sur un signal indéterminé.
|
||||
- **`secubox-waker.service`** (`User=secubox`, non privilégié) — reçoit du
|
||||
trafic **sbxwaf** (le WAF Go, `packages/secubox-toolbox-ng`/`secubox-waf-ng`) :
|
||||
un vhost on-demand sans route active est proxifié vers `/_wake/<vhost>` au
|
||||
lieu d'un 421. Le waker sert un splash 503 (`templates/waking.html`) et
|
||||
déclenche le réveil via `sudo→systemd-run→secubox-wakectl` (webui→ctl,
|
||||
jamais en direct — même patron que les autres `ctl` confinés).
|
||||
|
||||
Ce mécanisme **remplace** le déclencheur nginx `@waker` envisagé initialement
|
||||
(PIVOT 2026-07-20) : `sbxwaf` est le point d'entrée du trafic public sur ce
|
||||
dépôt, c'est donc lui qui détecte l'accès à un vhost éteint, pas nginx.
|
||||
|
||||
Détails complets (table lifecycle, format manifeste, procédure pilote) :
|
||||
[`packages/secubox-profiles/README.md`](../packages/secubox-profiles/README.md#scale-to-zero--lifecycle-waker-sleeper-ref-896).
|
||||
|
||||
---
|
||||
|
||||
## Contraintes ANSSI CSPN
|
||||
|
||||
Le projet vise la certification ANSSI CSPN à horizon 2027. Contraintes respectées :
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user