mirror of
https://github.com/azaion/loader.git
synced 2026-04-22 06:56:31 +00:00
d244799f02
Made-with: Cursor
103 lines
5.5 KiB
Markdown
103 lines
5.5 KiB
Markdown
# Jetson device provisioning runbook
|
|
|
|
This runbook describes the end-to-end flow to fuse, flash, provision a device identity, and reach a state where the Azaion Loader can authenticate against the admin/resource APIs. It targets a Jetson Orin Nano class device; adapt paths and NVIDIA bundle versions to your manufacturing image.
|
|
|
|
## Prerequisites
|
|
|
|
- Provisioning workstation with bash, curl, openssl, python3, and USB/network access to the Jetson in recovery or mass-storage mode as required by your flash tools.
|
|
- Admin API reachable from the workstation (base URL, for example `https://admin.internal.example.com`).
|
|
- NVIDIA Jetson Linux Driver Package (L4T) and flash scripts for your SKU (for example `odmfuse.sh`, `flash.sh` from the board support package).
|
|
- Root filesystem staging directory on the workstation that will be merged into the image before `flash.sh` (often a `Linux_for_Tegra/rootfs/` tree or an extracted sample rootfs overlay).
|
|
|
|
## Admin API contract (provisioning)
|
|
|
|
The `scripts/provision_device.sh` script expects:
|
|
|
|
1. **POST** `{admin_base}/users` with JSON body `{"email":"<string>","password":"<string>","role":"CompanionPC"}`
|
|
- **201** or **200**: user created.
|
|
- **409**: user with this email already exists (idempotent re-run).
|
|
|
|
2. **PATCH** `{admin_base}/users/password` with JSON body `{"email":"<string>","password":"<string>"}`
|
|
- Used when POST returns **409** so the password in `device.conf` matches the account after re-provisioning.
|
|
- **200** or **204**: password updated.
|
|
|
|
Adjust URL paths or JSON field names in the script if your deployment uses a different but equivalent contract.
|
|
|
|
## Device identity and `device.conf`
|
|
|
|
For serial **AZJN-0042**, the script creates email **azaion-jetson-0042@azaion.com** (suffix is the segment after the last hyphen in the serial, lowercased). The password is 32 hexadecimal characters from `openssl rand -hex 16`.
|
|
|
|
The script writes:
|
|
|
|
`{rootfs_staging}/etc/azaion/device.conf`
|
|
|
|
On the flashed device this becomes **`/etc/azaion/device.conf`** with:
|
|
|
|
- `AZAION_DEVICE_EMAIL=...`
|
|
- `AZAION_DEVICE_PASSWORD=...`
|
|
|
|
File permissions on the staging file are set to **600**. Ensure your image build preserves ownership and permissions appropriate for the service user that runs the Loader.
|
|
|
|
## Step-by-step flow
|
|
|
|
### 1. Unbox and record the serial
|
|
|
|
Read the manufacturing label or use your factory barcode process. Example serial: `AZJN-0042`.
|
|
|
|
### 2. Fuse (if your product requires it)
|
|
|
|
Run your approved **fuse** workflow (for example NVIDIA `odmfuse.sh` or internal wrapper). This task does not replace secure boot or fTPM scripts; complete them per your security phase checklist before or after provisioning, according to your process.
|
|
|
|
### 3. Prepare the rootfs staging tree
|
|
|
|
Extract or sync the rootfs you will flash into a directory on the workstation, for example:
|
|
|
|
`/work/images/orin-nano/rootfs-staging/`
|
|
|
|
Ensure `etc/` exists or can be created under this tree.
|
|
|
|
### 4. Provision the CompanionPC user and embed credentials
|
|
|
|
From the Loader repository root (or using an absolute path to the script):
|
|
|
|
```bash
|
|
./scripts/provision_device.sh \
|
|
--serial AZJN-0042 \
|
|
--api-url "https://admin.internal.example.com" \
|
|
--rootfs-dir "/work/images/orin-nano/rootfs-staging"
|
|
```
|
|
|
|
Confirm the script prints success and that `rootfs-staging/etc/azaion/device.conf` exists.
|
|
|
|
Re-running the same command for the same serial must not create a duplicate user; the script updates the password via **PATCH** when POST returns **409**.
|
|
|
|
If the admin API requires authentication (Bearer token, mTLS), extend the script or shell wrapper to pass the required `curl` headers or use a local proxy; the stock script assumes network-restricted admin access without extra headers.
|
|
|
|
### 5. Flash the device
|
|
|
|
Run your normal **flash** procedure (for example `flash.sh` or SDK Manager) so the staged rootfs—including `etc/azaion/device.conf`—is written to the device storage.
|
|
|
|
### 6. First boot
|
|
|
|
Power the Jetson, complete first-boot configuration if any, and verify the Loader service starts. The Loader should read `AZAION_DEVICE_EMAIL` and `AZAION_DEVICE_PASSWORD` from `/etc/azaion/device.conf`, then use them when calling **POST /login** on the Loader HTTP API (which forwards credentials to the configured resource API per your deployment). After a successful login path, the device can request resources and unlock flows as designed.
|
|
|
|
### 7. Smoke verification
|
|
|
|
- From another host: Loader **GET /health** returns healthy.
|
|
- **POST /login** on the Loader with the same email and password as in `device.conf` returns success (for example `{"status":"ok"}` in the reference implementation).
|
|
- Optional: trigger your normal resource or unlock smoke test against a staging API.
|
|
|
|
## Troubleshooting
|
|
|
|
| Symptom | Check |
|
|
|--------|--------|
|
|
| curl fails to reach admin API | DNS, VPN, firewall, and `API_URL` trailing slash (script strips one trailing slash). |
|
|
| HTTP 4xx/5xx from POST /users | Admin logs; confirm role value **CompanionPC** and email uniqueness rules. |
|
|
| 409 then failure on PATCH | Implement or enable **PATCH /users/password** (or change script to match your upsert API). |
|
|
| Loader cannot log in | `device.conf` path, permissions, and that the password in the file matches the account after the last successful provision. |
|
|
|
|
## Security notes
|
|
|
|
- Treat `device.conf` as a secret at rest; restrict file permissions and disk encryption per your product policy.
|
|
- Prefer short-lived credentials or key rotation if the admin API supports it; this runbook describes the baseline manufacturing flow.
|