# Изоляция и границы доступа

> Что интеграция может, чего не может и чем это обеспечено: пользователь ОС, каталоги, адреса, учётные данные.

Эта страница написана для тех, кто решает, пускать ли чужой код в свою сеть. Она
описывает механизмы, а не намерения: что именно ограничивает интеграцию и где проходит
граница, за которой ограничение — уже ваша ответственность.

## Процесс на подключение, пользователь на подключение

Каждое **подключение** (не интеграция, а именно связь с конкретной системой) работает
своим процессом под **своим пользователем ОС**. Идентификаторы выдаёт коннектор и
запоминает их, чтобы после перезапуска ничего не перемешалось.

Пользователь — на подключение, а не на интеграцию, потому что два подключения одной
интеграции держат **разные** учётные данные: прод и песочница не должны дотягиваться
друг до друга.

Если коннектор не может сменить пользователя (запущен не от root и без `CAP_SETUID`,
или контейнер стартовал с `--user`), интеграции **не запускаются вовсе**. Это
сознательно: работать «как получится, без изоляции» — другое обещание безопасности,
и мы его не даём. Git-мост в этом режиме работает полностью.

## Что видно на диске

Каталог состояния разложен так, что права ОС повторяют границу доверия:

| Каталог | Права | Кто и что |
|---|---|---|
| `<state_dir>/` | `0755` | проходной |
| `<state_dir>/identity` | `0700` | ключ агента — только ядро |
| `<state_dir>/secrets` | `0700` | токены git-провайдеров и подключений — только ядро |
| `<state_dir>/plugins` | `0755` | код интеграций и интерпретатор — читаемо |
| `<state_dir>/runtime` | `0755` | среда выполнения — читаемо |
| `<state_dir>/instances` | `0711` | проходной, но **не перечислимый**: подключение не может даже узнать имена соседей |
| `<state_dir>/instances/<GUID>` | `0700`, владелец — пользователь подключения | рабочий каталог: `HOME` и `TMPDIR` процесса |

Секреты лежат в каталоге, куда пользователю подключения хода нет. Читает их ядро.

Проверить это на своей машине можно одной командой — так выглядит рабочий
коннектор с одним подключением:

```console
$ ls -ld /var/lib/connector /var/lib/connector/*
drwxr-xr-x root   /var/lib/connector
drwxr-xr-x root   /var/lib/connector/catalog
drwx------ root   /var/lib/connector/identity     ← ключ агента
drwx--x--x root   /var/lib/connector/instances    ← проходной, не перечислимый
drwxr-xr-x root   /var/lib/connector/plugins
drwxr-xr-x root   /var/lib/connector/runtime
drwx------ root   /var/lib/connector/secrets      ← токены
-rw------- root   /var/lib/connector/state.json

$ ls -ld /var/lib/connector/instances/*
drwx------ 61000  /var/lib/connector/instances/FHTZDP8A706GTS67   ← своё, у своего пользователя
-rw------- root   /var/lib/connector/instances/uids.json
```

Пользователи подключений выдаются коннектором из отдельного диапазона и
запоминаются, чтобы после перезапуска ничего не перемешалось.

## Учётные данные: плагин их не видит

Интеграция не получает токенов — ни в настройках, ни в переменных окружения. Она
просит коннектор сделать запрос, а коннектор:

1. проверяет адрес, метод и путь по объявленному правилу;
2. **вычёркивает** заголовок авторизации, если интеграция попыталась поставить свой;
3. подставляет учётные данные сам — токеном, парой «учётная запись + секрет» или
   собственным заголовком трекера, как объявлено в манифесте;
4. записывает вызов в журнал подключения: какие учётные данные использованы (по имени,
   не по значению), метод, адрес, код ответа и длительность.

В переменных окружения процесса — только идентификатор подключения, его слаг и
**настройки, которые вы ввели в форму**. Ни ключа агента, ни токенов там нет.

## Куда разрешено ходить

Разрешение выводится из **вашего же поля** в форме подключения: «по адресу из
`base_url`», а не «на github.com». Поэтому в каталоге видно правило, а конкретный
адрес появляется, когда вы его вписали. Правило ограничивает хост, методы и префиксы
путей.

Дополнительно коннектор **отказывается** ходить на link-local адреса — там живут
метаданные и служба учётных данных облаков. Приватные диапазоны, наоборот, разрешены
намеренно: смысл коннектора в том, чтобы дотянуться до систем внутри вашей сети, и
запрет приватных сетей запретил бы сам продукт.

Частоту вызовов инструментов из прогонов коннектор ограничивает у себя: не более 120
обращений в минуту на подключение.

**Исключение — правило web** у интеграции [«Интернет»](/docs/connector/web): там адрес
называет модель, а не вы, поэтому правило устроено наоборот. Вместо хоста — ваши белый и
чёрный списки сайтов и типов содержимого, а приватные диапазоны **запрещены всегда**:
имя разрешается перед каждым запросом, хотя бы один непубличный адрес — отказ, и
соединение идёт ровно на проверенный адрес. Учётные данные на такой запрос не
навешиваются никогда.

<Callout type="warn">
Граница честности: изоляция — на уровне **пользователя ОС и учётных данных**, а не
сетевого пространства имён. Процесс интеграции — обычный процесс вашей машины и
технически может открыть сокет сам; ваших секретов у него при этом нет, поэтому такой
запрос никуда не аутентифицируется. Если вам нужен запрет на сетевом уровне, ставьте
его своими средствами (правила фаервола на пользователя, отдельный namespace,
выделенная машина под коннектор) — это ровно тот случай, когда мы не будем говорить,
что вопрос закрыт.
</Callout>

## Что уходит к нам

Коннектор отправляет **отчёт о состоянии** — то же, что вы видите в приложении:

- версия агента, онлайн/офлайн, список обслуживаемых репозиториев;
- по каждому подключению: слаг и название, интеграция и её версия, статус, последняя
  ошибка, проект разработки, **список инструментов** и **разрешённые адреса**;
- факты вызовов инструментов: какой инструмент, сколько длился, была ли ошибка.

Отчёт **никогда не содержит секретов** — это свойство его формата, а не аккуратности
вызывающего кода.

Отдельно уходят события трекера, но только те, что адресованы боту напрямую и только в
отмеченных проектах: [что именно](/docs/connector/trackers#что-уходит-к-нам-из-трекера).

## Удаление подключения

Удаление убирает подключение из конфига и останавливает его процесс. Файлы секретов и
рабочий каталог остаются на диске — их удаляет оператор, осознанно; коннектор не
чистит каталоги за пределами того, что сам создал в этот момент. Если машина выводится
из эксплуатации, снесите `state_dir` целиком: там ключ агента и все токены.
