เจ้าหน้าที่ 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> อาจเป็นอย่างใดอย่างหนึ่ง:
- โทเค็นเซสชันการเข้าสู่ระบบด้วยรหัสผ่าน จาก
POST /api/auth/login - 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):
POST /api/ws-ticketพร้อมAuthorization: Bearer …- เชื่อมต่อกับ
GET /ws/browserและส่งเฟรม JSON แรก{"ticket":"…"} - สร้างการจับมือไคลเอ็นต์/อุปกรณ์แบบปิดผนึกดั้งเดิมก่อนส่งการดำเนินการใดๆ ของอุปกรณ์ การให้สิทธิ์และห่วงโซ่ใบรับรองของผู้ปฏิบัติงานจะต้องตรวจสอบกับรูทที่อุปกรณ์ไว้วางใจ
ไคลเอ็นต์แบบเนทีฟใช้ 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 ไม่จำเป็นต้องดำเนินการบนอุปกรณ์:
- ตรวจสอบและแสดงรายการอุปกรณ์ผ่าน HTTPS ตรวจสอบสิทธิ์บัญชีและอุปกรณ์
- ส่งคำขอที่ถูกต้องไปยังแต่ละเส้นทางการทำงานของอุปกรณ์ในตารางการปฏิเสธ คาดหวัง HTTP
409และยืนยันว่าไม่มีการดำเนินการใดๆ ไปที่ agent รวมถึงการอ่านงานที่ค้างไว้และการรันคำสั่งที่ปักหมุดไว้ - ตรวจสอบข้อมูลรับรองที่ไม่ถูกต้อง บัญชีต้องห้าม และคำขอที่ป้อนไม่ถูกต้องแยกกัน คาดว่าจะมีข้อผิดพลาดในการรับรองความถูกต้อง การอนุญาต และการตรวจสอบ แทนที่จะถือว่าทุกคำขอส่งคืน
409 - อ่านรายการเซสชัน Exchange สำหรับเซสชันแบบใช้แล้วทิ้งที่เลือกไว้อย่างชัดเจน ให้ทดสอบการยกเลิกและตรวจสอบ
releasedเซสชันที่หายไปส่งคืนreleased:falseรายการเซสชันบนอุปกรณ์ออฟไลน์ในเครื่องส่งคืน503 - ดำเนินการอนุมัติรูทและให้สิทธิ์ จากนั้นรันการดำเนินการ CLI ดั้งเดิมที่ไม่เป็นอันตราย เช่น
remote-cli exec "$DEVICE_ID" -- uname -aตรวจสอบว่าทำได้สำเร็จผ่านการจับมือที่ปิดสนิท การให้สิทธิ์อุปกรณ์ที่สูญหายหรือไม่ถูกต้องจะต้องปิดไม่สำเร็จ - ตรวจสอบความถูกต้องของการลงทะเบียนคีย์ การอนุญาต/การดึงใบรับรอง การสำรองข้อมูลรูทเสริม และการตรวจสอบสิทธิ์รูทเชนของเบราว์เซอร์อย่างอิสระ 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 |