Safe Kiddo Daemon
Service to lock/unlock local user accounts on kids' laptops with countdown, notifications, optional sound, and shutdown. Provides a REST API plus a small web UI for remote control; retains the original sk.sh script as legacy/CLI fallback.
Features
- Disable/enable accounts, terminate sessions, optionally trigger shutdown.
- Desktop notifications and optional sound during countdown.
- Login-protected API with minimal web UI (PAM auth for root users, bearer token for calls).
- Systemd-managed service, virtualenv-based deploy, remote update script.
- Dry-run mode to validate flows without touching accounts.
Quick Start (Local/Target Device)
git clone <repo> /opt/sk
cd /opt/sk
./scripts/install.sh
sudo systemctl status skd.service
Then open http://localhost:8000/ and log in via PAM (default) to start quickly.
Configuration
Set in /etc/skd/env (see env.example):
SKD_AUTH_MODE:pam(default) oroidc.SKD_AUTH_SECRET: HMAC secret for bearer tokens/cookies (set a strong value).SKD_TOKEN_TTL_SECONDS: token lifetime (default 900s).SKD_AUTH_ALLOWED_USERS: optional comma list of accounts allowed to log in (used for PAM and as an allowlist for OIDC claims).SKD_AUTH_ALLOWED_GROUPS: groups whose members may log in (PAM only, defaultsudo).SKD_OIDC_*:ISSUER,CLIENT_ID,CLIENT_SECRET,REDIRECT_URI,SCOPESto point at your OIDC provider; setSKD_SESSION_COOKIE_SECURE=truefor HTTPS.- OIDC dynamic registration helper:
scripts/register_oidc_client.sh(requiresOIDC_INITIAL_ACCESS_TOKENandSKD_OIDC_ISSUER; usesSKD_OIDC_REDIRECT_URIfor the redirect). Run once during setup if your provider issues initial access tokens for client creation. SKD_ALLOWED_USERS: optional comma list to limit manageable accounts (must exist on the system).SKD_DEFAULT_COUNTDOWN,SKD_DEFAULT_SOUND,SKD_NOTIFY_TIMEOUT: behavior defaults.SKD_DRY_RUN=trueto test without real account changes or shutdown.SKD_SOUND_PLAYER/SKD_SOUND_FILE,SKD_NOTIFY_SEND_PATHif defaults differ. Notes:./scripts/install.shwill create/etc/skd/envfromenv.exampleif missing (edit afterwards) and ensure theskdservice user/group exist.
OIDC Setup
OIDC ist optional. Wenn der Provider noch nicht bereit ist, bleibe bei SKD_AUTH_MODE=pam.
- Issuer muss der externen URL des Providers entsprechen (TLS trust erforderlich).
- OIDC Client registrieren (DCR), z.B.:
export SKD_OIDC_ISSUER="https://auth.example.org"
export SKD_OIDC_REDIRECT_URI="https://<device-host>[:port]/login/oidc/callback"
export OIDC_INITIAL_ACCESS_TOKEN="<initial-access-token>"
./scripts/register_oidc_client.sh
- Danach in
/etc/skd/envsetzen:
SKD_AUTH_MODE=oidc
SKD_OIDC_ISSUER=...
SKD_OIDC_CLIENT_ID=...
SKD_OIDC_CLIENT_SECRET=...
SKD_OIDC_REDIRECT_URI=...
SKD_OIDC_SCOPES=openid profile email
SKD_SESSION_COOKIE_SECURE=true
Hinweise:
- Redirect-URI muss exakt sein (keine Wildcards).
- Bei Host/Port-Aenderung neu registrieren und neue Credentials setzen.
- Allowlist fuer OIDC:
SKD_AUTH_ALLOWED_USERSprueftpreferred_username,emailodersub.
Running
- Service: managed by systemd;
./scripts/install.shwrites the unit dynamically to/etc/systemd/system/skd.servicewith the current repo path and restarts it. - Manual run:
./scripts/run.sh(uses.venv, defaults to0.0.0.0:8000). - Login (PAM):
curl -X POST -H "Content-Type: application/json" -d '{"username":"root","password":"..."}' http://localhost:8000/login - Login (OIDC): open
http://localhost:8000/login/oidc/start→ provider → redirected back with session cookie set. - Health:
curl -H "Authorization: Bearer <token>" http://localhost:8000/health
OIDC Validation & Fallbacks
- Validierungsschritte:
docs/oidc-validation.md(State, Token-Exchange, Claims, Cookie). - Falls Discovery/JWKS nicht verfuegbar: OIDC deaktivieren und PAM nutzen.
- Falls DCR nicht verfuegbar: Client manuell im IdP anlegen und
SKD_OIDC_*setzen. - Bei Self-Signed TLS: CA im System trusten oder in Dev PAM nutzen.
API (Bearer token via /login)
GET /users→[{user, logged_in}](manageable system users; excludes root)POST /users/{name}/disablewith JSON{countdown?, sound?, message?}POST /users/{name}/enableGET /healthGET /me(returns current user + auth mode when a session/bearer token is present)
Example:
token=$(curl -s -X POST -H "Content-Type: application/json" -d '{"username":"root","password":"..."}' http://localhost:8000/login | jq -r .token)
curl -X POST -H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-d '{"countdown":90,"sound":true}' \
http://localhost:8000/users/child1/disable
Web UI
Served at /. Nutze den Button „Login via OIDC“ (setzt Session-Cookie) oder das PAM-Formular, falls OIDC deaktiviert; danach werden verfügbare System-User angezeigt und Aktionen senden Token/Cookies automatisch.
Updates
- Remote update via SSH:
ssh user@kid-laptop 'cd /opt/sk && ./scripts/update.sh'(fetch/reset toorigin/main, reinstalls deps, restarts service). - Manual:
git pull && source .venv/bin/activate && pip install -r backend/requirements.txt && sudo systemctl restart skd
Deployment (zip/SSH)
- Quick copy: create
sk_deploy.zip(already in repo root) and unzip on target under/opt/sk, then refresh venv deps and restart service. - Scripted deploy: edit
deploy_hosts.yml(host/user/port/install_dir/service user/group), then run./scripts/deploy.sh <host-name>; accepts JSON configs too. Requires SSH access andsudoon target. - After deploy on target:
sudo -u skd /opt/sk/.venv/bin/pip install -r /opt/sk/backend/requirements.txt && sudo systemctl restart skd.service
Security Hardening
- Restrict access to API/Web UI to LAN/VPN; firewall the port.
- Set a strong
SKD_AUTH_SECRET; rotate tokens by changing the secret. - Create dedicated
skduser/group; no login shell. - Configure sudoers minimally: allow
skdto runusermod -L/-U,pkill -KILL -u,shutdown now, and sound/notify binaries if needed (no full passwordless sudo). - Consider mTLS or IP allowlisting for added protection.
Legacy Script
sk.sh remains for direct SSH use. Plan to replace its logic with API-backed helpers; keep it as emergency fallback.