mistgate Документация

Релизы и подпись

Для мейнтейнеров и для тех, кто собирает Mistgate со своим ключом; ключ релиза, воспроизводимая сборка, подпись и публикация релиза, свой пакет и смена ключа.

На этой странице

Mistgate доверяет одному ключу релиза Ed25519: тот, у кого его закрытая половина, решает, что могут устанавливать агенты нод и панели. В официальные бинарники вшит ключ проекта, и мейнтейнеры подписывают им каждый релиз на GitHub. Если вы ставите официальный релиз, эта страница вам не нужна; работа с флотом описана в разделе Обновления. Эта страница — для мейнтейнеров и для тех, кто собирает бинарники со своим ключом.

Ключ релиза#

  • Закрытая половина хранится офлайн. Открытая вшивается в оба бинарника при сборке: RELEASE_KEY для make build, --key для mistgate release build и переменная репозитория MISTGATE_RELEASE_PUBLIC_KEY в workflow релиза.
  • При первом запуске панель сохраняет свой ключ в <data-dir>/release.pub. release.pub, отличающийся от вшитого ключа, никогда не принимается молча — ни в одну, ни в другую сторону: панель не доверяет ни одному пакету до mistgate release trust-key (см. «Смена ключа релиза» ниже).
  • Сборка без ключа не подписана: её агенты нод никогда не обновляются сами, а панель не может устанавливать релизы панели и не может дать установке по SSH доверенного агента.

Сделайте ключ (один раз)#

sh
mistgate release keygen --out ~/mistgate-release.key

Команда пишет закрытый ключ в файл (режим 0600; существующий файл никогда не перезаписывается) и печатает открытый ключ и его отпечаток (первые 16 шестнадцатеричных символов его SHA-256).

Внимание

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

Соберите с открытым ключом#

sh
git checkout v0.1.4
RELEASE_KEY=<открытый ключ> VERSION=v0.1.4 make build

Через mistgate release build собираются bin/mistgate-linux-{amd64,arm64} и bin/mistgate-node-linux-{amd64,arm64}. В панель и агенты вшиваются одинаковые версия, время сборки (время коммита рабочей копии) и открытый ключ релиза; mistgate version и mistgate-node version печатают отпечаток ключа.

Выпуск официального релиза#

Для каждого стабильного тега vMAJOR.MINOR.PATCH .github/workflows/release.yml запускает три задания. node собирает оба Linux-агента только средствами Go (без Node.js и npm-пакетов); panel собирает SPA админки через pnpm, а затем два бинарника панели. У обоих доступ к репозиторию только на чтение. publish — единственное задание с правом записи и единственное, которое не запускает код сборки, — создаёт черновик релиза с четырьмя бинарниками, BUILDINFO и SHA256SUMS. Все actions закреплены по SHA коммита. Черновик не виден панелям как последний релиз. Workflow требует переменную репозитория MISTGATE_RELEASE_PUBLIC_KEY и вшивает её во все четыре бинарника; если она не задана или некорректна, workflow завершится ошибкой и не опубликует релиз, который нельзя подписать.

Закрытый ключ в Actions не передаётся, и доверять бинарникам CI не нужно: на машине с ключом вы сами собираете релиз из тега, а mistgate release sign подписывает только те бинарники, которые ваша сборка воспроизводит байт в байт. Затем вы загружаете четыре файла манифестов и подписей и публикуете черновик. В течение 10 минут панели скачают и проверят пакет нод (ноды останутся на своих сборках, пока владелец не обновит их или не назначит обновление), а Проверить GitHub предложит релиз панели.

sh
VERSION=v0.1.6
git clone https://github.com/Mistgate/mistgate.git && cd mistgate   # или git fetch --tags в своей копии
git checkout "$VERSION"
(cd web && pnpm install --frozen-lockfile && pnpm build)           # бинарник панели содержит SPA
go build -o ../mistgate-signer ./cmd/mistgate                       # подписывающий бинарник; версия любая
gh release download "$VERSION" --repo Mistgate/mistgate \
  --pattern 'mistgate-linux-*' --pattern 'mistgate-node-linux-*' --dir ../downloaded
../mistgate-signer release sign --key ~/mistgate-release.key --version "$VERSION" --expires 90d \
  ../downloaded/mistgate-node-linux-amd64 ../downloaded/mistgate-node-linux-arm64 \
  ../downloaded/mistgate-linux-amd64 ../downloaded/mistgate-linux-arm64 --out ../signed
gh release upload "$VERSION" ../signed/manifest.json ../signed/manifest.sig \
  ../signed/panel-manifest.json ../signed/panel-manifest.sig --repo Mistgate/mistgate --clobber
gh release edit "$VERSION" --repo Mistgate/mistgate --draft=false

release sign откажется работать, если рабочая копия не стоит ровно на теге или в ней есть локальные изменения; затем пересоберёт каждый бинарник через mistgate release build с открытой половиной вашего ключа и сравнит со скачанным. Последняя команда публикует черновик: не публикуйте его, пока все четыре файла не загрузились.

Если подпись не прошла, потому что бинарник не совпал со своей пересборкой, не подписывайте: сначала выясните причину. Обычно это другой ключ в MISTGATE_RELEASE_PUBLIC_KEY, тег, перенесённый после сборки, или отличие тулчейна (см. ниже); необъяснимое отличие может означать взломанный раннер.

