AI Architect Trainer Відкрити інтерактивний трек

ГоловнаАрхітектура корпоративної аналітики

Контроль доступу та застосування політик

Де саме обвалюється RBAC, чим платить ABAC, як живе рушій політик у продакшні та чому правило доступу має стояти в площині даних, а не в застосунку.

Востаннє переглянуто: 2026-09-04 · In English

У цьому напрямі

Контроль доступу ламається не тоді, коли хтось написав неправильне правило, а тоді, коли правило стоїть не в тому місці. Застосунок захищає рівно ті шляхи, які ви написали; сховище має ще п'ять — BI-інструмент, ноутбук, Spark-джоба, репліка та відновлення з бекапу. Цей модуль розбирає три рішення, які визначають долю всієї моделі: коли переходити з ролей на атрибути, як винести рішення в окремий рушій політик без втрати аудиту та затримки, і як перенести застосування правила на рівень рядків і колонок разом із обмеженням мети.

RBAC і точка його обвалу: від вибуху ролей до атрибутів

E5.1

RBAC працює доти, доки право доступу є функцією лише посади. Модель гранично проста: суб'єкт отримує роль, роль несе набір дозволів, перевірка зводиться до пошуку в таблиці. Її головна цінність не в простоті, а в аналізованості: на питання «хто бачить цю таблицю?» відповідає один SELECT, і відповідь є повною.

Обвал настає в момент, коли рішення починає залежати від властивостей ресурсу або контексту — грифа запису, юрисдикції, належності до проєкту, часу доби, заявленої мети звернення. У RBAC для цих властивостей немає місця, тому єдиний спосіб їх виразити — закодувати комбінацію в саму назву ролі. Каталог ролей стає декартовим добутком:

ABAC (NIST SP 800-162) переносить ці властивості з назви ролі в дані. Рішення обчислюється як функція чотирьох груп атрибутів — суб'єкта, ресурсу, дії та середовища. Роль при цьому не зникає: вона лишається одним атрибутом суб'єкта серед інших.

Практичний критерій вибору один. Якщо нову вимогу можна задовольнити, дописавши значення в довідник атрибутів — ви в ABAC. Якщо для неї треба створити роль — ви вже всередині вибуху ролей, просто ще не порахували його.

-- RBAC: every new axis multiplies the entitlement catalogue.
-- 14 job families x 9 jurisdictions x 4 classification tiers x 30 deal teams
SELECT count(*) AS role_count
FROM   roles
WHERE  name ~ '^analyst_[a-z]{2}_(public|internal|confidential|restricted)_deal[0-9]+$';
-- role_count = 15120   <- fourteen real jobs hide behind these

-- ABAC: the same 15120 grants collapse into one predicate over attributes.
-- The role does not vanish; 'analyst' survives as ONE subject attribute.
SELECT d.*
FROM   deals d
WHERE  current_setting('app.job_family')  = 'analyst'
  AND  d.jurisdiction    = ANY (string_to_array(current_setting('app.jurisdictions'), ','))
  AND  d.classification <= current_setting('app.clearance')::int
  AND  d.deal_team_id    = ANY (string_to_array(current_setting('app.teams'), ',')::int[]);

-- Adding jurisdiction 'PL': one row in a reference table, zero new roles.
-- Under RBAC the same change would have minted 1680 of them.

На практиці

Європейський інвестиційний банк проводив піврічний перегляд прав на каталозі з 15 120 ролей (14 посадових родин × 9 юрисдикцій × 4 грифи × 30 угодних команд). 41% ролей не використали жодного разу за 12 місяців, середній користувач тримав 3.2 ролі, а сам перегляд забирав 6 тижнів роботи двох аналітиків. Перемоделювання в гібрид — 62 ролі плюс 4 атрибути з довідників HR і CRM — скоротило каталог у 244 рази, а перегляд до 2 днів.

Антипатерн

Створювати роль на кожну нову комбінацію (`analyst_de_confidential_deal17`) і називати це «тонким налаштуванням RBAC». Діагностична ознака проста: щоб задовольнити вимогу бізнесу, ви відкриваєте каталог ролей, а не довідник атрибутів.

