Secrets Management¶
This document describes how cryptographic keys and credentials flow through the 3WE Robot Platform in development and production environments.
Key Material Overview¶
| Secret | Storage Location | Purpose | Rotation |
|---|---|---|---|
| DTLS PSK | Device NVS (security/dtls_psk) |
Encrypts control channel | Re-provision + OTA |
| OTA Public Key | Device NVS (security/ota_pubkey) |
Verifies firmware updates | Re-provision only |
| OTA Private Key | Secure offline storage | Signs firmware releases | Replace + re-provision fleet |
| Wi-Fi Password | Device NVS (wifi/password) |
Network access | Captive portal re-provision |
| Secure Boot Key | ESP32 eFuse (one-time write) | Validates bootloader | Cannot rotate (hardware fuse) |
Development Environment¶
In development, security features are relaxed for ease of iteration:
- Wi-Fi: Compile-time fallback via
CONFIG_WIFI_SSID/CONFIG_WIFI_PASSWORDin Kconfig - DTLS: Can boot without PSK (control channel unencrypted, logged as error)
- OTA: Can boot without public key (firmware updates disabled)
- NVS: Unencrypted (readable via
esptool.py read_flash) - Secure Boot: Disabled (unsigned firmware accepted)
Production Environment¶
Production builds (CONFIG_PRODUCTION_BUILD=y) enforce:
- Wi-Fi: NVS-only provisioning (Kconfig fallback disabled at compile time)
- DTLS: Required — device refuses to start control listener without valid PSK
- OTA: Required — unsigned firmware images rejected at bootloader level
- NVS: Encrypted (
CONFIG_NVS_ENCRYPTION=y) — at-rest protection for all keys - Secure Boot: Enabled (
CONFIG_SECURE_BOOT_V2_ENABLED=y) — only signed bootloader/app runs
Key Provisioning Workflow¶
Per-Device Provisioning¶
Use the provision-keys CLI tool (installed with pip install robot-payload-sdk[provision]):
# 1. Generate unique keys for a device
provision-keys generate --output keys/device_001.json
# 2. Flash keys to device NVS via UART
provision-keys flash --keys keys/device_001.json --port /dev/ttyUSB0
# 3. Batch generation for fleet
provision-keys batch --csv devices.csv --output-dir keys/
Generated Files¶
After generate, two files are created:
- device_001.json — Manifest with PSK hex, OTA public key hex, provisioning status
- device_001.key.pem — OTA signing private key (KEEP SECRET, chmod 600)
Device Inventory¶
Each manifest JSON contains:
{
"device_id": "robot-AABBCCDDEEFF",
"psk_hex": "...",
"psk_identity": "robot-AABBCCDDEEFF",
"ota_public_key_der_hex": "...",
"provisioned": true,
"provisioned_at": "2025-01-15T10:30:00Z"
}
Store manifests in a secure, access-controlled location (not in the git repository).
NVS Encryption¶
When CONFIG_NVS_ENCRYPTION=y is set:
- ESP-IDF generates an NVS encryption key on first boot (stored in a dedicated flash partition)
- All NVS read/write operations are transparently encrypted
- A flash dump cannot recover key material without the encryption key
Recovery: If the NVS encryption key is lost or corrupted, the device must be fully erased and re-provisioned. There is no recovery path.
Key Rotation¶
Rotating DTLS PSK¶
- Generate new PSK:
provision-keys generate --output keys/device_001_v2.json - Push new PSK via OTA config update (future feature) or re-flash NVS
- Update fleet inventory
- Old PSK immediately invalid after NVS write
Rotating OTA Signing Key¶
- Generate new key pair
- Build new firmware signed with both old and new keys (dual-sign transition period)
- OTA push firmware that accepts the new public key
- Push firmware that writes new public key to NVS
- Subsequent OTA images signed with new key only
- Revoke old key from signing infrastructure
Note: OTA public key rotation requires careful staged rollout. A mis-signed OTA leaves devices unable to update.
CI/CD Secrets¶
GitHub Actions¶
| Secret | Purpose | Where Used |
|---|---|---|
PYPI_TOKEN |
Publish SDK to PyPI | release.yml (or OIDC trusted publisher) |
OTA_SIGNING_KEY |
Sign release firmware | release.yml firmware-build job |
Configure via: Repository → Settings → Secrets and variables → Actions
Local Development¶
Copy .env.example to .env and fill in local values. The .env file is gitignored.
Security Best Practices¶
- Never commit keys —
.gitignoreincludes*.pem,*.key,keys/ - Principle of least privilege — CI only gets secrets it needs per job
- Audit access — Review who can access signing keys quarterly
- Backup signing keys — Store OTA private keys in at least 2 secure locations
- Monitor provisioning — Track which devices have been provisioned via inventory manifests
- Incident response — If a signing key is compromised, rotate immediately and OTA all devices