backlog: удалена задача local-image-build, она реализована
- все три приложения (homepage, transcriber, remembos) собирают образы локально ролью app_image, реестр и yc_*-переменные выведены из оборота - ссылавшиеся задачи обновлены: narrow-secret-scopes и no-secrets-in-playbook-output больше не ждут эту работу
This commit is contained in:
@@ -36,8 +36,7 @@ _(sec-ревью)_ — три независимых security-ревью на м
|
|||||||
- [Уведомления о размере приложений и заполнении диска](disk-usage-alerts.md) — алерты на заполнение диска и аномальный рост data-томов; сервер ресурсно ограничен _(tududi)_
|
- [Уведомления о размере приложений и заполнении диска](disk-usage-alerts.md) — алерты на заполнение диска и аномальный рост data-томов; сервер ресурсно ограничен _(tududi)_
|
||||||
- [Handlers рестарта для оставшихся приложений](handlers-remaining-apps.md) — apprise/dashboard/transcriber/miniflux монтируют конфиг в контейнер, но рестарта нет вовсе; правка конфига не подхватывается
|
- [Handlers рестарта для оставшихся приложений](handlers-remaining-apps.md) — apprise/dashboard/transcriber/miniflux монтируют конфиг в контейнер, но рестарта нет вовсе; правка конфига не подхватывается
|
||||||
- [Composable-роль `backup`](ansible-backup-role.md) — бэкап — самый чистый шов для extraction (одинаков у всех, различается только список targets) _(ансибл-ревью)_
|
- [Composable-роль `backup`](ansible-backup-role.md) — бэкап — самый чистый шов для extraction (одинаков у всех, различается только список targets) _(ансибл-ревью)_
|
||||||
- [Локальная сборка образов вместо Yandex Container Registry](local-image-build.md) — все три приложения переведены на роль `app_image`; осталось вычистить `yc_*`-переменные из vault и прогнать деплой
|
- [Вывести из оборота секреты с широкими правами](narrow-secret-scopes.md) — `yc_oauth_token` (весь аккаунт Yandex Cloud) уже выведен; осталось проставить радиус остальным переменным vault и сузить широкие
|
||||||
- [Вывести из оборота секреты с широкими правами](narrow-secret-scopes.md) — один `yc_oauth_token` открывает весь аккаунт Yandex Cloud; после инцидента 24 июля цена утечки одной переменной должна быть ограничена одним сервисом
|
|
||||||
- [outline: секреты из файлов](secrets-file-outline.md) — умеет generic `<NAME>_FILE` для всех пяти секретов; единственное приложение, где выносится вообще всё, включая пароль БД
|
- [outline: секреты из файлов](secrets-file-outline.md) — умеет generic `<NAME>_FILE` для всех пяти секретов; единственное приложение, где выносится вообще всё, включая пароль БД
|
||||||
- [wakapi: секреты из файлов](secrets-file-wakapi.md) — salt, SMTP и OIDC выносятся либо через generic `_FILE`, либо через `config.yml`; для OIDC второй путь надёжнее из-за бага с `=` в значении
|
- [wakapi: секреты из файлов](secrets-file-wakapi.md) — salt, SMTP и OIDC выносятся либо через generic `_FILE`, либо через `config.yml`; для OIDC второй путь надёжнее из-за бага с `=` в значении
|
||||||
- [authelia: секреты из файлов](secrets-file-authelia.md) — пять полей закрывает `_FILE`, jwks-ключ и client secret — только template-фильтр; заодно четыре client secret можно перевести в хэш и перестать считать секретами
|
- [authelia: секреты из файлов](secrets-file-authelia.md) — пять полей закрывает `_FILE`, jwks-ключ и client secret — только template-фильтр; заодно четыре client secret можно перевести в хэш и перестать считать секретами
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
`/root/.gramps`), rssbridge, dozzle, homepage и valkey/postgres-сайдкары gramps.
|
`/root/.gramps`), rssbridge, dozzle, homepage и valkey/postgres-сайдкары gramps.
|
||||||
Дотянуть там, где образ позволяет (rssbridge, valkey) — продолжение уже принятой
|
Дотянуть там, где образ позволяет (rssbridge, valkey) — продолжение уже принятой
|
||||||
в проекте практики.
|
в проекте практики.
|
||||||
- ~~**homepage на `:latest`**~~ — **снято**: переход на роль `app_image`
|
- ~~**homepage на `:latest`**~~ — **снято**: переход на роль `app_image` дал
|
||||||
([local-image-build](local-image-build.md)) дал каждому деплою уникальный тег
|
каждому деплою уникальный тег из `BUILD_ID`, плавающего `latest` больше нет
|
||||||
из `BUILD_ID`, плавающего `latest` больше нет ни у homepage, ни у остальных.
|
ни у homepage, ни у остальных.
|
||||||
- **Соглашение о портах**: зафиксировать в AGENTS.md, что новые `ports:` — только
|
- **Соглашение о портах**: зафиксировать в AGENTS.md, что новые `ports:` — только
|
||||||
с `127.0.0.1:`. Docker публикует порты мимо UFW, поэтому дисциплина
|
с `127.0.0.1:`. Docker публикует порты мимо UFW, поэтому дисциплина
|
||||||
localhost-биндинга — единственный контроль (сейчас соблюдается: apprise, wanderer).
|
localhost-биндинга — единственный контроль (сейчас соблюдается: apprise, wanderer).
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
# Локальная сборка образов вместо Yandex Container Registry
|
|
||||||
|
|
||||||
**Приоритет:** Средний
|
|
||||||
|
|
||||||
Три приложения деплоятся через Yandex Container Registry: homepage, transcriber,
|
|
||||||
remembos. Схема одинаковая — образ собирается локально и пушится в
|
|
||||||
`cr.yandex/...` (`playbook-homepage-registry.yml`,
|
|
||||||
`playbook-transcriber-registry.yml`), плейбук деплоя делает `docker_login` с
|
|
||||||
`yc_oauth_token`, compose тянет образ по registry-пути с зашитым в git тегом
|
|
||||||
(`transcriber:2fc5a56-1761210134`, `remembos:v0.2.0`, `homepage-nginx:latest`).
|
|
||||||
У remembos registry-плейбука нет вовсе — образ пушится руками.
|
|
||||||
|
|
||||||
Роль `app_image` (канон в `~/projects/private/ansible-roles`) делает то же самое
|
|
||||||
без registry: собирает образ на control-хосте командой самого приложения
|
|
||||||
(контракт — `task image`, получает `BUILD_ID` через окружение), везёт его на
|
|
||||||
сервер через `docker save`/`load` и отдаёт факт `app_image_tag` для compose.
|
|
||||||
Обкатана в umbar на jellybit и trackers.
|
|
||||||
|
|
||||||
Что станет иначе: из деплоя уходят внешний реестр и OAuth-токен, тег образа
|
|
||||||
перестаёт быть константой в git, а `inv pl -- homepage` становится полным
|
|
||||||
деплоем — сейчас сборка живёт в `task deploy` репозитория homepage, который сам
|
|
||||||
зовёт `ansible-playbook`.
|
|
||||||
|
|
||||||
Шаги:
|
|
||||||
|
|
||||||
- ~~завендорить роль `app_image`~~ — **сделано**: подписка в `SYNCED_ROLES`,
|
|
||||||
копия в `roles/app_image`; механика переноса — [shared-roles-sync](shared-roles-sync.md)
|
|
||||||
- ~~homepage: завести в Taskfile таск `image` с тегом из `$BUILD_ID`, перевести
|
|
||||||
плейбук на роль, удалить `playbook-homepage-registry.yml` и registry-переменные
|
|
||||||
из `vars/homepage.yml`~~ — **сделано**: таск `image` собирает node-образ, сайт
|
|
||||||
и nginx-образ одной командой; `task deploy`/`deploy-with-ansible` удалены,
|
|
||||||
деплой целиком — `inv pl -- homepage`
|
|
||||||
- ~~remembos: контракта сборки нет (есть Dockerfile, нет Taskfile) — завести таск
|
|
||||||
`image`, убрать зашитый тег из compose~~ — **сделано**: в репозитории remembos
|
|
||||||
появился `Taskfile.yml` с таском `image`, плейбук зовёт роль, compose тянет
|
|
||||||
`remembos:{{ app_image_tag }}` с `pull_policy: never`; `docker_login` из
|
|
||||||
плейбука убран
|
|
||||||
- ~~transcriber: исходников на этой машине нет~~ — **сделано**: репозиторий
|
|
||||||
нашёлся (`~/projects/private/transcriber`), Taskfile сведён к таску `image`,
|
|
||||||
плейбук переведён на роль; `vars/transcriber.images.yml` с зашитым тегом
|
|
||||||
удалён вместе с ритуалом «yq + коммит тега» из старого `task deploy`
|
|
||||||
- осталось: убрать `yc_oauth_token` и `yc_container_registry` из vault — на них
|
|
||||||
больше никто не ссылается; дальше по [narrow-secret-scopes](narrow-secret-scopes.md)
|
|
||||||
|
|
||||||
Готово, когда ни один плейбук не делает `docker_login`, `cr.yandex` не
|
|
||||||
встречается в репозитории, а все три приложения деплоятся одним
|
|
||||||
`inv pl -- <app>`. Осталось только вычистить vault и прогнать деплой каждого
|
|
||||||
приложения.
|
|
||||||
|
|
||||||
Цена размена: дедупликации по слоям больше нет — каждый деплой везёт полный
|
|
||||||
образ, и для сборки нужен локальный docker с тулчейном. Для ручного нечастого
|
|
||||||
деплоя это осознанный выбор (так решено в самой роли). Замеры архивов
|
|
||||||
(`docker save`): homepage — 61 МБ, transcriber — 73 МБ, remembos — 21 МБ.
|
|
||||||
|
|
||||||
Пересекается с [gitea-runner-on-demand](gitea-runner-on-demand.md): если сборки
|
|
||||||
уедут в CI, доставка образа на сервер снова становится отдельным вопросом.
|
|
||||||
|
|
||||||
Связано: playbook-homepage.yml, playbook-transcriber.yml, playbook-remembos.yml,
|
|
||||||
vars/homepage.yml, vars/transcriber.yml, roles/app_image,
|
|
||||||
files/{homepage,transcriber,remembos}/docker-compose.template.yml.
|
|
||||||
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
**Приоритет:** Средний
|
**Приоритет:** Средний
|
||||||
|
|
||||||
`yc_oauth_token` в vault — OAuth-токен аккаунта Yandex Cloud: реестр, виртуалки,
|
Показательный случай — `yc_oauth_token`: OAuth-токен всего аккаунта Yandex Cloud
|
||||||
биллинг. Нужен он ради одной операции — `docker login` в плейбуках homepage,
|
(реестр, виртуалки, биллинг) ради одной операции, `docker login` в плейбуках
|
||||||
transcriber и remembos. Радиус прав несопоставим с задачей, и 24 июля он вместе
|
homepage, transcriber и remembos. 24 июля он вместе с ещё 52 переменными ушёл
|
||||||
с ещё 52 переменными ушёл открытым текстом в транскрипт: цена одной такой утечки
|
открытым текстом в транскрипт: цена одной такой утечки — весь аккаунт, а не один
|
||||||
— весь аккаунт, а не один сервис.
|
сервис. Из этого репозитория он уже выведен (см. ниже), но такой перекос радиуса
|
||||||
|
надо найти и снять у остальных переменных.
|
||||||
|
|
||||||
Принцип, к которому идём: секрет даёт доступ ровно к тому, ради чего заведён.
|
Принцип, к которому идём: секрет даёт доступ ровно к тому, ради чего заведён.
|
||||||
Всё, что шире, — либо заменяется на скоупированный доступ (сервисный аккаунт с
|
Всё, что шире, — либо заменяется на скоупированный доступ (сервисный аккаунт с
|
||||||
@@ -14,10 +15,9 @@ transcriber и remembos. Радиус прав несопоставим с за
|
|||||||
общего), либо выводится из оборота совсем, либо риск принимается явно и
|
общего), либо выводится из оборота совсем, либо риск принимается явно и
|
||||||
записывается.
|
записывается.
|
||||||
|
|
||||||
Ядро задачи закрывается сборкой без реестра: после
|
Ядро задачи уже закрыто: homepage, transcriber и remembos собирают образы
|
||||||
[local-image-build](local-image-build.md) `yc_oauth_token` не нужен ни в одном
|
локально ролью `app_image`, `docker_login` из плейбуков ушёл, а `yc_oauth_token`
|
||||||
плейбуке и удаляется из vault. До неё эта задача не начинается — иначе деплой
|
вместе с `yc_container_registry*` удалён из vault (коммит `6a0d786`).
|
||||||
трёх приложений просто ляжет.
|
|
||||||
|
|
||||||
Дальше — ревизия остального: пройти по `group_vars/all/secrets.yml` и проставить
|
Дальше — ревизия остального: пройти по `group_vars/all/secrets.yml` и проставить
|
||||||
каждой переменной радиус («один сервис» / «весь аккаунт у провайдера» / «все
|
каждой переменной радиус («один сервис» / «весь аккаунт у провайдера» / «все
|
||||||
|
|||||||
@@ -33,10 +33,9 @@ miniflux деплоится молча, а остальные — нет.
|
|||||||
Чисто: miniflux (образец), memos, calibre, tuwunel, dashboard, caddy, netdata,
|
Чисто: miniflux (образец), memos, calibre, tuwunel, dashboard, caddy, netdata,
|
||||||
dozzle, goaccess, rssbridge, homepage.
|
dozzle, goaccess, rssbridge, homepage.
|
||||||
|
|
||||||
Отдельным пунктом — `docker_login` в homepage, transcriber и remembos:
|
`docker_login` в homepage, transcriber и remembos с `yc_oauth_token` в аргументах
|
||||||
`yc_oauth_token` идёт параметром модуля. По умолчанию аргументы не печатаются, но
|
модуля — снят: приложения собирают образы локально ролью `app_image`, реестра и
|
||||||
всплывают при `-v` и в отчёте о падении. Закрывается тем же `no_log`, а совсем
|
токена в плейбуках больше нет.
|
||||||
уходит после [local-image-build](local-image-build.md).
|
|
||||||
|
|
||||||
## Рычаги и их цена
|
## Рычаги и их цена
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user