Как устроено
Секреты
Встроенное шифрованное хранилище, два запасных пути и две вещи, которые обязаны лежать отдельно.
В jobs.yaml не лежит ни одного значения секрета. В нём лежат ссылки —
строки вроде kr://restic/minio-primary, — которые Unruin разрешает ровно в тот
момент, когда они нужны. Именно это делает возможной конфигурацию как код: файл,
описывающий всё ваше устройство копий, безопасно коммитить, читать в diff и
обсуждать.
Ссылки разрешают три схемы.
| Схема | Где лежит значение | Для чего |
|---|---|---|
kr://имя |
собственное шифрованное хранилище Unruin, в каталоге состояния | почти для всего |
env://ИМЯ |
переменная окружения процесса unruin |
аварийный конверт и CI |
file://путь |
файл на диске | секреты, которые кладёт кто-то другой (Docker secrets, примонтированный том) |
Неизвестная схема — жёсткая ошибка, и пустое значение от поставщика тоже. Пути, на котором отсутствующий секрет тихо превращается в пустой пароль, нет.
Встроенное хранилище (kr://)
Способ по умолчанию и причина, по которой Unruin не нужен внешний менеджер секретов.
- Один файл,
secrets.kr, права0600, в каталоге состояния. - Значения зашифрованы AES-256-GCM ключом, выведенным из
UNRUIN_MASTER_PASSPHRASEчерез PBKDF2-HMAC-SHA256, 600 000 итераций. - Имя записи участвует как связанные данные AEAD, поэтому шифротекст нельзя переставить с одного имени на другое внутри файла.
Как заводить записи
Значения читаются из стандартного ввода, а не из командной строки, — чтобы они не попадали ни в список процессов, ни в историю оболочки:
unruin secret set restic/minio-primary # ввести или вставить, затем Ctrl-D
printf %s 'сам-пароль' | unruin secret set restic/minio-primary
unruin secret set ssh/vps-prod-1 < ~/.ssh/id_ed25519_backup
unruin secret ls
unruin secret rm restic/old-repo
Ввод сохраняется дословно, вместе с переводом строки на конце.
echo 'pw' |сохранит четыре символа, а не три, и хранилище потом откажет в пароле без внятной причины. Для пароля беритеprintf %s. Для файла ключа перевод строки на конце как раз уместен, поэтому< keyfile— правильно.
Один секрет, несколько полей
Ссылка может нести #поле:
access: "kr://minio/primary" # разрешается запись целиком
unruin secret set minio/primary#access_key
unruin secret set minio/primary#secret_key
Поле подмешивается в имя при поиске, поэтому один логический доступ — хранилищу S3 нужны и ключ доступа, и секретный ключ — остаётся одной вещью в голове и одной строкой в конфигурации.
Из панели
Когда задана UNRUIN_MASTER_PASSPHRASE, ключ SSH или ключ хранилища можно
вставить прямо в форму сервера или хранилища. Он ляжет зашифрованным, а в
конфигурации останется только ссылка. По значениям секретов API работает только
на запись: сохранённое нельзя прочитать обратно через панель, можно только
заменить или удалить. Когда мастер-фразы нет или хранилище не читается, в панели
висит плашка об этом — вместо того чтобы дать вам печатать в форму, которая тихо
не сработает.
Наименьшие права, если они вам нужны
У хранилища бывает два доступа:
access— доступ, которым Unruin (а для источников-путей и сама цель) пишет;prune_access— необязательный привилегированный доступ, которым пользуется только уборка; он живёт у оркестратора и никогда не уезжает на цель.
Разделение существует, чтобы можно было выдать целям доступ только на
дозапись: тогда взломанный веб-сервер сможет добавлять точки восстановления, но
не сможет удалить историю собственных копий. Не нужен такой размен — не пишите
prune_access, и один access будет делать всё, включая уборку. Это сложность
по желанию, а не по умолчанию.
Две вещи, которые обязаны лежать отдельно
Всё в kr:// зашифровано одной фразой, а зашифрованный файл лежит на той же
машине, что и то, что он защищает. Поэтому:
UNRUIN_MASTER_PASSPHRASE— где-то, где не эта машина.secrets.krс тома состояния — туда же.
Потеряете оба — пропадут все секреты kr://: ключи хранилищ, ключи SSH, доступы
к бэкендам. Потеряете одну фразу — файл станет нечитаемым. Эти две вещи — корень
всего остального, и Unruin их не копирует: средство резервного копирования,
которое хранит ключи от своих копий внутри этих копий, не решило ничего.
Аварийный конверт намеренно лежит не в хранилище
Аварийное хранилище существует для случая, когда потеряны оркестратор, машина и
том состояния. Значит, его ключ обязан жить снаружи kr:// — на env://,
подставляемый из вашего менеджера паролей или с бумажки:
repo_password: "env://BREAKGLASS_RESTIC_PW"
С этим ключом, адресом хранилища и бинарником restic ваши данные достаются вообще без участия Unruin. В этом весь смысл, и это проверено, а не заявлено — см. восстановление без Unruin.
Как менять секрет
- Сохраните новое значение под тем же именем (
unruin secret set …перезаписывает). unruin validate <config> --preflight— он разрешает каждый секрет и действительно соединяется, поэтому криво вставленный ключ упадёт здесь, а не в три часа ночи.- Перезапустите
serve, если процесс что-то держит долго (ключи SSH пишутся на каждый запуск, хранилище читается по требованию).
Для ключа хранилища restic смена — это его собственное управление ключами
(restic key add / restic key remove) на самом хранилище, и потом правка
ссылки. Изменить только ссылку — значит не изменить в хранилище ничего, и Unruin
просто перестанет его открывать.
Где секретов нет
- Не в
jobs.yaml, никогда: API конфигурации принимает только ссылки и отвергает всё, что похоже на значение. - Не в списке процессов: значения читаются со стандартного ввода или из окружения.
- Не в журналах: разрешённое значение — тип, который при печати сам себя затирает.
- Не в оповещениях: сообщение о сбое говорит, какое хранилище и что проверить, а не чем оно пыталось представиться.