remote.เอกสารหน้าหลัก

เจ้าหน้าที่ AI ควรดึงข้อมูล https://remote.ivjn.us/SKILL.md.

HTTP API สำหรับการดำเนินการ Agent

ขณะนี้การดำเนินการที่ปิดผนึกแบบเนทีฟรองรับผู้เรียก HTTP เท่านั้น ใช้ remote-cli --transport http หรือ REMOTE_TRANSPORT=http POST /api/sealed/connections สร้างกล่องจดหมาย POST /input ส่งการจับมือหรือไซเฟอร์เท็กซ์ที่ลงนามแล้ว ผลการสำรวจความคิดเห็น GET /events และ DELETE ปิดการเชื่อมต่อ ลูกค้ายังคงรักษาการเข้ารหัสแบบ end-to-end และการอนุญาตอุปกรณ์ที่มีอยู่ จุดสิ้นสุดการดำเนินการของอุปกรณ์เดิมยังคงส่งคืน 409 การเชื่อมต่ออุปกรณ์ยังคงไม่เปลี่ยนแปลง กล่องจดหมาย HTTP ต้องการความเกี่ยวข้องกับการสร้างอินสแตนซ์ Exchange และหมดอายุหลังจาก 90 วินาทีโดยไม่มีกิจกรรม ทำให้อินพุตเป็นอนุกรม ลองเฉพาะลำดับและข้อความไซเฟอร์เท็กซ์เดียวกันอีกครั้ง และรับทราบเหตุการณ์ที่ประมวลผลด้วย after เว็บ Console, อุปกรณ์พกพา และ LAN ยังคงรักษาการขนส่งที่มีอยู่ การดำเนินการที่กำหนดไว้ล่วงหน้ายังคงต้องใช้ manage

https://remote.ivjn.us/sealed-http.md

HTTP 409 / Sealed sessions are required. จากปลายทางการทำงานของอุปกรณ์หมายความว่าต้องใช้เซสชันที่ปิดผนึก โทเค็น Bearer เพียงอย่างเดียวไม่สามารถสั่งงานอุปกรณ์ได้ ใช้ remote-cli --profile alice exec lab -- uname -a หรือ remote-cli --profile alice --transport http exec lab -- uname -a ในสภาพแวดล้อมที่ใช้ได้เฉพาะ HTTP โดย CLI ยังคงดำเนินการจับมือที่ลงนามและการเข้ารหัสจากต้นทางถึงปลายทาง

URL ฐาน

การผลิต Exchange:

https://exchange.ivjn.us

การปรับใช้ที่โฮสต์ด้วยตนเองใช้ต้นทาง HTTPS ของคุณเอง เส้นทางทั้งหมดด้านล่างสัมพันธ์กับฐานนั้น ส่ง JSON ด้วย Content-Type: application/json

การรับรองความถูกต้อง

