От японского 降ろす (órosu) — «разгружать», «сгружать».
Проблема
CI-системы хорошо справляются со сборкой ПО и плохо — с его доставкой. Перенос артефакта сборки из пайплайна на продакшн-машину обычно сводится к одному из нескольких привычных, но хрупких паттернов:
- Приватные SSH-ключи, скопированные в секреты CI и разбросанные по каждому пайплайну и репозиторию, которому нужен деплой
- SFTP/rsync-скрипты, скопированные из одного проекта в другой, каждый со своими небольшими багами
- Захардкоженные пути и права доступа, которые ломаются при малейшем изменении структуры сервера
- Продакшн-машины, напрямую доступные для CI-раннеров, расширяющие поверхность атаки с каждым новым пайплайном
- Разрастание секретов, из-за которого ротация одного скомпрометированного ключа превращается в аудит всех репозиториев, которые могли на него ссылаться
Это не специфично для какой-то одной CI/CD-платформы — это стандартная форма задачи «выполнить скрипт на удалённой машине из пайплайна», и риски накапливаются с каждым проектом, который её перенимает.
Как Orosu решает эту задачу
Orosu устанавливается один раз на целевой машине как orosu-server и превращает деплой из открытой SSH-сессии в ограниченный, аутентифицированный запрос:
- CI собирает приложение — бинарник, образ контейнера, статические файлы — что бы ни производил пайплайн
- CI запускает задачу через соединение WebSocket, при необходимости прикладывая файлы
orosu-serverаутентифицирует запрос с помощью подписей Ed25519 — без паролей и общих секретов в передачеorosu-serverвыполняет заранее заданный скрипт — один из фиксированного набора, настроенного на сервере, а не произвольную команду от CI- Скрипт выполняет деплой, используя файлы и аргументы, приложенные к задаче
Никакого прямого SSH, никакого жонглирования учётными данными по пайплайнам и никакой серверной поверхности за пределами конкретных скриптов, явно настроенных оператором.
Установка
orosu-server и сопутствующий CLI orosu-keygen поставляются как пакеты для Debian/Ubuntu из apt-репозитория:
curl -fsSL https://packages.nerdy.pro/NerdyPro.gpg | sudo gpg --dearmor -o /usr/share/keyrings/nerdy-pro.gpg
echo "deb [signed-by=/usr/share/keyrings/nerdy-pro.gpg] https://packages.nerdy.pro/ stable main" | sudo tee /etc/apt/sources.list.d/nerdy-pro.list
sudo apt update
sudo apt install orosu
GitHub Releases также публикует готовые бинарники orosu-server и orosu-keygen напрямую — для машин, на которые нельзя добавить apt-репозиторий.
Быстрый старт
Сгенерируйте пару ключей клиента с помощью orosu-keygen, находясь в /etc/orosu:
orosu-keygen --name my-ci-client --private-key-output my-ci-client.key --public-key-output my-ci-client.pub
Публичный ключ идёт в конфиг сервера; приватный становится секретом CI.
Настройте сервер в /etc/orosu/orosu-server.toml — адрес прослушивания и публичный ключ клиента:
listen:
tcp: "127.0.0.1:8081"
clients:
- name: my-ci-client
secret_file: /etc/orosu/my-ci-client.pub
Сервер, слушающий localhost, обычно стоит за обратным прокси, который терминирует TLS и пробрасывает апгрейды WebSocket — в README приведена конфигурация nginx для этого случая.
Определите скрипт, который клиенту разрешено запускать:
#!/bin/bash
echo "Hello, $1!"
clients:
- name: my-ci-client
secret_file: /etc/orosu/my-ci-client.pub
scripts:
- name: test-script
command:
- "bash"
- "/etc/orosu/scripts/test.sh"
Запустите его из CI с помощью сопутствующего GitHub Action, передав адрес сервера и приватный ключ клиента через секреты:
- name: Remotely execute a script
uses: orosu-ci/orosu@v0
with:
address: ${{ secrets.OROSU_SERVER_URL }}
script: test-script
key: ${{ secrets.OROSU_CLIENT_KEY }}
arguments: "from CI pipeline"
Сквозное шифрование
WSS/:termTLS защищает соединение, но когда TLS терминируется на обратном прокси перед orosu-server — а это стандартная схема выше — аргументы скрипта, загруженные файлы и потоковый вывод остаются открытым текстом на этом прокси. Опциональное рукопожатие сквозного шифрования (X25519 + HKDF-SHA256 + ChaCha20-Poly1305) закрывает этот разрыв:
orosu-keygen --kind server --private-key-output server.key --public-key-output server.pub
Публичный ключ сервера добавляется в его конфиг и передаётся в CI как входной параметр server_key экшена. Переход опционален и аддитивен с обеих сторон независимо — сервер с настроенным шифрованием по-прежнему обслуживает клиентов, не передающих server_key, точно так же, как раньше, и скоординированного обновления не требуется.
Безопасность
Безопасность — требование первого класса при проектировании, а не запоздалая мысль:
- Криптографическая аутентификация — каждая задача подписывается ключом Ed25519 клиента; в канале нет ни пароля, ни общего секрета, который мог бы перехватить атакующий.
- Закрытый набор действий — CI может запускать только те скрипты, которые оператор явно задал на сервере. Пути от задачи CI к произвольной команде оболочки не существует.
- Защищённая обработка вложений — имена записей в zip проверяются на обход путей, а количество записей и суммарный размер после распаковки ограничены, поэтому специально сформированное или чрезмерно большое вложение не может выйти за пределы каталога извлечения или исчерпать диск.
- Многоуровневое шифрование — опциональное рукопожатие сквозного шифрования проверяет атаку low-order-point на обмене X25519 в дополнение к уже обеспечиваемой конфиденциальности.
- Безопасные права доступа по умолчанию —
orosu-keygenзаписывает файлы приватных ключей с правами0600независимо от текущего umask.
Эти механизмы вошли в релиз 0.7.0 как обновление, не требующее дополнительных действий — без изменений конфига, CLI или протокола. Полную историю релизов см. в CHANGELOG.md.
Лицензия
Orosu распространяется под лицензией Apache-2.0.