Skip to content

Latest commit

 

History

History
128 lines (104 loc) · 11.6 KB

File metadata and controls

128 lines (104 loc) · 11.6 KB

Security Implementation Plan

This is the security baseline for the Altiair DDIL edge mesh demo. It is written for an unclassified, authorized training environment using consenting tagged training subjects, tagged assets, and controlled training objects. Do not use this repo to process classified information. If a customer brings Controlled Unclassified Information into scope, treat that as a new authorization boundary and map the environment to NIST SP 800-171 and the applicable CMMC level before ingesting that data.

Source Baseline

Protection Goals

  1. Keep credentials, access details, tokens, Foundry URLs, private ontology RIDs, and device private keys out of git.
  2. Keep every node useful when cloud access is degraded, but never trusted only because it is reachable on a local link.
  3. Protect the mission graph from spoofed or stale sensor events.
  4. Keep raw media local by default and forward compact, signed, policy-gated evidence first.
  5. Make the LLM advisory only; deterministic policy gates decide what can be shared or surfaced.
  6. Make node loss survivable: revoke that node, preserve the local queue on remaining nodes, and keep the operator display clear about degraded state.

Threat Model

Risk Control
Lost or stolen Pi / Jetson Unique WireGuard key per node, revocation list, encrypted queue, no committed secrets, short retention, remote Foundry tokens only on gateway nodes.
Hostile or curious local-link client WireGuard overlay, API bound to wg0 or explicit host, bearer token or mTLS, firewall default deny, no broad CORS.
Sensor spoofing or stale RFID read Tag allowlist, freshness window, confidence and precision fields, multi-sensor corroboration before cue escalation.
Malicious bundle or malformed JSON Body size limits, JSON schema validation, strict content type, reject unknown policy states, fail closed on parse errors.
Prompt injection through sensor text or Foundry context Treat all retrieved/context text as untrusted data, require structured output, reject model commands that bypass policy gates.
Gateway overload or data exfiltration Queue high-water marks, rate limits, summarization before raw media, policy-gated upload, audit logs.
Dependency or build-chain compromise Lockfiles, dependency review, npm audit, minimal runtime packages, generated SBOM before customer demo.
Unauthorized operator action Role-based UI affordances, visible policy state, explicit acknowledgement, no engagement planning controls in the MVP.

Secure Coding Practices

  • Use TypeScript strict typing and explicit domain types for nodes, bundles, policy states, and gateway decisions.
  • Validate all external inputs at API boundaries. The Rust service should use schema validation for every route before data reaches business logic.
  • Fail closed for authentication, authorization, policy state, missing gateway, and unknown sensor source.
  • Keep authorization separate from presentation. The UI may show degraded state and evidence, but it cannot authorize sharing or action by itself.
  • Use allowlists for model families, sensor types, node IDs, policy states, bundle priorities, and upload destinations.
  • Limit request body size and queue depth before parsing or storing payloads.
  • Return generic errors to callers; write detailed diagnostic context only to local protected logs.
  • Do not log secrets, bearer tokens, private keys, Foundry URLs, OAuth client secrets, raw RFID identifiers, or raw media paths.
  • Add tests for blocked policy states, oversize bundles, stale peer observations, gateway failover, malformed input, and node failure.
  • Run npm run build, npm run agent:test, npm run agent:smoke, npm run smoke:mock, npm run mesh:smoke, npm run security:smoke, and npm audit --omit=dev before demos; smoke:mock is a test harness, not the final live data path.
  • Keep the Photo Booth "secure coding" ask as a shipped gate, not a slide-only claim: model-family blocking, mission policy blocking, no obvious committed secrets, protected API routes, and secure HTTP headers must pass locally before demo.

Node Hardening

Baseline for every Pi and Jetson:

  1. Patch before demo: sudo apt update && sudo apt full-upgrade -y.
  2. Use unique hostnames and unique OS users. Do not reuse passwords.
  3. Enable SSH key auth only; disable password login and root login.
  4. Install only required packages: wireguard-tools, sqlite3, jq, sensor utilities, and the node runtime.
  5. Enable a default-deny firewall. Allow SSH only from the admin machine, WireGuard UDP from the selected local link, and the Altiair API only on the WireGuard interface.
  6. Store app data under a dedicated service user with 0700 directories.
  7. Keep device private keys under 0600 permissions and never copy them back into the repo.
  8. Rotate WireGuard keys after public demos. Rotate the Altiair-LAN SSID password after public demos.

Example firewall posture, adjusted per device:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from <admin-ip> to any port 22 proto tcp
sudo ufw allow 51820/udp
sudo ufw allow in on wg0 to any port 8080 proto tcp
sudo ufw enable

