Релизы и подпись
Для мейнтейнеров и для тех, кто собирает 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 доверенного агента.
Сделайте ключ (один раз)#
mistgate release keygen --out ~/mistgate-release.keyКоманда пишет закрытый ключ в файл (режим 0600; существующий файл никогда не перезаписывается) и печатает открытый ключ и его отпечаток (первые 16 шестнадцатеричных символов его SHA-256).
храните файл ключа офлайн и сделайте резервную копию. Без него ни одну ноду нельзя обновить из панели: придётся сделать новый ключ, собрать с ним новые бинарники и один раз обновить вручную каждую ноду и панель.
Соберите с открытым ключом#
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 предложит релиз панели.
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=falserelease 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: их подписи не сходятся с её ключом. Обновления нод она получает из пакета, который вы подписываете и копируете в её каталог данных, а бинарник панели вы меняете вручную (см. «Ранние сборки и ручное обновление» в разделе Обновления).
Подпишите бинарники нод#
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, кладёт рядом копии бинарников, перечитывает результат и проверяет его, затем печатает версию, срок действия, каждый файл с размером и отпечаток ключа.
Положите пакет на панель#
scp dist/* panel.example.com:/var/lib/mistgate/dist/Панель читает <data-dir>/dist и замечает изменения в течение минуты; Перечитать папку на странице «Обновления» читает её сразу. Учитываются только обычные файлы (символьные ссылки не открываются). Меняйте пакет целиком; замена пакета во время раскатки ставит раскатку на паузу. Сошлась ли подпись, показывает карточка Пакет релиза: см. Обновления.
Смена ключа релиза#
- Создайте новый ключ командой
mistgate release keygenи задайте его открытую половину вMISTGATE_RELEASE_PUBLIC_KEY(или в своёмRELEASE_KEY). - Все установленные агенты доверяют только старому ключу: один раз обновите каждую ноду вручную агентом, собранным с новым ключом, как старый агент (см. «Старые агенты: один раз вручную» в разделе Обновления).
- Панель устанавливает релизы панели только под вшитым в неё ключом, а это всё ещё старый: замените бинарник панели вручную на собранный с новым ключом.
- Новая панель пишет в журнал
release key mismatchи не доверяет ни одному пакету. На сервере панели выполнитеmistgate release trust-key(от root или пользователя службы панели, с--data-dir, если каталог данных не/var/lib/mistgate): команда запишет новый ключ вrelease.pubи напечатает старый и новый отпечатки. Перезапустите панель.
Ключ, подменённый кем-то в release.pub, никогда не заставит панель доверять другому подписанту: ключом установки может стать только ключ, вшитый в бинарник, и только через trust-key.