Рушій політик: PDP/PEP/PIP, policy-as-code та бюджет затримки

E5.2

Винесення рішення із застосунку — це розділення чотирьох ролей, зафіксоване ще в архітектурі XACML і відтворене кожним сучасним рушієм: PEP перехоплює звернення та застосовує вердикт, PDP обчислює вердикт, PIP постачає атрибути, PAP адмініструє політики. Цінність не в абревіатурах, а в наслідку: правило перестає бути розсипаним по if-ах у 340 сервісах і стає одним артефактом, який можна прочитати, протестувати й версіонувати.

Policy-as-code означає рівно п'ять інженерних зобов'язань.

Затримка — місце, де наївна архітектура вмирає. Мережевий виклик PDP коштує 1–5 мс. Якщо PEP питає дозвіл на кожен рядок результату з 50 000 рядків, ви щойно додали до запиту від 50 до 250 секунд. Правильна відповідь не в масштабуванні PDP, а в частковій евалуації: PDP отримує відомі атрибути суб'єкта, обчислює все, що можна обчислити, і повертає не «так/ні», а залишковий предикат — умову, яку виконавець запиту вставляє у WHERE. Одне звернення до рушія замість 50 тисяч, а фільтрація йде там, де живуть дані.

Свіжість атрибутів визначає лаг відкликання. Якщо PIP кешує атрибути з TTL 15 хвилин, то звільнений співробітник зберігає доступ до 15 хвилин — це не баг, це властивість конструкції, яку треба або прийняти свідомо, або зняти push-інвалідацією на подіях життєвого циклу.

package data_access

# Deny-by-default. The single most consequential line in this file.
default allow := false

# Coarse capability still comes from the role - RBAC survives here.
allow if {
    input.action == "read"
    input.subject.roles[_] == "claims_analyst"
    clearance_ok
    purpose_ok
    not embargoed
}

clearance_ok if input.subject.clearance >= input.resource.classification

# Purpose is a request-time claim, never a property of the person.
purpose_ok if input.purpose in data.consent.allowed_purposes[input.resource.basis]

# deny-overrides: an explicit prohibition beats every permit above.
embargoed if input.resource.legal_hold == true

# Decision log contract - all three fields, or the decision is not reproducible.
decision := {
    "allow":       allow,
    "policy_sha":  data.build.git_sha,
    "attrs_as_of": input.subject.attributes_fetched_at
}

# Partial evaluation with resource.* left unknown returns a RESIDUAL, not a boolean:
#   classification <= 2 AND legal_hold = false
# The query engine splices that into WHERE. One engine call, not 50k.

На практиці

Страховий маркетплейс тримав логіку авторизації в 340 мікросервісах — у середньому в 11 місцях на сервіс. Після винесення в один Rego-бандл із sidecar-PDP: p99 затримки авторизації 0.4 мс завдяки частковій евалуації та фільтру, що йде в запит; час викатки зміни політики впав з 3 тижнів до 12 хвилин; а перший же прогін регресійних тестів політики виявив 7 сервісів, які при таймауті PDP працювали fail-open.

Антипатерн

Ставити PDP у мережевий виклик на кожен рядок результату, а потім, коли запит починає займати хвилини, вводити fail-open по таймауту «щоб не блокувати користувачів». Це перетворює перевантаження системи на автоматичне скасування контролю доступу — рівно в момент найбільшого ризику.

Застосування в площині даних: RLS, маскування колонок і обмеження мети

E5.3

Застосунок захищає рівно ті шляхи, які ви написали. Одна й та сама таблиця сховища доступна щонайменше з п'яти інших дверей: BI-інструмент із власним конектором, ноутбук дата-сайєнтиста, Spark-джоба, логічна репліка та відновлення з бекапу. Перевірка в контролері порталу не стосується жодних із них. Це не питання дисципліни команди — це питання того, що точка застосування стоїть вище за точку зберігання.

Рішення: опустити предикат у площину даних. Row-level security в Postgres, row-фільтри та маски колонок у Snowflake, Databricks чи Ranger, або доступ виключно через один керований об'єктний шар — саме цю задачу розв'язує онтологічний рівень Palantir Foundry разом зі своїм рівнем політик. Механізм різний, інваріант однаковий: жоден споживач не має шляху до рядка в обхід правила.

