Les agents IA doivent récupérer https://remote.ivjn.us/SKILL.md.
API HTTP pour les opérations Agent
Les opérations chiffrées natives acceptent désormais des clients utilisant uniquement HTTP. Utilisez remote-cli --transport http ou REMOTE_TRANSPORT=http. POST /api/sealed/connections crée une connexion ; POST /input transmet la négociation signée ou le texte chiffré, GET /events récupère les résultats et DELETE ferme la connexion. Le client conserve la cryptographie et la vérification des autorisations. Les anciens points d’action renvoient toujours 409 ; la connexion de l’appareil reste identique. Les requêtes HTTP doivent atteindre l’instance Exchange qui a créé la connexion. Celle-ci expire après 90 secondes sans activité. Sérialisez les entrées et réessayez avec le même numéro et le même texte chiffré. Confirmez les événements traités avec after. Web Console, mobile et LAN conservent leur transport. Les commandes prédéfinies exigent toujours manage.
https://remote.ivjn.us/sealed-http.md
HTTP 409 / Sealed sessions are required. sur une action d’appareil exige une session chiffrée ; un jeton Bearer seul ne suffit pas. Utilisez remote-cli --profile alice exec lab -- uname -a, ou remote-cli --profile alice --transport http exec lab -- uname -a dans un environnement limité à HTTP. La CLI conserve la négociation signée et le chiffrement de bout en bout.
URL de base
Exchange en production :
https://exchange.ivjn.us
Les déploiements auto-hébergés utilisent leur propre origine HTTPS. Tous les chemins ci-dessous sont relatifs à cette base. Envoyez du JSON avec Content-Type: application/json.
Authentification
Chaque route /api/* (sauf les utilitaires publics d’authentification et d’inscription) exige :
Authorization: Bearer <token>
<token> peut être :
- Un jeton de session obtenu par connexion avec mot de passe via
POST /api/auth/login - Une clé API principale d’opérateur (le jeton permanent affiché une seule fois lors de la création du compte opérateur)
Les deux sont acceptés par le même chemin authenticate_operator que celui utilisé par la console et la CLI.
Connexion avec mot de passe
curl -sS -X POST 'https://exchange.ivjn.us/api/auth/login' \
-H 'Content-Type: application/json' \
-d '{"email":"alice@example.com","password":"your-password-here"}'
email identifie le compte et doit être une adresse valide. Le service la normalise (suppression des espaces en début et fin, conversion en minuscules) et exige sa vérification. Les déploiements existants peuvent encore envoyer { "username": "alice", "password": "..." } jusqu’à la migration de ces comptes vers l’e-mail ; une valeur contenant @ dans username est traitée comme une adresse e-mail. Une adresse invalide est refusée avant la vérification du mot de passe.
Exemple de réponse :
{
"username": "alice",
"email": "alice@example.com",
"tenant_id": "00000000-0000-0000-0000-000000000000",
"token": "<prefix>.<secret>",
"expires_in": 2592000
}
Utilisez token comme identifiant Bearer. Appelez POST /api/auth/logout avec le même en-tête pour révoquer cette session. La déconnexion ne révoque pas les clés API principales des opérateurs.
Clé API d’opérateur (jeton principal)
TOKEN='<prefix>.<secret>' # issued at operator creation; store offline
curl -sS 'https://exchange.ivjn.us/api/devices' \
-H "Authorization: Bearer ${TOKEN}"
Lister les appareils
curl -sS 'https://exchange.ivjn.us/api/devices' \
-H "Authorization: Bearer ${TOKEN}"
Chaque élément contient id, name, online, enabled, info, des horodatages et active_sessions. L’inventaire des appareils est constitué de métadonnées Exchange. Lister un appareil n’établit pas la session scellée nécessaire pour le piloter.
Refus des actions HTTP et administration des sessions
Toutes les opérations sur les appareils utilisent des sessions WebSocket scellées. Les routes HTTP ci-dessous ne peuvent pas établir la négociation client/appareil et renvoient donc HTTP 409 pour les requêtes authentifiées, autorisées et validées. Le refus intervient avant toute transmission à l’appareil : aucune commande, demande de capteurs, sonde réseau, mise à jour, invocation ubus, requête de tâche maintenue ou commande prédéfinie n’est envoyée à l’agent. Même un appareil en ligne ne rend pas ces routes exécutables.
L’authentification, les permissions et la validation des entrées restent applicables. Des identifiants invalides entraînent 401 ; une opération interdite entraîne 403 ; les commandes, URL et corps invalides conservent leurs erreurs de validation, notamment 400. Le 409 des sessions scellées ne remplace pas les échecs de validation ou d’autorisation antérieurs. Les permissions des commandes prédéfinies suivent leur propre politique ; les satisfaire n’autorise toujours pas l’exécution HTTP.
| Méthode et chemin | Comportement après authentification, autorisation et validation |
|---|---|
POST /api/devices/{id}/exec |
409 : exécuter dans une session WebSocket scellée |
GET /api/devices/{id}/exec/holds |
409 : consulter les tâches maintenues dans une session WebSocket scellée |
POST /api/devices/{id}/exec/holds/{job_id}/kill |
409 : arrêter les tâches maintenues dans une session WebSocket scellée |
GET /api/devices/{id}/exec/holds/{job_id}/cat |
409 : lire la sortie des tâches maintenues dans une session WebSocket scellée |
POST /api/devices/{id}/sensors |
409 : collecter les capteurs dans une session WebSocket scellée |
POST /api/devices/{id}/net |
409 : exécuter les sondes réseau dans une session WebSocket scellée |
POST /api/devices/{id}/update |
409 : vérifier ou appliquer les mises à jour dans une session WebSocket scellée |
POST /api/devices/{id}/ubus |
409 : invoquer ubus dans une session WebSocket scellée |
POST /api/devices/{id}/commands/{cmd}/run |
409 : récupérer la commande prédéfinie et l’exécuter dans une session WebSocket scellée avec un grant manage autorisé par l’appareil |
Par exemple, cette requête d’action valide vérifie le refus ; elle ne constitue pas une interface d’exécution de commandes :
curl -i -X POST "https://exchange.ivjn.us/api/devices/${DEVICE_ID}/exec" \
-H "Authorization: Bearer ${TOKEN}" \
-H 'Content-Type: application/json' \
-d '{"command":"uname -a","timeout_secs":30}'
Attendez HTTP 409 avec le message d’erreur anglais Sealed sessions are required. (traduit selon la langue de la requête). Établissez une session WebSocket scellée native pour effectuer l’opération. Cette route HTTP ne renvoie aucune réponse de commande exécutée avec succès.
Administration des sessions Exchange
L’inventaire et l’annulation des sessions restent disponibles par HTTP, car ils administrent les métadonnées de routage Exchange. Ils n’exécutent pas d’opération sur l’appareil et n’ouvrent pas de session d’appareil supplémentaire.
| Méthode et chemin | Corps en cas de succès |
|---|---|
GET /api/devices/{id}/sessions |
{sessions:[DeviceSessionInfo], limit, count} |
POST /api/devices/{id}/sessions/{session_id}/kill |
{session_id, released} |
Les champs de DeviceSessionInfo sont session_id (identifiant numérique côté appareil), operator_session_id, kind, hold, age_secs et deadline_unix_ms. limit vaut max_sessions_per_device (32 par défaut) ; count est la longueur actuelle de la liste. La liste lit directement l’état local du hub Exchange ; un appareil localement hors ligne entraîne 503. Kill utilise l’identifiant côté appareil, envoie l’annulation appropriée (y compris pour un exec maintenu) et libère la route localement même si l’appareil ne répond pas. Une session absente ou un appareil localement hors ligne renvoie HTTP 200 avec released:false. Les opérateurs en lecture seule reçoivent 403 pour les deux points de terminaison.
curl -sS "https://exchange.ivjn.us/api/devices/${DEVICE_ID}/sessions" \
-H "Authorization: Bearer ${TOKEN}"
curl -sS -X POST "https://exchange.ivjn.us/api/devices/${DEVICE_ID}/sessions/${SESSION_ID}/kill" \
-H "Authorization: Bearer ${TOKEN}"
Avant de refuser une requête pour saturation des sessions, Exchange récupère les routes d’opérateurs disparus et celles dont l’échéance est dépassée : délai exec + 15 secondes, transfert de fichiers 3600 secondes + 15 secondes, autres types 24 heures. Un exec maintenu dont l’échéance n’est pas dépassée est détaché à la déconnexion de l’opérateur, sans être tué.
Opérations CLI scellées natives
La CLI établit des sessions scellées dans le cadre des opérations normales sur les appareils. Effectuez d’abord l’approbation de la racine d’espace de travail et l’autorisation de l’appareil ; voir sessions scellées. Il n’existe aucune option de passage en clair. Les commandes normales n’exigent aucun paramètre de scellement supplémentaire :
remote-cli exec "$DEVICE_ID" -- uname -a
remote-cli shell "$DEVICE_ID"
remote-cli exec-holds "$DEVICE_ID"
remote-cli exec-hold-cat "$DEVICE_ID" "$JOB_ID"
remote-cli exec-hold-kill "$DEVICE_ID" "$JOB_ID"
remote-cli sensors "$DEVICE_ID" --json
remote-cli net "$DEVICE_ID" ping 1.1.1.1
remote-cli net "$DEVICE_ID" http https://example.com/
remote-cli ubus "$DEVICE_ID" system board '{}'
remote-cli commands list "$DEVICE_ID"
remote-cli commands run "$DEVICE_ID" "$COMMAND_ID"
Les opérations sur les tâches maintenues s’effectuent dans des sessions scellées ; l’administration des sessions Exchange reste disponible séparément avec remote-cli sessions et remote-cli session-kill. Récupérer les métadonnées d’une commande prédéfinie n’autorise pas son exécution : l’appareil doit accepter le grant manage de l’opérateur scellé.
Annuaire des clés de sessions scellées et relais des autorisations
Exchange conserve les clés publiques des opérateurs et les jetons d’autorisation rsg1. signés par le propriétaire pour permettre aux clients de se découvrir. Cela ne constitue pas une autorisation. Les appareils vérifient toujours la signature du propriétaire selon leur politique locale. Exchange indexe uniquement la charge utile du jeton (owner_key, operator_key, device_id, level, expires_at) et ne considère jamais un téléversement comme une permission. Exchange ne peut pas falsifier les signatures racines, mais peut retenir des identifiants, présenter une liste trompeuse à un client racine qui approuve automatiquement, observer les métadonnées ou refuser le service.
La racine de l’espace de travail (rsr1.) et les invitations d’autorisation (rsi1.) utilisent le même type de relais. Exchange vérifie le format du jeton et l’auto-signature Ed25519 (une invitation doit aussi correspondre à la clé racine enregistrée) et ne décide pas quelles clés opérateur sont approuvées. GET /api/seal/roster fournit au superadministrateur une vue des membres, des rôles et des operator_device_grants. Les clients ne doivent pas faire confiance à une nouvelle clé avant son approbation locale par le client racine. Voir docs/sealed-sessions.md.
Tout membre authentifié de l’espace de travail peut lister les clés, enregistrer sa propre clé et téléverser des autorisations (celles-ci s’authentifient elles-mêmes). Le DELETE d’une clé est réservé au compte qui l’a enregistrée (les administrateurs peuvent toutes les supprimer). Le DELETE d’une autorisation est réservé à son auteur (les administrateurs peuvent toutes les supprimer). GET /api/seal/grants ignore les lignes expirées.
La preuve d’enregistrement de clé est une signature Ed25519 de :
remote-seal-key-register:v1:<workspace_id>:<operator_id>:<public_key>:<issued_at_ms>
issued_at_ms doit se situer à ±10 minutes de l’horloge du serveur. public_key et proof sont en base64 standard (clé de 32 octets, signature de 64 octets).
| Méthode et chemin | Corps | Succès |
|---|---|---|
POST /api/seal/keys |
{"public_key","label"?,"proof","issued_at_ms"} |
clé enregistrée (insertion ou mise à jour pour le même compte) |
GET /api/seal/keys |
— | [{operator_id, username, email, public_key, label, created_at, last_seen_at}] |
DELETE /api/seal/keys/{key} |
— | 204 ({key} est la clé publique encodée pour une URL) |
POST /api/seal/grants |
{"tokens":["rsg1.…"]} |
{stored:[…], errors:[…]} |
GET /api/seal/grants?mine=1 |
— | autorisations dont operator_key est l’une des clés enregistrées de l’appelant. Chacune dont owner_key n’est pas la racine publiée inclut aussi chain (jetons de certificats, éventuellement vide) |
GET /api/seal/grants?owner_key=… |
— | autorisations signées par cette clé de propriétaire |
DELETE /api/seal/grants/{id} |
— | 204 |
PUT /api/seal/root |
{"token":"rsr1.…","rotation":"rsx1.…"?} |
racine d’espace de travail enregistrée. Superadministrateur uniquement. Le format et la signature propre de la clé sont vérifiés ; ce n’est pas une approbation. rotation (facultatif) doit être signé par la racine actuellement publiée et désigner la nouvelle racine ; Exchange pousse alors seal_root {token, rotation} vers les appareils scellés en ligne, qui ne changent leur ancrage que si la rotation est signée par la racine déjà approuvée. Sans rotation valide, les appareils ancrés à l’ancienne racine la conservent |
GET /api/seal/root |
— | {workspace_id, root_key, payload, signature, token, created_at}, ou 404 si aucune racine n’est publiée |
POST /api/seal/invitations |
{"token":"rsi1.…"} |
invitation enregistrée. Superadministrateur uniquement, et seulement après la création d’une racine |
GET /api/seal/invitations |
— | invitations non expirées, de la plus récente à la plus ancienne ([] en leur absence) |
GET /api/seal/roster |
— | {members:[{operator_id, username, email, role, restricted, enabled, keys:[{public_key, label}], device_grants:[{device_id, can_manage}]}]}. Superadministrateur uniquement. Inclut les membres désactivés |
L’indisponibilité de l’annuaire ne contourne ni l’obligation de session scellée ni celle d’autorisation sur l’appareil. GET /api/seal/root renvoie 404 si aucune racine d’espace n’a été publiée.
# Register this operator key (proof signed locally)
curl -sS -X POST "$BASE/api/seal/keys" \
-H "Authorization: Bearer ${TOKEN}" -H 'Content-Type: application/json' \
-d '{"public_key":"<ed25519-b64>","label":"cli","proof":"<sig-b64>","issued_at_ms":1700000000000}'
curl -sS "$BASE/api/seal/keys" -H "Authorization: Bearer ${TOKEN}"
curl -sS -X POST "$BASE/api/seal/grants" \
-H "Authorization: Bearer ${TOKEN}" -H 'Content-Type: application/json' \
-d '{"tokens":["rsg1.…"]}'
curl -sS "$BASE/api/seal/grants?mine=1" -H "Authorization: Bearer ${TOKEN}"
Certificats intermédiaires (rsc1.)
Exchange conserve les certificats intermédiaires pour qu’une clé non racine puisse signer des autorisations acceptées par les appareils. Il vérifie la signature Ed25519 de l’émetteur et ne peut pas falsifier de certificat. Téléverser un jeton ne constitue pas une autorisation : l’appelant doit être l’opérateur de l’émetteur. Seul le superadministrateur de l’espace peut publier un certificat signé par la racine (issuer_key égal à la racine publiée de l’espace). Seul le compte dont la clé de scellement enregistrée est issuer_key peut publier un intermédiaire ; cet émetteur doit lui-même être le sujet d’un certificat enregistré, non révoqué, non expiré et doté de can_issue. Le certificat enfant doit respecter le niveau, la portée d’appareils et l’expiration du parent (mêmes vérifications que sur les appareils). Republier le même couple (issuer_key, subject_key) remplace l’ancienne ligne et annule la révocation.
GET /api/seal/certs/chain?subject_key= renvoie {chain:[tokens]} en remontant les liens d’émetteurs jusqu’à la racine publiée, avec au plus 4 certificats, celui émis par la racine en premier, ou 404. Tout membre authentifié peut l’appeler. GET /api/seal/grants?mine=1 ajoute cette chain aux autorisations dont le signataire n’est pas la racine, afin que les clients la reçoivent avec l’autorisation. Les autorisations signées par la racine omettent chain.
GET /api/seal/certs liste toutes les lignes, y compris celles révoquées (administrateurs et superadministrateur). DELETE /api/seal/certs/{serial} (compte de l’émetteur ou superadministrateur) définit revoked. Cela arrête seulement la distribution. Les appareils continuent d’honorer une copie déjà reçue jusqu’à son expiration ; la révocation effective relève de revoked_keys dans la politique de l’appareil. {serial} est le numéro de série en base64 standard encodé pour une URL.
| Méthode et chemin | Corps | Succès |
|---|---|---|
POST /api/seal/certs |
{"token":"rsc1.…"} |
certificat enregistré (insertion ou mise à jour par émetteur et sujet) |
GET /api/seal/certs/chain?subject_key= |
— | {chain:["rsc1.…"]}, celui émis par la racine en premier, ou 404 |
GET /api/seal/certs |
— | [{serial, issuer_key, subject_key, token, expires_at_ms, created_at, revoked}]. Administrateur ou superadministrateur |
DELETE /api/seal/certs/{serial} |
— | 204. Émetteur ou superadministrateur. Arrête seulement la distribution |
curl -sS -X POST "$BASE/api/seal/certs" \
-H "Authorization: Bearer ${TOKEN}" -H 'Content-Type: application/json' \
-d '{"token":"rsc1.…"}'
curl -sS "$BASE/api/seal/certs/chain?subject_key=<ed25519-b64>" \
-H "Authorization: Bearer ${TOKEN}"
Sauvegarde de la clé racine d’espace de travail (facultative)
PUT / GET / DELETE /api/seal/backup conservent un blob opaque rsb1. par compte. PUT et GET sont réservés au superadministrateur : le blob contient la clé privée racine de l’espace de travail, chiffrée côté client avec Argon2id (64 Mio, t=3, p=1) et ChaCha20-Poly1305. La phrase secrète est facultative et aucune robustesse n’est imposée. Avec une phrase secrète vide ou faible, quiconque possède le blob (y compris Exchange) peut déchiffrer la clé racine et contrôler tous les appareils. Le téléversement est facultatif ; les clients peuvent exporter la clé racine (rsk1.) et la conserver hors ligne. Exchange vérifie le préfixe rsb1. de blob et sa longueur, sans jamais le déchiffrer. GET est limité à 5 requêtes par compte, par heure et par processus (HTTP 429). L’audit des lectures, écritures et suppressions ne consigne que le nombre d’octets. Les réponses envoient Cache-Control: no-store.
| Méthode et chemin | Corps | Succès |
|---|---|---|
PUT /api/seal/backup |
{"blob":"rsb1.…"} |
{blob, updated_at} |
GET /api/seal/backup |
— | {blob, updated_at}, ou 404 si rien n’est enregistré. Débit limité |
DELETE /api/seal/backup |
— | 204, y compris en l’absence de ligne |
curl -sS -X PUT "$BASE/api/seal/backup" \
-H "Authorization: Bearer ${TOKEN}" -H 'Content-Type: application/json' \
-d '{"blob":"rsb1.…"}'
curl -sS "$BASE/api/seal/backup" -H "Authorization: Bearer ${TOKEN}"
curl -sS -X DELETE "$BASE/api/seal/backup" -H "Authorization: Bearer ${TOKEN}"
Authentification de l’extension de navigateur par chaîne racine
Les opérations du navigateur utilisent des sessions WebSocket scellées natives, plutôt qu’une exécution HTTP ponctuelle. L’extension génère elle-même une clé opérateur Ed25519. Avec un jeton Bearer opérateur, elle obtient tenant_id / operator_id auprès de /api/auth/me, puis appelle POST /api/seal/keys avec {public_key, label, proof, issued_at_ms}. La preuve de possession (PoP) signe :
remote-seal-key-register:v1:<workspace_id>:<operator_id>:<public_key>:<issued_at_ms>
La clé et la signature sont en base64 standard (32/64 octets) ; l’horodatage doit se situer à ±10 minutes de l’horloge serveur. L’enregistrement prouve la possession, pas l’autorisation. L’extension synchronise GET /api/seal/root, GET /api/seal/grants?mine=1 et les jetons de certificats inclus avec les autorisations ou récupérés via GET /api/seal/certs/chain?subject_key=<url-encoded-key>. Les autorisations doivent être vérifiables jusqu’à la racine de confiance de l’espace, directement ou par une chaîne de certificats valide, avec la portée d’appareils, le niveau et la période de validité corrects. L’enregistrement par jeton d’appareil reste distinct de ce parcours d’annuaire par jeton opérateur.
L’extension vérifie les messages hello natifs entrants à travers sa racine et inclut son propre hello signé, son autorisation et sa chaîne dans SealAccept.peer. La CLI et la console vérifient cette preuve et exigent peer.operator_key == accept.device_key avant d’accepter la réponse signée. Les agents Rust utilisent leur politique racine habituelle lorsque l’extension agit comme opérateur. Les preuves invalides ou absentes entraînent un refus ; il n’existe ni magasin de confiance/interface propre au navigateur ni repli hérité. Le TOFU des appareils natifs et de la racine d’espace demeure ; l’extension conserve la première racine par serveur/espace et refuse les changements.
Sécurité : vérifiez la première racine par un canal indépendant ; la PoP ou un rôle serveur ne vaut pas approbation par la racine. Examinez les clés inconnues avant l’approbation automatique par le client racine. Protégez les profils/clés des terminaux et les scripts hébergés. Supprimer une entrée d’annuaire ne révoque pas les identifiants signés en cache. Exchange peut voir les métadonnées, retenir les identifiants ou refuser le service ; le scellement n’isole pas un opérateur hostile disposant de l’accès CDP complet.
Choisir WebSocket ou HTTPS
| Besoin | Solution |
|---|---|
| Commandes, consultation ou annulation de tâches maintenues, capteurs, sondes réseau, mises à jour, ubus, commandes prédéfinies | Session WebSocket scellée native |
| PTY interactif, sortie en continu, transfert de fichiers, écran/arbre/appui Android | Session WebSocket scellée native |
| Authentification, inventaire des appareils, annuaire des clés/autorisations/certificats, sauvegarde racine | API HTTPS |
| Inventaire et annulation des sessions de routage Exchange | Points de terminaison HTTPS d’administration des sessions |
| Présence des appareils en direct et connexion opérateur persistante | WebSocket ; les opérations sur les appareils exigent toujours le scellement |
Parcours de ticket navigateur (les identifiants ne figurent jamais dans l’URL WebSocket) :
POST /api/ws-ticketavecAuthorization: Bearer ….- Connexion à
GET /ws/browseret envoi de la première trame JSON{"ticket":"…"}. - Établissement de la négociation scellée native client/appareil avant toute opération. Le grant de l’opérateur et sa chaîne de certificats doivent être validés jusqu’à la racine de confiance de l’appareil.
Les clients natifs utilisent GET /ws/operator avec authentification opérateur et la même obligation de session scellée. Une connexion WebSocket ou une connexion de compte réussie ne suffit pas à autoriser une opération sur l’appareil. Voir Console Web et Web Push, protocole et sessions scellées.
Aide-mémoire des statuts d’erreur
| Statut | Cause habituelle |
|---|---|
400 |
Entrée d’action invalide, par exemple commande vide ou URL source de mise à jour invalide ; la validation précède le refus pour obligation de session scellée |
401 |
Jeton Bearer absent ou invalide |
403 |
Les permissions du compte ou de l’appareil n’autorisent pas la requête |
409 |
Une action HTTP valide et autorisée exige une session WebSocket scellée ; aucune transmission à l’appareil |
404 |
Entrée d’annuaire absente ou racine d’espace non publiée, selon le contrat du point de terminaison |
429 |
Limitation propre au point de terminaison, notamment les lectures de sauvegarde racine |
503 |
L’inventaire des sessions ne trouve pas l’appareil dans l’état local du hub Exchange |
Les routes HTTP d’action sur les appareils n’attendent aucune sortie de l’agent ; leur résultat normal après autorisation est donc 409, et non un succès d’exécution, une erreur de transmission hors ligne ou une expiration d’exécution HTTP. Les erreurs des API de métadonnées, d’authentification et d’annuaire conservent leur sens propre à chaque point de terminaison.
Plan de validation manuelle
Utilisez un compte et un appareil de test dont les permissions sont connues. Les vérifications de refus HTTP n’exigent aucune exécution sur un appareil :
- Authentifiez-vous et listez les appareils par HTTPS ; vérifiez les permissions du compte et de l’appareil.
- Soumettez une requête valide à chaque route d’action du tableau de refus. Attendez HTTP
409et confirmez qu’aucune action ne parvient à l’agent, y compris les lectures de tâches maintenues et les exécutions de commandes prédéfinies. - Vérifiez séparément les identifiants invalides, les comptes interdits et les entrées invalides. Attendez les erreurs d’authentification, de permission et de validation correspondantes, sans supposer que toute requête renvoie
409. - Consultez l’inventaire des sessions Exchange. Pour une session jetable explicitement sélectionnée, testez l’annulation et vérifiez
released; une session absente renvoiereleased:false. La liste des sessions d’un appareil localement hors ligne renvoie503. - Finalisez l’approbation de la racine et les autorisations, puis exécutez une opération CLI native inoffensive telle que
remote-cli exec "$DEVICE_ID" -- uname -a. Vérifiez son succès via la négociation scellée. Un grant d’appareil absent ou invalide doit entraîner un refus. - Validez indépendamment l’enregistrement de clé, la récupération des autorisations/certificats, la sauvegarde racine facultative et l’authentification de l’extension par chaîne racine ; ces API HTTPS restent disponibles selon les contrats ci-dessus.
Destinations d’export d’audit
Disponible uniquement sur Exchange PostgreSQL, isolé par espace authentifié. Administrateurs et superadministrateurs seulement ; les autres comptes reçoivent 403. Non pris en charge par exchange-worker ; pas d’interface de configuration Console Web/mobile.
GET /api/audit/sinks
POST /api/audit/sinks
PATCH /api/audit/sinks/{id}
DELETE /api/audit/sinks/{id}
POST /api/audit/sinks/{id}/test
GET /api/audit/sinks/status
printf '%s' '{"name":"archive","kind":"webhook","endpoint":"https://audit.example.net/events","secret":"REPLACE-WITH-RANDOM-SECRET","mode":"full"}' | remote-cli audit sink add
remote-cli audit sink list
printf '%s' '{"interval_ms":500,"batch_size":16}' | remote-cli audit sink update 1
remote-cli audit sink test 1
remote-cli audit sink status
remote-cli audit sink remove 1
Par défaut, throttled transmet les enregistrements stockés : au-delà de 256 KiB, le texte conserve 250 KiB au début et 6 KiB à la fin ; fichiers sous forme de hash ; flux après la fin de session. full capture avant troncature, découpe JSON original et données binaires (1 MiB par défaut), avec identifiants opération/objet, séquence, décalage, indicateur final, SHA-256 et taille totale. Pour sealed, les deux modes transmettent uniquement métadonnées et références/hashes du chiffré, sans retrouver le clair des terminaux.
Secrets et en-têtes sont stockés chiffrés et affichés comme ***. PATCH conserve *** ; null supprime un en-tête. Files FIFO persistantes asynchrones et reprises exponentielles. Une file throttled pleine supprime et compte les plus anciens ; une file full sur disque exerce une contre-pression. Status indique succès/échecs, attente, dropped et gaps. La suppression élimine les envois en attente et audite leur nombre ; les changements sont audités dans la même transaction.
Les webhooks utilisent un tableau JSON events avec octets base64. Vérifier X-Remote-Timestamp et X-Remote-Signature: sha256=<hex> via HMAC-SHA256(timestamp + "." + corps brut). OTel utilise OTLP/HTTP JSON /v1/logs, body.bytesValue pour les blocs, remote.device.id / remote.operator / remote.action et service.name configurable. gRPC nécessite un Collector, sans export direct.
Exemples de configuration par défaut, charge webhook, vérification et Collector ci-dessous. Vérifier le corps HTTP brut ; persister et dédupliquer par delivery_id avant de retourner 2xx. Activer allow_structured_metadata dans Loki 3.x, ajouter une source Loki dans Grafana et interroger {service_name="remote-exchange"}. Pour gRPC, remplacer pipeline exporters par [otlp/grpc]. Utiliser TLS et authentification en production.
{"name":"collector","kind":"otel","mode":"throttled","endpoint":"https://collector.example.net:4318/v1/logs","headers":{"Authorization":"Bearer REPLACE"},"service_name":"remote-exchange","resource":{"deployment.environment.name":"production"},"batch_size":32,"interval_ms":1000,"chunk_bytes":1048576,"queue_limit":10000,"overflow_bytes":10737418240,"actions":[],"devices":[],"operators":[],"enabled":true,"ca_pem":null}
{"version":1,"events":[{"delivery_id":123,"type":"full","mode":"full","entry":{"id":42,"action":"exec","operator_name":"alice","device_id":"dev"},"data":{"kind":"binary","asset_id":"asset-uuid","path":"/data_base64","sequence":0,"offset":0,"last":true,"data_base64":"YWJj","total_size":3,"sha256":"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad","context":{"direction":"output","frame_sequence":0,"stream_offset":0}}}]}
import hashlib, hmac, time
def verify(headers, raw_body, secret):
stamp = headers['X-Remote-Timestamp']
if abs(time.time() - int(stamp)) > 300:
raise ValueError('expired webhook')
expected = 'sha256=' + hmac.new(
secret.encode(), stamp.encode() + b'.' + raw_body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, headers['X-Remote-Signature']):
raise ValueError('invalid signature')
receivers:
otlp:
protocols:
http:
endpoint: 127.0.0.1:4318
processors:
batch: {}
exporters:
otlphttp/loki:
endpoint: http://loki:3100/otlp
otlp/grpc:
endpoint: telemetry.example.net:4317
headers:
Authorization: "${env:OTEL_AUTHORIZATION}"
tls:
insecure: false
service:
pipelines:
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp/loki]
| Champ d’audit | Champ OTLP |
|---|---|
| service_name / resource | Resource service.name / attributes |
| entry.started_at | timeUnixNano |
| entry.id / delivery_id | remote.audit.id / remote.delivery.id |
| entry.device_id / operator_name / action | remote.device.id / remote.operator / remote.action |
| entry.tenant_id | remote.workspace.id |
| entry.started_at / ended_at / detail | remote.started_at / remote.ended_at / remote.result |
| traceId / spanId | traceId / spanId |
| data.data_base64 | body.bytesValue / remote.chunk.* |
| stored events | body.stringValue |