ทุกเส้นทาง /api/* (ยกเว้นผู้ตรวจสอบสิทธิ์สาธารณะ/ผู้ช่วยลงทะเบียน) ต้องใช้:

Authorization: Bearer <token>

<token> อาจเป็นอย่างใดอย่างหนึ่ง:

  1. โทเค็นเซสชันการเข้าสู่ระบบด้วยรหัสผ่าน จาก POST /api/auth/login
  2. Operator primary API key (โทเค็นที่มีอายุการใช้งานยาวนานจะแสดงครั้งเดียวเมื่อมีการสร้างบัญชีตัวดำเนินการ)

ทั้งสองได้รับการยอมรับโดยพาธ authenticate_operator เดียวกับที่ใช้โดยคอนโซลและ CLI

รหัสผ่านเข้าสู่ระบบ

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 คือข้อมูลประจำตัวของบัญชีและต้องเป็นที่อยู่ที่ถูกต้อง บริการทำให้เป็นมาตรฐาน (ตัดแต่ง ตัวพิมพ์เล็ก) และต้องมีการตรวจสอบที่อยู่ การใช้งานที่มีอยู่ยังคงสามารถส่ง { "username": "alice", "password": "..." } ได้จนกว่าบัญชีเหล่านั้นจะย้ายไปที่อีเมล ค่าที่มี @ ใน username จะถือเป็นอีเมล ที่อยู่ที่ไม่ถูกต้องจะถูกปฏิเสธก่อนการตรวจสอบรหัสผ่าน

ตัวอย่างการตอบกลับ:

{
  "username": "alice",
  "email": "alice@example.com",
  "tenant_id": "00000000-0000-0000-0000-000000000000",
  "token": "<prefix>.<secret>",
  "expires_in": 2592000
}

ใช้ token เป็นหนังสือรับรองผู้ถือ โทร POST /api/auth/logout ด้วยส่วนหัวเดียวกันเพื่อเพิกถอนเซสชันนั้น คีย์ API ตัวดำเนินการหลักจะไม่ถูกเพิกถอนโดยการออกจากระบบ

คีย์ Operator API (โทเค็นหลัก)

TOKEN='<prefix>.<secret>'   # issued at operator creation; store offline
curl -sS 'https://exchange.ivjn.us/api/devices' \
  -H "Authorization: Bearer ${TOKEN}"

แสดงรายการอุปกรณ์

curl -sS 'https://exchange.ivjn.us/api/devices' \
  -H "Authorization: Bearer ${TOKEN}"

แต่ละรายการประกอบด้วย id, name, online, enabled, info, การประทับเวลา และ active_sessions สินค้าคงคลังของอุปกรณ์คือข้อมูลเมตา Exchange การลงรายการอุปกรณ์ไม่ได้สร้างเซสชันที่ปิดผนึกซึ่งจำเป็นต่อการใช้งาน

การปฏิเสธ HTTP การกระทำของอุปกรณ์และการดูแลเซสชัน

การทำงานของอุปกรณ์ทั้งหมดใช้เซสชัน WebSocket ที่ปิดผนึก เส้นทาง HTTP ด้านล่างไม่สามารถสร้างการจับมือไคลเอ็นต์/อุปกรณ์ได้ ดังนั้นจึงส่งคืน HTTP 409 สำหรับคำขอที่ได้รับการตรวจสอบสิทธิ์และได้รับอนุญาตซึ่งผ่านการตรวจสอบความถูกต้องของคำขอ การปฏิเสธเกิดขึ้นก่อนการจัดส่งอุปกรณ์: ไม่มีการส่งคำสั่ง, คำขอเซ็นเซอร์, โพรบเครือข่าย, การอัปเดต, การเรียก ubus, คำของานที่ค้าง หรือคำสั่งที่ปักหมุดไว้จะถูกส่งไปยัง agent อุปกรณ์ออนไลน์ไม่ได้ทำให้เส้นทางเหล่านี้สามารถดำเนินการได้

การตรวจสอบสิทธิ์ การอนุญาต และการตรวจสอบอินพุตยังคงมีผลอยู่ ข้อมูลรับรองไม่ถูกต้องส่งคืน 401; การดำเนินการที่ต้องห้ามส่งคืน 403; คำสั่ง URL หรือเนื้อหาคำขอที่ไม่ถูกต้องยังคงมีข้อผิดพลาดในการตรวจสอบ รวมถึง 400 409 เซสชันที่ปิดผนึกไม่ได้แทนที่การตรวจสอบความถูกต้องหรือการอนุญาตก่อนหน้านี้ที่ล้มเหลว การตรวจสอบสิทธิ์สำหรับคำสั่งที่ปักหมุดเป็นไปตามนโยบายคำสั่งที่ปักหมุด การส่งต่อยังคงไม่อนุญาตให้มีการดำเนินการ HTTP

วิธีการและเส้นทาง ลักษณะการทำงานหลังจากการพิสูจน์ตัวตน การอนุญาต และการตรวจสอบความถูกต้อง
POST /api/devices/{id}/exec 409: ดำเนินการภายในเซสชัน WebSocket ที่ปิดผนึก
GET /api/devices/{id}/exec/holds 409: ตรวจสอบงานที่จัดขึ้นภายในเซสชัน WebSocket ที่ปิดผนึก
POST /api/devices/{id}/exec/holds/{job_id}/kill 409: หยุดงานที่จัดขึ้นภายในเซสชัน WebSocket ที่ปิดผนึก
GET /api/devices/{id}/exec/holds/{job_id}/cat 409: อ่านเอาต์พุตงานที่เก็บไว้ภายในเซสชัน WebSocket ที่ปิดผนึก
POST /api/devices/{id}/sensors 409: รวบรวมเซ็นเซอร์ภายในเซสชัน WebSocket ที่ปิดสนิท
POST /api/devices/{id}/net 409: รันโพรบเครือข่ายภายในเซสชัน WebSocket ที่ปิดผนึก
POST /api/devices/{id}/update 409: ตรวจสอบหรือใช้การอัปเดตภายในเซสชัน WebSocket ที่ปิดผนึก
POST /api/devices/{id}/ubus 409: เรียก ubus ภายในเซสชัน WebSocket ที่ปิดผนึก
POST /api/devices/{id}/commands/{cmd}/run 409: ดึงคำสั่งที่ปักหมุดไว้และดำเนินการภายในเซสชัน WebSocket ที่ปิดผนึกพร้อมสิทธิ์การจัดการที่ได้รับอนุญาตจากอุปกรณ์

ตัวอย่างเช่น คำขอดำเนินการที่ถูกต้องนี้เป็นการตรวจสอบการปฏิเสธ ไม่ใช่อินเทอร์เฟซการดำเนินการคำสั่ง:

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}'

คาดหวัง HTTP 409 พร้อมด้วยข้อความแสดงข้อผิดพลาดภาษาอังกฤษ Sealed sessions are required. (แปลตามภาษาที่ร้องขอ) สร้างเซสชัน WebSocket แบบปิดผนึกดั้งเดิมเพื่อดำเนินการ ไม่มีการตอบสนองคำสั่งเอาต์พุตที่สำเร็จจากเส้นทาง HTTP นี้

การดูแลจัดการเซสชัน Exchange

สินค้าคงคลังและการยกเลิกเซสชันยังคงใช้งานได้ผ่าน HTTP เนื่องจากจัดการข้อมูลเมตาการกำหนดเส้นทาง Exchange พวกเขาจะไม่ดำเนินการการทำงานของอุปกรณ์หรือเปิดเซสชันอุปกรณ์เพิ่มเติม

วิธีการและเส้นทาง ร่างกายที่ประสบความสำเร็จ
GET /api/devices/{id}/sessions {sessions:[DeviceSessionInfo], limit, count}
POST /api/devices/{id}/sessions/{session_id}/kill {session_id, released}

ฟิลด์ DeviceSessionInfo คือ session_id (ID ตัวเลขฝั่งอุปกรณ์), operator_session_id, kind, hold, age_secs และ deadline_unix_ms limit คือ max_sessions_per_device (ค่าเริ่มต้น 32); count คือความยาวรายการปัจจุบัน รายการอ่านสถานะฮับ Exchange ในเครื่องโดยตรง อุปกรณ์ออฟไลน์ในเครื่องส่งคืน 503 Kill ใช้ device-side ID ส่งการยกเลิกที่เหมาะสม (รวมถึง exec ที่ถูกระงับ) และเผยแพร่เส้นทางในเครื่องแม้ว่าอุปกรณ์จะไม่ตอบรับก็ตาม เซสชันที่หายไปหรืออุปกรณ์ออฟไลน์ในเครื่องส่งคืน HTTP 200 พร้อมด้วย released:false ตัวดำเนินการแบบอ่านอย่างเดียวได้รับ 403 สำหรับจุดปลายทั้งสอง

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}"

ก่อนที่จะปฏิเสธขีดจำกัดเซสชันทั้งหมด Exchange จะเรียกคืนเส้นทางของผู้ดำเนินการที่ไม่ทำงานและเส้นทางที่เลยกำหนดเวลาไปแล้ว: การหมดเวลาของ exec + 15 วินาที, การถ่ายโอนไฟล์ 3600 วินาที + 15 วินาที, ประเภทอื่นๆ 24 ชั่วโมง ผู้บริหารที่จัดขึ้นภายในกำหนดเวลาจะแยกออกจากกันเมื่อตัวดำเนินการตัดการเชื่อมต่อแทนที่จะถูกฆ่า

การดำเนินการ CLI ที่ปิดผนึกแบบเนทีฟ

CLI สร้างเซสชันที่ปิดผนึกซึ่งเป็นส่วนหนึ่งของการทำงานของอุปกรณ์ตามปกติ ดำเนินการอนุมัติรูทพื้นที่ทำงานและการอนุญาตอุปกรณ์ก่อน โปรดดู เซสชันที่ปิดผนึก ไม่มีการเลือกไม่ใช้ข้อความธรรมดา คำสั่งปกติไม่จำเป็นต้องมีแฟล็กการปิดผนึกเพิ่มเติม:

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"

การปฏิบัติงานที่จัดขึ้นจะดำเนินการภายในเซสชันที่ปิดสนิท การดูแลจัดการเซสชัน Exchange มีแยกจำหน่ายผ่าน remote-cli sessions และ remote-cli session-kill การดึงข้อมูลเมตาคำสั่งที่ปักหมุดไม่อนุญาตให้ดำเนินการ: อุปกรณ์จะต้องยอมรับสิทธิ์การจัดการของผู้ปฏิบัติงานที่ปิดผนึก

ไดเร็กทอรีคีย์เซสชันที่ปิดผนึกและการถ่ายทอดสิทธิ์

Exchange จัดเก็บคีย์สาธารณะของผู้ปฏิบัติงานและโทเค็นการให้สิทธิ์ rsg1. ที่เจ้าของลงนาม เพื่อให้ลูกค้าสามารถค้นพบกันและกันได้ **นี่ไม่ใช่การอนุญาต อุปกรณ์ ** ยังคงตรวจสอบลายเซ็นของเจ้าของกับนโยบายท้องถิ่น Exchange จัดทำดัชนีเพย์โหลดโทเค็นเท่านั้น (owner_key, operator_key, device_id, level, expires_at) และจะไม่ถือว่าการอัปโหลดเป็นการอนุญาต Exchange ไม่สามารถปลอมแปลงลายเซ็นรูทได้ แต่สามารถระงับข้อมูลประจำตัว นำเสนอบัญชีรายชื่ออย่างไม่ถูกต้องไปยังไคลเอนต์รูทที่อนุมัติอัตโนมัติ สังเกตข้อมูลเมตา หรือปฏิเสธบริการ

รูทของเวิร์กสเปซ (rsr1.) และคำเชิญให้สิทธิ์ (rsi1.) เป็นการถ่ายทอดประเภทเดียวกัน Exchange ตรวจสอบรูปร่างโทเค็นและลายเซ็นตนเองของ Ed25519 (คำเชิญจะต้องตรงกับรูทคีย์ที่เก็บไว้ด้วย) และ not จะตัดสินใจว่าคีย์ตัวดำเนินการใดที่ได้รับการอนุมัติ GET /api/seal/roster เป็นมุมมองผู้ดูแลระบบระดับสูงของสมาชิก บทบาท และ operator_device_grants ลูกค้าจะต้องไม่ถือว่าคีย์ที่ปรากฏใหม่นั้นเชื่อถือได้จนกว่าไคลเอนต์รูทจะอนุมัติคีย์นั้นในเครื่อง ดูที่ docs/sealed-sessions.md

สมาชิกพื้นที่ทำงานที่ได้รับการตรวจสอบสิทธิ์สามารถแสดงรายการคีย์ ลงทะเบียนคีย์ของตนเอง และอัปโหลดสิทธิ์ (สิทธิ์คือการตรวจสอบสิทธิ์ด้วยตนเอง) DELETE ของคีย์นั้นจำกัดอยู่ที่บัญชีที่ลงทะเบียน (ผู้ดูแลระบบอาจลบออกก็ได้) DELETE ของทุนจำกัดเฉพาะผู้อัปโหลด (ผู้ดูแลระบบอาจลบรายการใดก็ได้) GET /api/seal/grants ข้ามแถวที่หมดอายุ

หลักฐานการลงทะเบียนที่สำคัญคือ Ed25519 มากกว่า:

remote-seal-key-register:v1:<workspace_id>:<operator_id>:<public_key>:<issued_at_ms>

issued_at_ms ต้องอยู่ภายใน ±10 นาทีของนาฬิกาเซิร์ฟเวอร์ public_key และ proof เป็น base64 มาตรฐาน (คีย์ 32 ไบต์, ลายเซ็น 64 ไบต์)

วิธีการและเส้นทาง ร่างกาย ความสำเร็จ
POST /api/seal/keys {"public_key","label"?,"proof","issued_at_ms"} รหัสที่ลงทะเบียน (upsert สำหรับบัญชีเดียวกัน)
GET /api/seal/keys — [{operator_id, username, email, public_key, label, created_at, last_seen_at}]
DELETE /api/seal/keys/{key} — 204 ({key} เป็นคีย์สาธารณะที่เข้ารหัส URL)
POST /api/seal/grants {"tokens":["rsg1.…"]} {stored:[…], errors:[…]}
GET /api/seal/grants?mine=1 — มอบสิทธิ์ให้ operator_key เป็นหนึ่งในคีย์ที่ลงทะเบียนของผู้โทร เงินช่วยเหลือแต่ละรายการที่ owner_key ไม่ใช่รูทที่เผยแพร่ยังรวมถึง chain ด้วย (โทเค็นใบรับรอง อาจว่างเปล่า)
GET /api/seal/grants?owner_key=… — ทุนที่ลงนามโดยรหัสเจ้าของนั้น
DELETE /api/seal/grants/{id} — 204
PUT /api/seal/root {"token":"rsr1.…","rotation":"rsx1.…"?} รูทพื้นที่ทำงานที่เก็บไว้ ผู้ดูแลระบบระดับสูงเท่านั้น มีการตรวจสอบรูปร่างและลายเซ็นของคีย์เอง นี่ไม่ใช่การอนุมัติ rotation (ทางเลือก) ต้องลงนามโดย root ที่เผยแพร่ในปัจจุบัน และตั้งชื่อ root ใหม่ จากนั้น Exchange จะพุช seal_root {token, rotation} ไปยังอุปกรณ์ที่ปิดผนึกแบบออนไลน์ ซึ่งจะปักหมุดใหม่เมื่อมีการลงนามการหมุนโดยรูทที่พวกเขาเชื่อถืออยู่แล้วเท่านั้น หากไม่มีการหมุนที่ถูกต้อง อุปกรณ์ที่ปักหมุดรูทเก่าจะเก็บไว้
GET /api/seal/root — {workspace_id, root_key, payload, signature, token, created_at} หรือ 404 เมื่อไม่มีการเผยแพร่
POST /api/seal/invitations {"token":"rsi1.…"} คำเชิญที่เก็บไว้ ผู้ดูแลระบบระดับสูงเท่านั้น และหลังจากที่รูทแล้วเท่านั้น
GET /api/seal/invitations — คำเชิญที่ยังไม่หมดอายุ ใหม่ล่าสุดมาก่อน ([] เมื่อไม่มี)
GET /api/seal/roster — {members:[{operator_id, username, email, role, restricted, enabled, keys:[{public_key, label}], device_grants:[{device_id, can_manage}]}]}. ผู้ดูแลระบบระดับสูงเท่านั้น รวมถึงสมาชิกผู้พิการด้วย

ความไม่พร้อมใช้งานของไดเร็กทอรีไม่ได้ข้ามข้อกำหนดเซสชันที่ปิดผนึกหรือการให้สิทธิ์อุปกรณ์ GET /api/seal/root ส่งคืน 404 เมื่อไม่มีการเผยแพร่เวิร์กสเปซ root

# 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}"

ใบรับรองระดับกลาง (rsc1.)

Exchange เก็บใบรับรองระดับกลางเพื่อให้คีย์ที่ไม่ใช่รูทสามารถลงนามสิทธิ์ที่อุปกรณ์จะยอมรับได้ ** ตรวจสอบ ** ลายเซ็น Ed25519 ของผู้ออก และ ** ไม่สามารถปลอมแปลงใบรับรอง ** ได้ การอัปโหลดโทเค็นไม่ได้รับการอนุญาต: ผู้เรียกจะต้องเป็นผู้ดำเนินการของผู้ออก ใบรับรองที่ลงนามระดับรูท (issuer_key เท่ากับรูทของเวิร์กสเปซที่เผยแพร่) อาจเผยแพร่ได้โดยผู้ดูแลระบบระดับสูงของเวิร์กสเปซเท่านั้น ตัวกลางอาจถูกเผยแพร่โดยบัญชีที่มีรหัสประทับตราที่ลงทะเบียนคือ issuer_key เท่านั้น และผู้ออกนั้นจะต้องอยู่ภายใต้ใบรับรองที่เก็บไว้ ไม่ถูกเพิกถอน และยังไม่หมดอายุพร้อมกับ can_issue เด็กจะต้องอยู่ในระดับผู้ปกครอง ขอบเขตอุปกรณ์ และการหมดอายุ (ใช้การตรวจสอบอุปกรณ์เดียวกัน) การเผยแพร่ (issuer_key, subject_key) เดิมอีกครั้งจะแทนที่แถวเก่าและล้างการเพิกถอน

GET /api/seal/certs/chain?subject_key= ส่งคืนลิงก์ผู้ออกการเดินของ {chain:[tokens]} จนถึงรูทที่เผยแพร่ ใบรับรองสูงสุด 4 ใบ ออกให้รูทก่อน หรือ 404 สมาชิกที่ได้รับการรับรองความถูกต้องอาจเรียกมันว่า GET /api/seal/grants?mine=1 เพิ่ม chain บนสิทธิ์ที่ผู้ลงนามไม่ใช่รูท ดังนั้นไคลเอ็นต์จะได้รับพร้อมกับสิทธิ์ เงินช่วยเหลือที่ลงนามโดยรูทจะละเว้น chain

GET /api/seal/certs แสดงรายการทุกแถว รวมถึงแถวที่ถูกเพิกถอน (ผู้ดูแลระบบและผู้ดูแลระบบระดับสูง) DELETE /api/seal/certs/{serial} (บัญชีของผู้ออกหรือผู้ดูแลระบบระดับสูง) ตั้งค่า revoked ที่หยุดการกระจายเท่านั้น อุปกรณ์จะปฏิบัติตามสำเนาที่พวกเขามีอยู่แล้วจนกว่าจะหมดอายุ การเพิกถอนแบบถาวรคือ revoked_keys ของนโยบายอุปกรณ์ {serial} เป็นอนุกรม base64 มาตรฐานที่เข้ารหัส URL

วิธีการและเส้นทาง ร่างกาย ความสำเร็จ
POST /api/seal/certs {"token":"rsc1.…"} ใบรับรองที่เก็บไว้ (เพิ่มโดยผู้ออกและหัวเรื่อง)
GET /api/seal/certs/chain?subject_key= — {chain:["rsc1.…"]}, ออก root ก่อน หรือ 404
GET /api/seal/certs — [{serial, issuer_key, subject_key, token, expires_at_ms, created_at, revoked}]. ผู้ดูแลระบบหรือผู้ดูแลระบบขั้นสูง
DELETE /api/seal/certs/{serial} — 204. ผู้ออกหรือผู้ดูแลระบบขั้นสูง หยุดการกระจายเท่านั้น
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}"

การสำรองข้อมูลคีย์รูทของพื้นที่ทำงาน (ไม่บังคับ)

PUT / GET / DELETE /api/seal/backup เก็บ rsb1. ทึบแสงหนึ่งหยดต่อบัญชี PUT และ GET เป็นผู้ดูแลระบบระดับสูงเท่านั้น: blob คือคีย์ส่วนตัวของพื้นที่ทำงาน root ซึ่งเข้ารหัสบนไคลเอ็นต์ด้วย Argon2id (64 MiB, t=3, p=1) และ ChaCha20-Poly1305 ข้อความรหัสผ่านเป็นทางเลือกและไม่มีความเข้มงวดในการบังคับใช้ ** ด้วยข้อความรหัสผ่านที่ว่างเปล่าหรืออ่อนแอ ใครก็ตามที่ถือ Blob (รวมถึง Exchange) จะสามารถถอดรหัสคีย์รูทและควบคุมทุกอุปกรณ์ได้ ** การอัปโหลดเป็นทางเลือก ลูกค้าสามารถส่งออกคีย์รูท (rsk1.) และเก็บไว้แบบออฟไลน์แทน Exchange ตรวจสอบว่า blob เริ่มต้นด้วย rsb1. และความยาวของมัน และไม่เคยถอดรหัส GET จำกัดอยู่ที่ 5 คำขอต่อบัญชีต่อชั่วโมงต่อกระบวนการ (HTTP 429) การอ่าน เขียน และการลบจะถูกตรวจสอบด้วยจำนวนไบต์เท่านั้น การตอบกลับส่ง Cache-Control: no-store

วิธีการและเส้นทาง ร่างกาย ความสำเร็จ
PUT /api/seal/backup {"blob":"rsb1.…"} {blob, updated_at}
GET /api/seal/backup — {blob, updated_at} หรือ 404 เมื่อไม่มีการจัดเก็บ อัตราจำกัด
DELETE /api/seal/backup — 204 รวมถึงเมื่อไม่มีแถวอยู่
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}"

การตรวจสอบสิทธิ์รูทเชนส่วนขยายของเบราว์เซอร์

การทำงานของเบราว์เซอร์ใช้เซสชัน WebSocket ที่ปิดผนึกแบบเนทีฟ ไม่ใช่ HTTP one-shot การดำเนินการ ส่วนขยายจะสร้างคีย์ตัวดำเนินการ Ed25519 ด้วยตนเอง โดยมีผู้ปฏิบัติงาน โทเค็นผู้ถือจะได้รับ tenant_id / operator_id จาก /api/auth/me จากนั้นจึงโทร POST /api/seal/keys พร้อม {public_key, label, proof, issued_at_ms} สัญญาณ PoP:

remote-seal-key-register:v1:<workspace_id>:<operator_id>:<public_key>:<issued_at_ms>

คีย์/ลายเซ็นเป็น base64 มาตรฐาน (32/64 ไบต์) เวลาจะต้องอยู่ภายใน ±10 นาทีของนาฬิกาเซิร์ฟเวอร์ การจดทะเบียนพิสูจน์การครอบครอง ไม่ใช่การอนุญาต ส่วนขยายจะซิงค์ GET /api/seal/root, GET /api/seal/grants?mine=1 และ โทเค็นใบรับรองที่รวมอยู่ในทุนหรือดึงมาจาก GET /api/seal/certs/chain?subject_key=<url-encoded-key>. เงินช่วยเหลือจะต้องตรวจสอบเพื่อ รูทพื้นที่ทำงานที่เชื่อถือได้ โดยตรงหรือผ่านสายใบรับรองที่ถูกต้องด้วย ขอบเขต ระดับ และความถูกต้องของอุปกรณ์ที่ถูกต้อง การลงทะเบียนโทเค็นอุปกรณ์ยังคงอยู่ แยกจากโฟลว์ไดเรกทอรีโอเปอเรเตอร์โทเค็นนี้

ส่วนขยายจะตรวจสอบ Hellos ดั้งเดิมที่เข้ามาผ่านทางรูทและรวมส่วนขยายด้วย เป็นเจ้าของ Hello/Grant/Chain ที่ลงนามใน SealAccept.peer CLI/console ตรวจสอบหลักฐานนั้น และต้องมี peer.operator_key == accept.device_key ก่อนยอมรับการลงนาม การตอบสนอง เอเจนต์ Rust ใช้นโยบายรูทปกติเมื่อส่วนขยายทำหน้าที่เป็น ผู้ปฏิบัติงาน การพิสูจน์ที่ไม่ถูกต้อง/ขาดหายไปล้มเหลวในการปิด ไม่มีเบราว์เซอร์แยกต่างหาก trust store/UI หรือทางเลือกดั้งเดิม อุปกรณ์ดั้งเดิมและพื้นที่ทำงาน-TOFU รูทยังคงอยู่ ส่วนขยายจะจัดเก็บรูทแรกต่อเซิร์ฟเวอร์/พื้นที่ทำงาน และปฏิเสธการเปลี่ยนแปลง

Security: ตรวจสอบรูทแรกนอกแบนด์ PoP หรือบทบาทของเซิร์ฟเวอร์ไม่ได้ การอนุมัติรูต ตรวจสอบคีย์ที่ไม่รู้จักก่อนการอนุมัติอัตโนมัติของไคลเอ็นต์รูท ป้องกัน โปรไฟล์/คีย์ปลายทางและสคริปต์ที่โฮสต์ การลบไดเรกทอรีไม่เพิกถอน ข้อมูลประจำตัวที่ลงนามในแคช Exchange สามารถดูข้อมูลเมตา ระงับข้อมูลรับรอง หรือ ปฏิเสธการให้บริการ การปิดผนึกไม่ได้แยกตัวดำเนินการ CDP เต็มรูปแบบที่ไม่เป็นมิตรออกจากกัน

การเลือก WebSocket หรือ HTTPS

ต้องการ ใช้
คำสั่ง, การตรวจสอบหรือยกเลิกงานที่ค้างไว้, เซ็นเซอร์, โพรบเครือข่าย, อัปเดต, ubus, คำสั่งที่ปักหมุด เซสชัน WebSocket ที่ปิดผนึกแบบเนทีฟ
PTY แบบโต้ตอบ, เอาต์พุตสตรีมมิ่ง, การถ่ายโอนไฟล์, หน้าจอ Android/ทรี/แตะ เซสชัน WebSocket ที่ปิดผนึกแบบเนทีฟ
การตรวจสอบสิทธิ์ คลังอุปกรณ์ ไดเร็กทอรีคีย์/สิทธิ์/ใบรับรอง การสำรองข้อมูลรูท HTTPS API
สินค้าคงคลังเซสชันการกำหนดเส้นทาง Exchange และการยกเลิก จุดสิ้นสุดการดูแลเซสชัน HTTPS
การมีอยู่ของอุปกรณ์ที่ใช้งานอยู่และการเชื่อมต่อของผู้ให้บริการที่มีอายุการใช้งานยาวนาน WebSocket; การทำงานของอุปกรณ์ในการเชื่อมต่อยังคงต้องมีการปิดผนึก

การไหลของตั๋วเบราว์เซอร์ (ข้อมูลประจำตัวไม่เคยอยู่ใน URL ของ WebSocket):

  1. POST /api/ws-ticket พร้อม Authorization: Bearer …
  2. เชื่อมต่อกับ GET /ws/browser และส่งเฟรม JSON แรก {"ticket":"…"}
  3. สร้างการจับมือไคลเอ็นต์/อุปกรณ์แบบปิดผนึกดั้งเดิมก่อนส่งการดำเนินการใดๆ ของอุปกรณ์ การให้สิทธิ์และห่วงโซ่ใบรับรองของผู้ปฏิบัติงานจะต้องตรวจสอบกับรูทที่อุปกรณ์ไว้วางใจ

ไคลเอ็นต์แบบเนทีฟใช้ GET /ws/operator พร้อมการรับรองความถูกต้องของผู้ปฏิบัติงานและข้อกำหนดเซสชันที่ปิดผนึกเหมือนกัน การเชื่อมต่อ WebSocket หรือการเข้าสู่ระบบบัญชีที่สำเร็จเพียงอย่างเดียวไม่ได้ให้อนุญาตการทำงานของอุปกรณ์ โปรดดูที่ Web console และ Web Push, protocol และ sealed sessions

เอกสารสรุปสถานะข้อผิดพลาด

สถานะ สาเหตุทั่วไป
400 อินพุตการดำเนินการไม่ถูกต้อง เช่น คำสั่งว่างหรือ URL แหล่งที่มาของการอัปเดตไม่ถูกต้อง การตรวจสอบความถูกต้องเกิดขึ้นก่อนการปฏิเสธเซสชันที่ปิดผนึก
401 โทเค็น Bearer หายไปหรือไม่ถูกต้อง
403 การอนุญาตบัญชีหรืออุปกรณ์ไม่อนุญาตให้ทำการร้องขอ
409 การดำเนินการของอุปกรณ์ HTTP ที่ถูกต้องและได้รับอนุญาตต้องมีเซสชัน WebSocket ที่ปิดผนึก ไม่มีการจัดส่งอุปกรณ์เกิดขึ้น
404 รายการไดเรกทอรีหายไปหรือรูทพื้นที่ทำงานที่ไม่ได้เผยแพร่ ตามสัญญาปลายทาง
429 ขีดจำกัดอัตราเฉพาะปลายทาง รวมถึงการอ่านข้อมูลสำรองระดับรูทของพื้นที่ทำงาน
503 สินค้าคงคลังของเซสชันไม่พบอุปกรณ์ในสถานะฮับ Exchange ภายในเครื่อง

เส้นทาง HTTP การดำเนินการของอุปกรณ์ไม่รอเอาต์พุต agent ดังนั้นผลลัพธ์ที่ได้รับอนุญาตตามปกติคือ 409 ไม่ใช่ความสำเร็จในการดำเนินการ ข้อผิดพลาดในการจัดส่งแบบออฟไลน์ หรือการหมดเวลาการดำเนินการ HTTP ข้อผิดพลาดจากข้อมูลเมตา การตรวจสอบสิทธิ์ และ API ไดเรกทอรีจะคงความหมายเฉพาะตำแหน่งข้อมูลไว้

แผนการตรวจสอบความถูกต้องด้วยตนเอง

ใช้บัญชีทดสอบและอุปกรณ์ที่มีสิทธิ์ที่ทราบ การตรวจสอบการปฏิเสธ HTTP ไม่จำเป็นต้องดำเนินการบนอุปกรณ์:

  1. ตรวจสอบและแสดงรายการอุปกรณ์ผ่าน HTTPS ตรวจสอบสิทธิ์บัญชีและอุปกรณ์
  2. ส่งคำขอที่ถูกต้องไปยังแต่ละเส้นทางการทำงานของอุปกรณ์ในตารางการปฏิเสธ คาดหวัง HTTP 409 และยืนยันว่าไม่มีการดำเนินการใดๆ ไปที่ agent รวมถึงการอ่านงานที่ค้างไว้และการรันคำสั่งที่ปักหมุดไว้
  3. ตรวจสอบข้อมูลรับรองที่ไม่ถูกต้อง บัญชีต้องห้าม และคำขอที่ป้อนไม่ถูกต้องแยกกัน คาดว่าจะมีข้อผิดพลาดในการรับรองความถูกต้อง การอนุญาต และการตรวจสอบ แทนที่จะถือว่าทุกคำขอส่งคืน 409
  4. อ่านรายการเซสชัน Exchange สำหรับเซสชันแบบใช้แล้วทิ้งที่เลือกไว้อย่างชัดเจน ให้ทดสอบการยกเลิกและตรวจสอบ released เซสชันที่หายไปส่งคืน released:false รายการเซสชันบนอุปกรณ์ออฟไลน์ในเครื่องส่งคืน 503
  5. ดำเนินการอนุมัติรูทและให้สิทธิ์ จากนั้นรันการดำเนินการ CLI ดั้งเดิมที่ไม่เป็นอันตราย เช่น remote-cli exec "$DEVICE_ID" -- uname -a ตรวจสอบว่าทำได้สำเร็จผ่านการจับมือที่ปิดสนิท การให้สิทธิ์อุปกรณ์ที่สูญหายหรือไม่ถูกต้องจะต้องปิดไม่สำเร็จ
  6. ตรวจสอบความถูกต้องของการลงทะเบียนคีย์ การอนุญาต/การดึงใบรับรอง การสำรองข้อมูลรูทเสริม และการตรวจสอบสิทธิ์รูทเชนของเบราว์เซอร์อย่างอิสระ HTTPS API เหล่านั้นยังคงใช้งานได้ภายใต้สัญญาข้างต้น

ปลายทางการส่งออกบันทึกการตรวจสอบ

รองรับเฉพาะ PostgreSQL Exchange และจำกัดอยู่ในพื้นที่ทำงานที่ผ่านการรับรองความถูกต้อง เฉพาะผู้ดูแลระบบและ superadmin เท่านั้น บัญชีอื่นจะได้รับ 403 ไม่รองรับ exchange-worker และไม่มีหน้าตั้งค่าใน Web/Mobile Console

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

โหมด throttled ซึ่งเป็นค่าเริ่มต้นจะส่งออกบันทึกการตรวจสอบที่จัดเก็บไว้ ข้อความที่ยาวกว่า 256 KiB จะเก็บ 250 KiB แรกและ 6 KiB สุดท้าย ไฟล์จะแสดงเป็นแฮช และสตรีมจะส่งออกเมื่อเซสชันสิ้นสุด โหมด full เก็บข้อมูลก่อนตัดทอน โดยแบ่ง JSON ต้นฉบับและเนื้อหาไบนารีเป็นชิ้น (ค่าเริ่มต้น 1 MiB) พร้อม ID การทำงาน/สินทรัพย์ ลำดับ ออฟเซ็ต เครื่องหมายชิ้นสุดท้าย SHA-256 และขนาดรวม สำหรับเซสชันที่ปิดผนึก ทั้งสองโหมดส่งออกเฉพาะข้อมูลเมตาและการอ้างอิง/แฮชของข้อมูลเข้ารหัส ไม่มีโหมดใดกู้คืนข้อความธรรมดาบนปลายทางได้

ข้อมูลลับและส่วนหัวถูกเข้ารหัสและอ่านกลับเป็น *** คำขอ PATCH จะคงค่าเดิมเมื่อรับ *** ส่วนส่วนหัวที่มีค่า null จะถูกลบ การส่งใช้คิว FIFO แบบคงทนที่ทำงานเบื้องหลังและลองใหม่โดยเพิ่มระยะรอแบบเอ็กซ์โพเนนเชียล เมื่อคิว throttled เต็ม จะทิ้งรายการเก่าสุดและนับจำนวนที่ทิ้ง ส่วนคิว full บนดิสก์จะชะลอผู้ส่งเมื่อเต็ม สถานะแสดงความสำเร็จ/ล้มเหลว งานค้าง รายการที่ทิ้ง และช่องว่าง การลบปลายทางจะทิ้งข้อมูลที่รอส่งและบันทึกจำนวนไว้ การเปลี่ยนการตั้งค่าถูกบันทึกการตรวจสอบในธุรกรรมเดียวกัน

Webhook ส่งอาร์เรย์ events ใน JSON โดยเข้ารหัสไบต์เป็น base64 ตรวจสอบ X-Remote-Timestamp และ X-Remote-Signature: sha256=<hex> ด้วย HMAC-SHA256(timestamp + "." + raw body) OTel ใช้ OTLP/HTTP JSON /v1/logs, body.bytesValue สำหรับชิ้นข้อมูล, แอตทริบิวต์ remote.device.id / remote.operator / remote.action และ service.name ที่กำหนดค่าได้ gRPC ต้องใช้ Collector เป็นตัวกลาง ไม่มีตัวส่งออก gRPC โดยตรง

ด้านล่างคือตัวอย่างการตั้งค่าเริ่มต้น payload ของ webhook การตรวจสอบลายเซ็น และ Collector ต้องตรวจสอบเนื้อหา HTTP ดิบ จัดเก็บและตัดรายการซ้ำด้วย delivery_id ก่อนตอบ 2xx เปิด allow_structured_metadata ใน Loki 3.x เพิ่มแหล่งข้อมูล Loki ใน Grafana แล้วค้นหา {service_name="remote-exchange"} หากใช้ gRPC ให้เปลี่ยน exporters ของ pipeline เป็น [otlp/grpc] ใช้ TLS และการรับรองความถูกต้องในระบบจริง

{"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]
ฟิลด์การตรวจสอบ ฟิลด์ 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.*
เหตุการณ์ที่จัดเก็บ body.stringValue