Перейти до вмісту

Авторизація — хто що може робити і як ви це доводите

Control Center відповідає на два питання авторизації, і вони справді різні. «Чи може ця людина викликати цю операцію?» — це про людей, ролі та репозиторії. «Чи може цей агент спричинити цей ефект?» — це про дії, аргументи та радіус ураження; це вже Обмеження.

Ця сторінка — про перше питання, а також про запис, який залишають обидва.

Кожне рішення про авторизацію на боці людини проходить через одну функцію:

can(principal, permission, resource) → allow | deny + why

Дозвіл — це <domain>:<tier>: tickets:write, members:administer, repos:read. Каталог виведений, а не написаний вручну: він обчислюється з самої поверхні операцій (префікс назви операції дає домен, нижня межа ролі, яку вона вже застосовує, дає рівень), тож усі ~550 операцій мають дозвіл, і ніхто його не вписує.

Саме ця вивідність і варта захисту. Вона означає, що для НОВОЇ операції перевірка вмикається за замовчуванням — слабке місце моделі з ручними анотаціями в тому, що хтось забуває, а забувають саме про перевірку. Тест-храповик фіксує отриманий набір доменів, тож додавання операції під новим префіксом — це рішення про назву, яке ухвалює людина, а не випадковість.

Чотири рівні точно відповідають вбудованим ролям:

Рівень Мінімальна роль Приклад
read гість tickets:read
write учасник tickets:write
administer адмін members:administer
own власник workspace:own

П’ять вбудованих ролей — власник, адмін, учасник, переглядач, гість — це пресети над цим каталогом. Володіння — це одне місце на робочий простір, яке передають явно через Передати володіння (власника, що йде, інакше не видалити: скасування доступу через SCIM відмовляє будь-якому власнику робочого простору — спершу передайте володіння).

Користувацькі ролі працюють відніманням. Така роль називає базовий пресет (admin, member, viewer або guest — ніколи owner) і набір дозволів, ВИЛУЧЕНИХ із нього — «адмін, але без керування учасниками». Вона ніколи не може дати більше за свою основу, і саме тому їх безпечно вводити в наявну інсталяцію: кожна наявна перевірка залишається коректною верхньою межею. Учасники мають їх як custom:<id>, а клієнт, надто старий, щоб зрозуміти це значення, відкочується до гостя, а не вгадує.

Під ролями лежать дозволи на рівні репозиторію (none / read / review / write): членство в робочому просторі ніколи мовчки не дає більше прав, ніж forge. Їх перевіряє кожна поверхня, що відкриває доступ до коду, — зокрема ті, що дістаються до коду збоку, як-от термінал або сеанс редактора, відкритий на worktree простору.

Деякі операції взагалі не про робочий простір: налаштування всієї інсталяції, конфігурація SSO, облікові дані провайдерів, керування моделями, резервні копії всієї інсталяції. Такі операції оголошують повноваження сервера, і їх відхиляють усім, крім оператора інсталяції (записаного власника сервера). Навмисно існує одна особа оператора і одне її визначення.

Кожне рішення про авторизацію — і дозвіл, і відмову — дописується в журнал аудиту окремого робочого простору, пов’язаний хеш-ланцюгом.

Журнал самих лише відмов відповідає на питання «що ми заблокували?», але не на питання «що цей агент насправді зробив і хто це дозволив?», а розбір інциденту починається саме з нього. Тому кожен запис зберігає весь ланцюг атрибуції: діючий принципал, людину, від імені якої він діяв, делегування, через яке він прийшов, дію та її аргументи (у вигляді дайджесту), рішення і правило, за яким його ухвалено.

Записи пов’язані в ланцюг: хеш кожного покриває попередній, тож правка, видалення або перестановка будь-якого рядка ламає всі хеші після нього. Перевірити ланцюг заново перераховує все і називає першу ланку, що не сходиться. Журнал аудиту, який не можна перевірити, — це журнал; той, який можна перерахувати, — доказ.

Два наслідки, які варто знати:

  • Таблиця аудиту не підпадає під очищення за віком. Хеш-ланцюг не можна вкоротити з середини. Строк зберігання — це експорт, а потім усічення, і після усічення залишається контрольна точка з кінцевим хешем видаленого сегмента, тож те, що вціліло, усе одно перевіряється аж до самого початку.
  • Він іде поруч зі стрічкою активності, а не поверх неї. Стрічка — це те, що робили люди; журнал — те, що було дозволено й відхилено. Спільний ідентифікатор кореляції читає один виклик в обох.

Він експортується як JSON із розділювачами-переводами рядків і може потоково передаватися в SIEM (Splunk, Elastic, Sentinel — HTTP-ендпоінт із bearer-токеном). Потокове передавання за задумом не дає гарантій: недоступний SIEM у жодному разі не повинен блокувати виклик інструмента агентом, а надійна й перевірювана копія все одно лежить на диску.

Інсталяція може задати максимальний вік сеансу і тайм-аут простою. І те й те перевіряється під час перевірки облікових даних пристрою, через яку проходить кожен автентифікований канал: сеанс, який клієнт міг би проігнорувати, відповідає на анкету, а не на дії зловмисника. Інсталяція також може вимагати SSO — тоді ручне прив’язування нових пристроїв вимикається (із запобіжником від блокування: воно відмовляє, поки немає жодного робочого з’єднання SSO).

  • Це не ACL на окремі об’єкти. Дозволів на окремий тікет чи повідомлення немає — і це навмисно. Розділення на рівні репозиторію — саме те, що команди насправді просять, і воно є; спільний доступ до окремих об’єктів — комбінаторна поверхня без підтвердженого попиту тут.
  • Це не рушій політик, який налаштовують на DSL. Словник навмисно закритий, тож усю політику можна відобразити, пояснити й перелічити.
  • Застосовується ніде, крім сервера. Клієнтські перевірки існують лише для того, щоб не пропонувати елемент керування, у якому відмовлять. Остаточне рішення завжди за сервером.