Обмеження мети (GDPR ст. 5(1)(b)) не виражається роллю. Той самий лікар у вівторок лікує пацієнта, а в середу робить ретроспективне дослідження. Особа, посада й навіть набір атрибутів ідентичні — законна підстава різна. Отже, мета має бути заявою часу запиту: клієнт передає її явно, політика перевіряє її проти підстави обробки конкретного запису, а журнал зберігає її разом із рішенням. Ефективний доступ — це перетин заявленої мети та підстави: якщо політика дозволяє дослідження, а запис не має відповідної згоди, вердикт — відмова.

Похідні дані успадковують обмеження. Вітрина, побудована з обмежених рядків, без успадкування правил стає каналом відмивання доступу: те, чого не можна прочитати рядком, читається сумою. Мінімальний захист — поріг k-анонімності на агрегати та наскрізний лінеаж грифа від джерела до вітрини.

-- One enforcement point in the data plane. The BI tool, the notebook and the
-- nightly export all traverse the same predicate. No application code involved.
ALTER TABLE encounters ENABLE ROW LEVEL SECURITY;
ALTER TABLE encounters FORCE  ROW LEVEL SECURITY;  -- applies to the owner too

-- Purpose is a request-time claim bound to the session, never a role.
CREATE POLICY encounters_treatment ON encounters FOR SELECT
  USING (
    current_setting('app.purpose', true) = 'treatment'
    AND care_team_id = ANY (string_to_array(current_setting('app.care_teams', true), ',')::int[])
  );

CREATE POLICY encounters_research ON encounters FOR SELECT
  USING (
    current_setting('app.purpose', true) = 'research'
    AND consent_research = true                       -- lawful basis on the ROW
    AND discharged_at < now() - interval '30 days'
  );
-- Two policies on one table are OR-ed: adding one WIDENS access. Verify, do not assume.

-- Column level: mask, never drop. A deterministic token keeps the join key alive.
CREATE VIEW encounters_governed AS
SELECT id,
       care_team_id,
       CASE WHEN current_setting('app.purpose', true) = 'treatment'
            THEN patient_mrn
            ELSE encode(hmac(patient_mrn, current_setting('app.pepper', true), 'sha256'), 'hex')
       END AS patient_mrn,
       diagnosis_code
FROM   encounters;

На практиці

Лікарняне сховище обслуговувало 3 BI-інструменти, ноутбуки дата-сайєнс-команди та нічний експорт до страховика, тоді як перевірки доступу існували лише в порталі. Аудит показав, що 100% обмежених рядків читалися з ноутбука в обхід порталу. Після перенесення правил у RLS з обов'язковою заявленою метою: одна точка застосування, падіння пропускної здатності 6% на потоці 220 тис. рядків/с, і кожне звернення в журналі несло код мети — час відповіді на запит суб'єкта даних скоротився з 9 днів до 40 хвилин.

Антипатерн

Робити «чисту» копію таблиці під кожну аудиторію замість одного правила над одним джерелом. Копії розходяться вже на другому релізі, відкликання доступу не поширюється на них жодним чином, а лінеаж грифа обривається на першому ж `CREATE TABLE AS SELECT`.

Джерела, з яких виведено напрям

  1. A Comparison of Attribute Based Access C
  2. A Role and Attribute Based Access Contro
  3. A Comprehensive Review of Access Control
  4. A Literature Review on Access Control in
  5. A Distributed Access Control Architectur
  6. A Multipolicy Authorization Framework fo
  7. Authentication and Authorization in Microservices
  8. A Comparison of Logical Formula and Enum
  9. Cryptographically Secure Information Flow Control on Key V
  10. A Framework for Policies over Provenance
  11. A Semantic Hierarchy for Erasure Policies
  12. A Practical Attribute Based Document Col

Пройти інтерактивно

У кожного напряму є питання, картки з інтервальним повторенням і облік прогресу. Для них потрібен акаунт — безкоштовний і на одну хвилину.

Відкрити інтерактивний трек Створити безкоштовний акаунт

Далі в цьому треку