Mesh And API Controls

  • No external hotspot, router, or internet path is required. Use the Pi 5 Altiair-LAN AP as the baseline untrusted underlay; loopback is the software fallback and Jetson Ethernet is the hardware fallback.
  • Physical preservation across separate nodes requires the Pi 5 AP or Ethernet fallback before failure. The system can preserve bundles already replicated to another node, but it cannot recover data that existed only on the failed node.
  • Use WireGuard as the mission overlay with per-device keys and narrow /32 AllowedIPs.
  • Bind the Altiair API to the node overlay address or an explicit host using ALTIAIR_API_HOST.
  • Set ALTIAIR_API_TOKEN for every demo. The prototype requires this token for all non-health routes when configured.
  • Set ALTIAIR_APP_ENCRYPTION_SECRET or ALTIAIR_APP_ENCRYPTION_KEY on nodes that exchange TypeScript demo/API POST traffic when app-level payload encryption is required. The app envelope uses AES-256-GCM and binds method/path/purpose metadata as authenticated data.
  • Local node API and UI responses set no-store, nosniff, no-referrer, frame denial, restrictive permissions policy, and a restrictive content security policy. Keep these defaults unless a route has a documented need to expand them.
  • Prefer mTLS or SPIFFE/SPIRE-style workload identity for a production service; bearer tokens are a demo control, not the final identity layer.
  • Keep Foundry/CASK credentials only on nodes with foundry_gateway role.
  • The Rust agent signs accepted bundle records with Ed25519. Use per-node keys and include node ID, bundle ID, created time, policy state, and content hash in the signed envelope.

Data Protection

  • Default retention is structured detections, not raw media.
  • Raw camera/audio should stay local unless policy allows a bounded thumbnail, transcript, or short clip.
  • Store RFID tag IDs as pseudonymous IDs where possible. Keep the tag-to-person or tag-to-asset mapping in Foundry or a protected local file, not in logs.
  • Use content hashes for bundle dedupe and tamper evidence.
  • TypeScript node API POST clients encrypt JSON request bodies when app-level encryption is configured. Foundry bundle-action uploads keep routing metadata clear but store the protected item in encrypted payloadJson; narrow GPS-position profile uploads remain field-level ontology writes.
  • The Rust agent encrypts queued payloads with AES-256-GCM. Demo defaults are derived locally so smoke tests can run without secrets; real deployments must set ALTIAIR_AGENT_SIGNING_KEY and ALTIAIR_AGENT_ENCRYPTION_KEY or their *_SECRET variants from local secret storage.
  • Keep policy state attached to every observation, insight, cue, and upload attempt.

Foundry / CASK Controls

  • Use a least-privilege Developer Console backend-service app.
  • Separate read scopes from writeback action scopes.
  • Keep OAuth secrets in environment variables or the platform secret store, not .env files committed to git.
  • Keep mock mode as the default for local tests when secrets are absent; final live demos should show queued sync if real Foundry credentials/actions are not loaded.
  • Write back evidence, insight drafts, acknowledgements, and node health only after policy checks pass.
  • Record upload attempts locally with bundle ID, node ID, selected gateway, policy state, and success/failure, but not secrets or raw content.

LLM Controls

  • The local model drafts explanations and verification checks only.
  • The deterministic policy gate remains authoritative for share, hold, review, and block decisions.
  • Prompt the model with compact evidence IDs and confidence fields, not large raw data dumps.
  • Require structured JSON output and reject outputs with unknown keys, action verbs outside the allowed set, or missing uncertainty.
  • Treat Foundry context, transcripts, RFID notes, operator notes, and camera labels as untrusted input.
  • Keep engagement controls, pursuit/capture instructions, and harm instructions out of the schema and UI.

Demo Acceptance Checklist

  • ALTIAIR_API_TOKEN is set on every node before demo traffic leaves loopback.
  • curl http://10.77.0.10:8080/health works without secrets and shows no sensitive values.
  • Protected routes require Authorization: Bearer <token>.
  • One Pi can fail and /mission-continuity reports degraded_one_node_failed.
  • Lost-node revocation is demonstrated by removing its WireGuard peer and marking it offline.
  • RFID/provider-style location events include freshness, precision/confidence, isCarrierGrade=false where applicable, and a policy state.
  • Foundry/CASK upload is disabled or queued unless real scopes and secrets are intentionally loaded on a gateway node.
  • No repository file contains private keys, tokens, private Foundry URLs, credentials, or access details.
  • npm run security:smoke passes after any change that touches model selection, mission policy, Foundry configuration, API routes, UI serving, or deployment docs.
  • npm run agent:smoke passes after any change that touches durable queue, signing, encryption, or Rust agent routes.