Воспроизводимая сборка#

mistgate release build (его используют workflow, make build и проверка в release sign) даёт байт в байт одинаковые бинарники для одного тега и ключа; сборка на Linux и кросс-сборка на Windows из одного коммита проверены и совпадают. Это выполняется, когда:

  • тулчейн Go — тот, что указан в строке toolchain файла go.mod. release build запрашивает ровно эту версию; если локальный Go другой, она один раз скачивается из прокси модулей Go;
  • исходники — чистая рабочая копия тега. Неотслеживаемые файлы (собранная SPA, bin/) в бинарник не попадают (-buildvcs=false); не меняйте .gitattributes репозитория — он выдаёт все файлы с окончаниями строк LF на любой системе;
  • флаги — фиксированные, их ставит release build: CGO_ENABLED=0, -trimpath, GOAMD64=v1, GOARM64=v8.0 и -ldflags "-s -w", где заданы только Version (тег), Built (время коммита тега) и ReleaseKey;
  • для бинарников панели SPA собрана командой pnpm install --frozen-lockfile && pnpm build (Node.js 22, версия pnpm из web/package.json).

Проверка доказывает, что CI собрал именно то, что лежит в теге. Код тега и зафиксированные зависимости она не проверяет: вредоносный пакет из go.sum или pnpm-lock.yaml соберётся и у вас точно так же.

Короткий срок подписи#

--expires (по умолчанию 30d) — сколько оба манифеста можно устанавливать; перехваченный старый манифест перестаёт работать, когда срок истекает. Ставьте короткий срок, например 90d, и продлевайте его заранее: выполните ту же команду release sign для того же тега с новым --expires и снова загрузите четыре файла с --clobber. Панели обновят пакет нод того же билда без повторного обновления нод, а манифест панели читают заново при каждой проверке. Если манифест панели истёк, панель так и пишет и релиз не устанавливает; пакет нод с истёкшим сроком больше нельзя раскатывать и использовать для установки по SSH.

Свой пакет#

Панель, собранная со своим ключом, игнорирует официальные релизы на GitHub: их подписи не сходятся с её ключом. Обновления нод она получает из пакета, который вы подписываете и копируете в её каталог данных, а бинарник панели вы меняете вручную (см. «Ранние сборки и ручное обновление» в разделе Обновления).

Подпишите бинарники нод#

sh
mistgate release sign --key ~/mistgate-release.key --version v0.1.4 --expires 90d \
  bin/mistgate-node-linux-amd64 bin/mistgate-node-linux-arm64 --out dist/
  • Запускайте её в рабочей копии тега (или укажите её в --source): команда откажется, если копия стоит не ровно на теге или в ней есть локальные изменения, пересоберёт бинарники и откажется, если какой-то не совпал.
  • Бинарники должны называться <имя>-<ос>-<архитектура>, как их называет make build. Переданные вместе с ними mistgate-linux-* попадут в panel-manifest.json.
  • Время сборки берётся из коммита тега; отличающийся --built отклоняется. Новая сборка, у которой собственное время сборки отличается от манифеста, после обновления откатывает себя сама (built_mismatch).
  • --expires — число дней (90d) или длительность в формате Go (2160h); по умолчанию 30d. Держите срок коротким и продлевайте его (см. выше).
  • Команда пишет dist/manifest.json и dist/manifest.sig, кладёт рядом копии бинарников, перечитывает результат и проверяет его, затем печатает версию, срок действия, каждый файл с размером и отпечаток ключа.

Положите пакет на панель#

sh
scp dist/* panel.example.com:/var/lib/mistgate/dist/

Панель читает <data-dir>/dist и замечает изменения в течение минуты; Перечитать папку на странице «Обновления» читает её сразу. Учитываются только обычные файлы (символьные ссылки не открываются). Меняйте пакет целиком; замена пакета во время раскатки ставит раскатку на паузу. Сошлась ли подпись, показывает карточка Пакет релиза: см. Обновления.

Смена ключа релиза#

  1. Создайте новый ключ командой mistgate release keygen и задайте его открытую половину в MISTGATE_RELEASE_PUBLIC_KEY (или в своём RELEASE_KEY).
  2. Все установленные агенты доверяют только старому ключу: один раз обновите каждую ноду вручную агентом, собранным с новым ключом, как старый агент (см. «Старые агенты: один раз вручную» в разделе Обновления).
  3. Панель устанавливает релизы панели только под вшитым в неё ключом, а это всё ещё старый: замените бинарник панели вручную на собранный с новым ключом.
  4. Новая панель пишет в журнал release key mismatch и не доверяет ни одному пакету. На сервере панели выполните mistgate release trust-key (от root или пользователя службы панели, с --data-dir, если каталог данных не /var/lib/mistgate): команда запишет новый ключ в release.pub и напечатает старый и новый отпечатки. Перезапустите панель.

Ключ, подменённый кем-то в release.pub, никогда не заставит панель доверять другому подписанту: ключом установки может стать только ключ, вшитый в бинарник, и только через trust-key.

Править страницу на GitHub