owner: группа docker убрана у сервисных пользователей
- 20 приложений её не получают: контейнерами рулит ansible от root, а членство в группе docker равносильно root на хосте - у gitea, miniflux и outline группа осталась — их backup.sh дампит базу через docker compose exec из-под самого приложения - задача service-users-docker-group закрыта, остаток вынесен в новую backup-dump-without-docker-group
This commit is contained in:
@@ -17,13 +17,13 @@ _(sec-ревью)_ — три независимых security-ревью на м
|
||||
|
||||
## Высокий
|
||||
|
||||
- [Убрать группу `docker` у сервисных пользователей](service-users-docker-group.md) — `docker` = root на хосте; ~все app-аккаунты фактически root, изоляция «юзер на сервис» обнуляется _(sec-ревью)_
|
||||
- [Изолировать/запаролить сессионный redis Authelia](authelia-redis-isolation.md) — стор сессий SSO в общей сети без пароля; запись в него = hijack SSO всех сервисов _(sec-ревью)_
|
||||
- [Алерты на проблемные контейнеры](container-alerts.md) — wakapi крутился в restart-loop несколько дней незамеченным; healthcheck в compose + алерты Netdata
|
||||
- [Никаких секретов в выводе плейбуков](no-secrets-in-playbook-output.md) — `inv pl` всегда с `--diff`, и каждая задача, рендерящая файл с секретом, печатает его в терминал; `no_log` стоит ровно в одном месте из четырнадцати
|
||||
|
||||
## Средний
|
||||
|
||||
- [Дампы бэкапов без группы `docker`](backup-dump-without-docker-group.md) — у miniflux/gitea/outline группа осталась: их backup.sh дампит через `docker compose exec` из-под самого приложения
|
||||
- [Захардить мониторинг-стек (netdata / dozzle / goaccess)](harden-monitoring-stack.md) — netdata/dozzle: лишние привилегии + docker.sock + доверие Remote-User в общей сети; socket-proxy + monitoring_network _(sec-ревью)_
|
||||
- [Закрыть calibre-web forward-auth и проверить дефолтные креды](calibre-forward-auth.md) — домен без forward_auth, защита на встроенной авторизации с дефолтом `admin/admin123` _(sec-ревью)_
|
||||
- [Включить автообновления безопасности](security-autoupdates.md) — патчи openssh/libssl только вручную; окна в недели между CVE и фиксом _(sec-ревью)_
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Дампы бэкапов без группы `docker` у сервисных пользователей
|
||||
|
||||
**Приоритет:** средний
|
||||
|
||||
Группу `docker` (= root на хосте) убрали у всех сервисных пользователей, кроме
|
||||
трёх: `miniflux`, `gitea`, `outline`. Их `backup.sh` делает `docker compose exec`
|
||||
(pg_dump, `gitea dump`), а `files/backups/backup-all.py` запускает такие скрипты
|
||||
через `su --login <app_user>`, то есть от имени самого приложения — без членства
|
||||
в группе дамп упадёт.
|
||||
|
||||
Дампить снаружи докера нельзя: postgres порт не публикует, `gitea dump` живёт
|
||||
только внутри контейнера.
|
||||
|
||||
Варианты, как развязать:
|
||||
|
||||
- **A. sudo-обёртка на дамп.** Плейбук кладёт `/usr/local/sbin/backup-<app>-dump.sh`
|
||||
(root:root, 0755 — сам app_user его не перепишет) с единственным
|
||||
`docker compose exec …`, в sudoers — `<app_user> ALL=(root) NOPASSWD:` ровно на
|
||||
этот файл, а `backup.sh` дёргает его через `sudo`. Пользователь получает право
|
||||
на одну фиксированную команду вместо права на весь докер. Механизм в проекте
|
||||
уже обкатан: так `playbook-backups.yml` разрешает `primary_user` запускать
|
||||
`backup-all.py`.
|
||||
- **B. root-скрипты в оркестраторе.** Новый контракт в `backup-all.py`: если у
|
||||
приложения есть `backup-root.sh` с владельцем root — запускать его без `su`.
|
||||
Механизм один на всех, но от root пойдёт скрипт целиком, включая
|
||||
`keep-files.py`, и дампы станут root-овыми файлами в директориях приложения.
|
||||
- **C. оставить как есть** — три аккаунта как осознанное исключение,
|
||||
задокументированное в плейбуках.
|
||||
|
||||
Предпочтение на момент записи — A.
|
||||
|
||||
Связано: playbook-miniflux.yml, playbook-gitea.yml, playbook-outline.yml,
|
||||
files/*/backup.template.sh, files/backups/backup-all.py.
|
||||
@@ -1,20 +0,0 @@
|
||||
# Убрать группу `docker` у сервисных пользователей
|
||||
|
||||
**Приоритет:** высокий
|
||||
|
||||
Все приложения заводят системного пользователя с `owner_extra_groups: ["docker"]`
|
||||
(во всех `playbook-*.yml`), но docker.sock реально монтируют только netdata и
|
||||
dozzle. Членство в группе `docker` эквивалентно root на хосте (`docker run -v
|
||||
/:/host`), поэтому выделенные «непривилегированные» аккаунты (authelia, outline,
|
||||
gitea и т.д.) фактически все имеют root — изоляция «пользователь на сервис», ради
|
||||
которой их и заводили, обнуляется. Контейнерами рулит Ansible от root (become),
|
||||
сервисам группа не нужна. Убрать `docker` из `owner_extra_groups` у всех, кроме
|
||||
тех, кому он действительно нужен для самостоятельного управления своим compose (и
|
||||
тем — лучше через socket-proxy). За `primary_user` группу оставить для ручных
|
||||
операций (`inv ssh`).
|
||||
|
||||
Из sec-ревью (fable, 2026-07-13). Усиливает риск из серии `secrets-file-*`
|
||||
(секреты в `environment:` контейнеров): членство в группе `docker` — как раз тот
|
||||
доступ, которым такие переменные и вычитываются.
|
||||
|
||||
Связано: все playbook-*.yml (owner_extra_groups), roles/owner, playbook-docker.yml.
|
||||
@@ -27,7 +27,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create internal application directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create internal application directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create internal application directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
# Группа docker = root на хосте, поэтому её не выдаём никому, кроме
|
||||
# приложений, чей backup.sh делает docker compose exec: оркестратор
|
||||
# запускает такие скрипты через su от имени этого пользователя.
|
||||
# См. docs/backlog/backup-dump-without-docker-group.md.
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create internal application directories"
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create internal application directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
# Группа docker = root на хосте, поэтому её не выдаём никому, кроме
|
||||
# приложений, чей backup.sh делает docker compose exec: оркестратор
|
||||
# запускает такие скрипты через su от имени этого пользователя.
|
||||
# См. docs/backlog/backup-dump-without-docker-group.md.
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create internal directories"
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create internal application directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
# Группа docker = root на хосте, поэтому её не выдаём никому, кроме
|
||||
# приложений, чей backup.sh делает docker compose exec: оркестратор
|
||||
# запускает такие скрипты через su от имени этого пользователя.
|
||||
# См. docs/backlog/backup-dump-without-docker-group.md.
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create internal directories"
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create internal application directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Create application internal directories"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -34,10 +34,18 @@ compose-шаблоны берут оттуда `owner_create_result.uid` и
|
||||
| `owner_uid` | да | Uid пользователя |
|
||||
| `owner_group` | нет | Имя группы, по умолчанию `owner_name` |
|
||||
| `owner_gid` | нет | Gid группы, по умолчанию `owner_uid` |
|
||||
| `owner_extra_groups` | нет | Дополнительные группы (обычно `["docker"]`) |
|
||||
| `owner_extra_groups` | нет | Дополнительные группы; по умолчанию пусто |
|
||||
| `owner_ssh_keys` | нет | Список публичных ключей для `authorized_keys` |
|
||||
| `owner_env` | нет | Словарь переменных окружения, попадающих в `~/.env` |
|
||||
|
||||
## Про группу `docker`
|
||||
|
||||
Членство в группе `docker` равносильно root на хосте (`docker run -v /:/host`),
|
||||
поэтому сервисным пользователям её не выдаём: контейнерами рулит Ansible от
|
||||
root. Исключение — приложения, чей `backup.sh` дампит базу через
|
||||
`docker compose exec`: оркестратор бэкапов запускает такие скрипты от имени
|
||||
самого приложения. См. `docs/backlog/backup-dump-without-docker-group.md`.
|
||||
|
||||
## Пример использования
|
||||
|
||||
```yaml
|
||||
@@ -48,5 +56,4 @@ compose-шаблоны берут оттуда `owner_create_result.uid` и
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_uid: "{{ app_owner_uid }}"
|
||||
owner_gid: "{{ app_owner_gid }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user