Протокол на конектора на Matrix
Конекторът на Matrix използва същия плик (envelope), hello, сигнал за
активност и жизнен цикъл на задачите като агентите и конекторите на Axis
(Протокол на агента и конектора) и добавя съобщенията и
задачите за управление на защитни стени. Go типовете в
entrosity-shared-go/proto/matrix (и JobProgress.Detail в
proto/jobs.go) са единственият източник на истина; тази страница
описва предназначението и поведението.
Както и останалата част от протокола, тези типове само растат: полета се добавят, никога не се преименуват и не получават ново предназначение, така че конекторите на терен продължават да работят.
Транспорт
- WebSocket:
wss://hub.entrosity.com/matrix/api/connector/v1/wsсAuthorization: Bearer <connector key>. JSON текстови рамки, по един плик в рамка. - Първото съобщение трябва да е
hello(capabilities: ["firewall"], плюс"sites"от версиите, които управляват разрешени сайтове,"update"от версиите, които инсталират подписани издания, иpending_job_ids); сървърът отговаря сhello.ack, доставя чакащите задачи и може да предложи обновяване. - Конекторът изпраща
heartbeatвсяка минута. Той е онлайн от свояhello, докато сокетът не се затвори, или до 3 минути без съобщение. Минаването офлайн прави залите на защитните му стени неактуални. - Задачите следват
job.assign→job.ack→job.progress→job.result. Задача, изпратена безjob.ack, се изпраща отново; задача, незавършена преди изтичането си, се маркира от сървъра като изтекла (Резултати).
HTTP крайни точки (/api/connector/v1)
| Метод и път | Предназначение |
|---|---|
POST /enroll | {enrollment_token, hostname, domain, version} → {connector_id, connector_key, ws_url}. Токенът трябва да е токен за конектор на Matrix на активен тенант. Ограничение за IP (MATRIX_ENROLL_RATE_PER_MINUTE). |
GET /ws | WebSocket. |
POST /heartbeat | HTTP резервен вариант на heartbeat. |
GET /jobs/pending, POST /jobs/{id}/ack, …/progress, …/result | HTTP резервен вариант с периодично запитване за жизнения цикъл на задачите. |
POST /jobs/{id}/authorize | Разрешаване в момента на записа (по-долу). |
POST /report | HTTP резервен вариант на matrix.report (същата обработка; приема се gzip). 204. |
GET /firewalls/{firewallID}/credentials | API ключът на защитната стена (Идентификационни данни). |
GET /releases/{releaseID}/msi?t=… | MSI на издание за самообновяване; токенът във връзката го разрешава (без ключа на конектора). |
Всички освен /enroll и изтеглянето на издание изискват ключа на
конектора. Всичко, което прави конекторът, е ограничено до неговия тенант
и до собствените му защитни стени.
Съобщения
Конектор → сървър: matrix.report
Report е {firewalls: [FirewallReport]} (най-много 50). Всеки
FirewallReport:
| Поле | Значение |
|---|---|
firewall_id | Защитната стена. |
status | online, unreachable, auth_failed, version_mismatch, direction_invalid или error, с error и error_code. |
fortios_version | Както я отчита FortiGate. |
guard_state | accepted, pending или mismatch. |
rooms_fetched_at, rooms | Room {policy_id, name, room, building, status} на всяко правило на зала (най-много 2000). |
groups_hash, groups_fetched_at, groups | Адресните групи (AddressGroup с members); groups се пропуска, когато не са се променили от последния отчет със същия groups_hash. Най-много 500 групи с по 2000 члена. |
sites_hash, sites_fetched_at, sites | Само от конектори с sites. sites е списък от SitesList (Разрешени сайтове): винаги общият списък (exists: false, когато групата му липсва) и списъкът на всяка текуща зала, чиято група съществува; пропуска се, когато не се е променил от последния отчет със същия sites_hash. (services, групата на премахнатите услуги на Entrosity, още се изпраща от по-старите конектори и се пренебрегва.) |
Изпраща се според интервала за отчет на всяка защитна стена, веднага след всеки запис, а с групите (и сайтовете) – на всеки 5 минути, след обновяване на адресите и след записи на адреси или сайтове.
Какво прави сървърът: записва или обновява залите (present,
last_seen_at); залите, липсващи в успешен отчет, стават
present = false; съхранява моментната снимка на групите, когато е
включена, както и сайтовете, когато са включени (отчет без
sites_hash, от по-стар конектор, ги изчиства); обновява състоянието,
версията, състоянието на защитата и last_report_at на защитната стена;
уведомява уеб приложенията (matrix.rooms, matrix.addresses,
matrix.sites).
Невалиден отчет се отказва (invalid_message).
Задачи
| Тип | Данни | Резултат | Таймаут / изтичане |
|---|---|---|---|
matrix.firewall.apply | FirewallApplyJob {firewall: FirewallRef, credentials_version} | FirewallApplyResult {guard_state} | 1 мин / 24 ч |
matrix.firewall.remove | {firewall_id} | – | 1 мин / 24 ч |
matrix.firewall.check | {firewall_id, credentials_version?} | CheckResult | 60 с / 2 мин |
matrix.refresh | {firewall_id, scope: rooms|addresses|all} | FirewallReport | 30 с / 1 мин |
matrix.policy.set | PolicySetJob {firewall_id, policy_id, room, desired, change_id} | PolicySetResult | 30 с / 60 с |
matrix.address.update | AddressOpJob с expected_ip | AddressOpResult | 2 мин / 2 мин |
matrix.address.create | AddressOpJob без expected_ip | AddressOpResult | 2 мин / 2 мин |
matrix.sites.set | SitesSetJob {firewall_id, list, room, domains, list_version, change_id} | SitesSetResult | 2 мин / 2 мин |
update_agent | UpdateJob, компонент matrix-connector | UpdateResult | 30 мин |
FirewallRefе конфигурацията на защитната стена:firewall_id,driver(fortigateилиsimulator),host,port,vdom,source_interface,destination_interface,policy_pattern,hostname_suffix,marker_prefix,verify_tls,ca_pem,expected_version,report_interval_seconds,writes_enabled,address_writes_enabled,site_writes_enabled. Никога не съдържа ключа. Превключвателите не са част от обхвата. (services_enabledиservice_domainsна премахнатите услуги на Entrosity вече не се изпращат; конекторите ги пренебрегват.) Неговият обхват (хост, порт, VDOM, двата интерфейса, шаблон, окончание, маркер) е това, което фиксира локалната защита.- Прилагането съхранява конфигурацията; първото прилагане записва
защитната стена в защитата като очакваща, а променен обхват – като
несъответстващ. Когато
credentials_versionе по-нова от съхранената, конекторът взима ключа. CheckResult:version,direction_ok,rooms,groups,members,warnings(на английски, със стабилни представки катоlater_accept_policy:),guard_state,policy_names(всяко правило със зададеното направление, най-много 2000), а от конектори съсsites:sites(списъците, както в отчета). Предупрежденията за разрешените сайтове използват представкитеsites_not_set_up:,sites_policy_missing:,sites_policy_disabled:,sites_policy_not_covering:,sites_group_read_only:иsites_wildcard_dns:. Правило, на което всекиdstaddrе група за разрешени сайтове (или старата групаMatrix Entrosity services), не се отчита катоlater_accept_policy. Само за четене.PolicySetResult:policy_id,room,name,previous,status,wrote(изпратен е запис),confirmed(прочетен обратно).AddressOpJob:operation_id(UUID, същият при повторните опити),firewall_id,policy_id,group,name,ip,expected_ip(промяна),group_version(64 шестнадесетични знака) иresume(отбелязаното в журналаAddressOpStateна прекъснат опит, при изричен повторен опит; етапupdate_sent,create_sent,createdилиmember_sent).AddressOpResult:operation_id,state{stage, address_uuid, original_members, previous_ip},member.
Неуспешна задача за запис също носи своя PolicySetResult /
AddressOpResult / SitesSetResult в job.result.result, така че
сървърът знае дали нещо е било записано.
Разрешени сайтове
Домейни, които компютрите на една зала достигат и когато правилото на
залата е изключено. Всеки списък е адресна група във FortiGate с
фиксирано име, която администраторът създава еднократно заедно с ACCEPT
правило (същото направление като залите, групата на списъка като
dstaddr, групата (групите) на залата като srcaddr):
Списък (list) | Адресна група |
|---|---|
shared (всички зали) | Matrix allowed sites |
код на зала, напр. SB1-102 | Matrix allowed sites SB1-102 |
SitesList:list,room(празно заshared),group,exists,policy(SitesPolicy{policy_id, name, status, covers}: първото включено ACCEPT правило с точното направление на защитната стена и групата вdstaddr;covers, когато неговиятsrcaddrсъдържа източника на всяко правило на зала – или на тази зала при собствен списък – илиall),version(64 шестнадесетични знака, отпечатък на групата и обектите на членовете ѝ),editable,reason,domains(SiteEntry{domain, object, owned, editable, reason}; вграденият членnoneне се изброява).- Обекти, притежавани от Matrix: адресни обекти
type fqdnс имеmatrix-site:<domain>(при по-дълги имена: първите 58 знака на домейна,~и 8 шестнадесетични цифри от неговия SHA-256; най-много 79), чийто коментар е<marker prefix> siteи чийтоfqdnе точно домейнът. Само те се премахват или изтриват; всеки друг член се показва само за преглед (Not created by Matrix; change it on the FortiGate.) и се запазва. - Домейни (
matrix.ValidSiteDomain): малки букви, два или повече етикета отa-z 0-9 -(punycode за международните имена), по избор*.в началото, най-много 253 знака, не IP адрес; най-много 200 в списък. matrix.sites.set:domainsе пълното желано множество от домейни, притежавани от Matrix (канонични, сортирани). Конекторът прочита всичко отново; списъкът трябва да е настроен (група и правило, иначеsites_not_set_up), да може да се редактира (да не се използва като източник или в друга група, без вложени групи) и да е във версияlist_version(иначеconflict); собствени списъци само за текущи зали. Той създава липсващите обекти (като използва повторно свой обект за същия домейн от друг списък), задава членовете на групата като запазените членове плюс новите обекти (none, когато не остава нищо), изтрива своите обекти на премахнатите домейни, които вече никоя група или правило не използва (доколкото може), и потвърждава с ново прочитане. Домейн, който вече се осигурява от член, който не е на Matrix, не се добавя повторно.- Услуги на Entrosity (премахнати):
matrix.services.sync(ServicesSyncJob), стъпката за разрешаванеservices.sync, списъкътservicesиServicesStateостават вproto/matrixсамо като остарели (deprecated) типове на протокола. Сървърите никога не изпращат задачата и отказват стъпката (services_removed); конекторите завършват задачата неуспешно като неподдържан тип задача. SitesSetResult:list,domains(притежаваните от Matrix след задачата),added,removed,stage,wrote,confirmed. Неуспех след какъвто и да е запис се отчита катоunconfirmed.
Задача за сайтове заема едно място от лимита на записи на минута на конектора; следващите ѝ записи проверяват отново изтичането на задачата и локалната защита.
Подробности за напредъка на задачата
job.progress има специфично за продукта поле detail
(JobProgress.Detail). Задачите за адреси изпращат AddressOpProgress
{operation_id, state} преди всяка стъпка на запис, след като са я
отбелязали в локалния журнал:
| Етап | Изпраща се преди |
|---|---|
update_sent | PUT firewall/address/<name> (новата подмрежа) |
create_sent | POST firewall/address (новият обект) |
created | – (обектът е прочетен обратно; следва членството) |
member_sent | PUT firewall/addrgrp/<group> (членовете) |
done | – (потвърдено) |
Сървърът пази етапа в операцията с адреса, така че при прекъсване се вижда докъде е стигнала, а повторният опит може да продължи.
Задачите за сайтове изпращат SitesSetProgress {list, stage, object} преди всяка стъпка на запис: create_sent (преди POST firewall/address на FQDN обект), created (прочетен обратно),
member_sent (преди PUT firewall/addrgrp/<group>), delete_sent (преди
DELETE firewall/address/<object> на неизползван обект на Matrix).
Разрешаване в момента на записа
Точно преди всеки запис конекторът изпраща
POST /jobs/{jobID}/authorize с AuthorizeRequest:
| Поле | За |
|---|---|
step | policy.status (превключване на зала), address.update, address.create, address.member, sites.set |
policy_id, room | Стъпките за зали и адреси (room и при sites.set на собствен списък) |
list, domains_hash | sites.set (списъкът на задачата, SitesDomainsHash на домейните ѝ) |
previous, desired | policy.status |
object_name, group | Стъпките за адреси |
Отговорът е {allowed: true} или {allowed: false, reason}. При
съмнение конекторът отказва: всеки друг отговор, грешка или липса на
отговор до 5 секунди блокира записа (unauthorized).
Сървърът разрешава само ако са изпълнени всички условия:
- задачата принадлежи на този конектор, е
ackedилиrunningи не е изтекла; - стъпката съответства на типа задача (
matrix.policy.set↔policy.status;address.update↔address.update;address.create↔address.createилиaddress.member;matrix.sites.set↔sites.set), а стойностите са равни на данните на задачата; задачаmatrix.services.syncвинаги се отказва (services_removed); - за
sites.set:site_writes_enabledна защитната стена е включено и авторът все още може да променя списъка (общия списък: администратор на тенанта; списък на зала: администратор на тенанта или учител с право за залата); - защитната стена е в употреба и
writes_enabled(стъпки за зали) илиaddress_writes_enabled(стъпки за адреси) е включено; - авторът на задачата все още е активен потребител на тенанта, чиято
сесия в Hub не е прекратена, и все още е администратор на тенанта (или
глобален администратор), или, при превключване на зали, учител с
право за залата; системна задача (без автор, автоматично повторно
включване) трябва да принадлежи на график, който е
firing.
Причини: invalid_request, unknown_job, job_not_live, expired,
step_mismatch, values_mismatch, firewall_disabled,
writes_disabled, user_inactive, session_ended, not_permitted,
room_not_granted, schedule_not_firing, services_removed (задача
matrix.services.sync на премахнатите услуги на Entrosity),
not_recorded. Всяко
извикване се записва като стъпка на промяната (metadata.steps); ако не
може да бъде записано, записът се отказва.
Идентификационни данни
GET /firewalls/{firewallID}/credentials → {token, version}
(Cache-Control: no-store), само за защитна стена, зададена на питащия
конектор; 404 no_credentials, когато няма съхранен ключ. Конекторът го
взима, когато прилагане или проверка носи по-нова credentials_version,
и го пази защитен с DPAPI във firewalls.json. Всяко взимане се записва
в одитния журнал на тенанта като firewall.credentials_fetch, без
ключа. Ключовете никога не се появяват в данните на задачите,
резултатите, отчетите, събитията или журналите.
Кодове на грешки при задачи
Докладват се в job.result.error_code:
| Код | Значение | Резултат |
|---|---|---|
forbidden_policy | Не е правило на зала, което може да се управлява. | отказано |
policy_changed | Променено между прочитанията или непотвърдено без запис. | отказано |
room_mismatch | Правилото вече не е тази зала. | отказано |
unconfirmed | Изпратен е запис, но не е потвърден. | непотвърдено |
conflict | Версията на групата или очакваният IP адрес се различават. | отказано |
duplicate_ip, duplicate_name | Друг управляван компютър има този IP адрес; съществува обект с това име. | отказано |
shared_object | Използва се извън залата: само за четене. | отказано |
invalid_input | Името или IP адресът са отхвърлени. | отказано |
sites_not_set_up | Групата за разрешени сайтове или нейното ACCEPT правило липсва. | отказано |
unauthorized | Разрешаването в момента на записа от сървъра е отказало. | отказано |
guard_pending, guard_mismatch | Локалната защита не е приета или обхватът е променен. | отказано |
writes_disabled | Записите са изключени (от превключвател в сървъра или от защитата). | отказано |
busy | Изпълнява се друг запис на същия обект. | отказано |
not_found | Обектът не е намерен във FortiGate. | отказано |
rate_limited | Локалният лимит на записи на конектора. | отказано |
expired | Задачата е пристигнала твърде късно за запис. | грешка |
unreachable, tls, auth_failed | Няма връзка; сертификатът не е проверен успешно; HTTP 401/403. | грешка |
version_mismatch, direction_invalid, invalid_response | Версията на FortiOS се различава от фиксираната; интерфейсите или зоните не са намерени; непоследователни данни от FortiGate. | грешка |
unknown_firewall, unknown_driver | Конекторът не познава защитната стена или няма такъв драйвер. | грешка |
interrupted | Конекторът е рестартиран преди какъвто и да е запис. | грешка |
Кодовете при самообновяване (update_unsigned, signature_invalid,
download_failed, hash_mismatch, exec_failed) са същите като при
другите конектори (Кодове на грешки).
Резултати
Как сървърът съпоставя задача за запис с резултата на промяната:
| Задача | Резултат на промяната |
|---|---|
Успешна (и, за залите, confirmed) | success |
Неуспешна с wrote: true, код unconfirmed, етап на адрес след prepared или етап на сайтове (create_sent, created, member_sent, delete_sent) | unconfirmed |
| Неуспешна без запис, с код за отказ (редовете с отказано по-горе) | denied |
| Неуспешна без запис, с всеки друг код | error |
| Изтекла, след като конекторът я е потвърдил или стартирал | unconfirmed |
| Изтекла, без изобщо да е потвърдена | error |
Сървърът никога не създава отново задача за запис сам; непотвърдена промяна чака човек (нова промяна или изричен повторен опит за адреса).
Ограничения
| Ограничение | Стойност |
|---|---|
| Защитни стени в отчет | 50 |
| Зали на защитна стена | 2000 |
| Адресни групи на защитна стена, членове на група | 500, 2000 |
| Списъци с разрешени сайтове на защитна стена, домейни в списък | 2001, 200 |
| Шаблон за имената на правилата | 500 знака, RE2, една (?P<room>…) |
| Интервал за отчет | 15–300 с (по подразбиране 30) |
| Локални записи на защитна стена за минута | 1–600 (по подразбиране 60) |
| Ключ | 512 знака, без интервали |