Безопасность и изоляция
Где и как исполняется ваш код — и как это проверить.
Ваш CI выполняется на нашей инфраструктуре, и каждый job — в собственной аппаратно-виртуализированной micro-VM. Эта страница описывает, как именно устроена изоляция, сколько живёт окружение job-а и как самостоятельно проверить образ, на котором исполняется ваш код — без звонка в отдел продаж и без NDA.
Обновлено: 2026-09-27 · v1.6
Модель изоляции
Недоверенный CI-код — ваши шаги сборки и всё, что они порождают, включая Docker-in-Docker — сдерживается несколькими независимыми слоями. Главная граница — micro-VM; остальные слои ограничивают, куда job может дотянуться, и делают попытку побега видимой. Это defense-in-depth, а не «доверьтесь контейнеру».
| Слой | Механизм | От чего защищает |
|---|---|---|
| Аппаратная micro-VM | Каждый раннер-под исполняется в собственной micro-VM со своим гостевым ядром, на Kata Containers. micro-VM — это лёгкая виртуальная машина, а не контейнер с общим ядром. | Главная граница. CI-код — и его Docker-in-Docker — не достаёт до ядра хоста и до VM другого job-а. |
| Сеть по умолчанию закрыта | Сеть раннера работает deny-by-default, на уровне ядра через eBPF / Cilium. Раннер не может принимать входящие соединения и не дотягивается внутрь кластера: приватные IP-диапазоны, cloud-metadata endpoint, control plane и соседние поды заблокированы — кроме внутреннего pull-through кеша пакетов и образов. Исходящий трафик идёт в публичный интернет. | Не даёт двигаться по сети вбок, красть cloud-metadata-токены или дотянуться до внутренних сервисов. |
| Нет кластерного токена | У раннера нет токена к оркестратору (Kubernetes API). | Эскалации привилегий не на что опереться: даже с root внутри VM у job-а нет кластерного токена, чтобы расширить доступ. |
| Привилегии нагрузки | Как на GitHub-hosted, job работает от не-root пользователя runner с беспарольным sudo, то есть имеет полный root внутри своей micro-VM — как и движок Docker-in-Docker. Эта привилегия заканчивается на границе VM: ни устройств, namespace’ов и монтирований хоста, ни кластерных учётных данных. | Root остаётся внутри собственной VM job-а, вдали от хоста. |
| Разделение по нодам | Раннеры работают на выделенных runner-хостах, физически отдельно от control plane, секретов и данных платформы. | Ограничивает радиус поражения: скомпрометированный job — далеко от control plane и данных других клиентов. |
| Runtime-детекция угроз | На хостах работает runtime-детекция через eBPF / Tetragon: она отслеживает активность, которая указывала бы на выход из VM на хост. | Попытка побега становится видимым, зафиксированным событием, а не проходит незаметно. |
Мы называем примитивы и объясняем, зачем каждый, но не публикуем стоящие за ними политики, allowlist’ы, версии или топологию. Компоненты держим на актуальном security-floor — конкретные номера версий намеренно не публикуются, поскольку версия маппится на известный набор CVE.
Эфемерность как дизайн
Окружение job-а не переживает сам job.
- Один job — одна свежая VM. Каждый job получает только что созданную micro-VM. Эфемерность означает, что она существует только для этого job-а.
- Уничтожается по завершении. Когда job завершается, VM и всё её содержимое — чекаут кода, окружение, любые секреты, которые в неё попали — уничтожаются.
- Без переиспользования между клиентами. VM никогда не передаётся от одного job-а к следующему. Нет «тёплого» окружения, из которого следующий job мог бы унаследовать остаточный код, кеши или секреты (общий pull-through-кеш — только публичные пакеты и образы).
Граница job-а — это граница доверия.
Supply chain, который можно проверить
Образ, на котором исполняется ваш код, собирается в публичном CI и проверяется независимо — и вам не нужно верить на слово, что внутри.
Бейджи ведут на живые аттестации и Scorecard; подпись, provenance и SBOM проверяются командами ниже.
Неизменяемые образы. Неизменяем digest, а не тег: vYYYYMMDD и sha-<commit> могут переводиться пересборкой, а digest’ы без тега со временем удаляются — поэтому закрепляйте vYYYYMMDD@sha256:. На нашей стороне парк раннеров закреплён на конкретный digest, а его подпись и provenance проверяются перед каждой сменой пина.
Каждый образ, собранный из main, подписан cosign keyless (Sigstore — Fulcio + Rekor, через GitHub Actions OIDC) и несёт SLSA build provenance и CycloneDX SBOM-аттестацию. Подпись накладывается только после того, как опубликованный по digest артефакт прошёл trivy-гейт: сборка блокируется на устранимых HIGH/CRITICAL-уязвимостях в пакетах ОС — то есть валидная подпись означает, что образ прошёл CVE-гейт. Образ пересобирается еженедельно со свежими apt-патчами; базу и инструменты обновляет Renovate; раннеры переводятся на новый digest после проверки подписи.
Образ: ghcr.io/tempusbuild/runner-ubuntu-24.04 — теги по дате, без плавающего :latest. На каком образе прошёл job, видно в его логе: Set up job → Runner Image → Version: vYYYYMMDD. Работайте по @sha256:-digest, а не по тегу:
IMAGE=ghcr.io/tempusbuild/runner-ubuntu-24.04
DIGEST=$(docker buildx imagetools inspect "${IMAGE}:vYYYYMMDD" --format '{{.Manifest.Digest}}')
1. Подпись — привязывает образ к нашему build-workflow и к OIDC-issuer’у GitHub. Любая другая identity — не наша сборка:
cosign verify \
--certificate-identity-regexp '^https://github\.com/tempusbuild/runner-images/\.github/workflows/build\.yml@refs/heads/main$' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
"${IMAGE}@${DIGEST}"
2. Build provenance — Sigstore-подписанная SLSA-аттестация, проверяется через gh CLI:
gh attestation verify "oci://${IMAGE}@${DIGEST}" --owner tempusbuild
3. SBOM (CycloneDX) — cosign-аттестация на тот же digest. SBOM слишком велик для transparency-log, поэтому таймстемпится TSA (RFC3161), а не логируется в Rekor; поэтому проверка пропускает Rekor-lookup, но всё равно проверяет identity, подпись и доверенный таймстемп:
cosign verify-attestation \
--type cyclonedx \
--insecure-ignore-tlog \
--use-signed-timestamps \
--certificate-identity-regexp '^https://github\.com/tempusbuild/runner-images/\.github/workflows/build\.yml@refs/heads/main$' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
"${IMAGE}@${DIGEST}"
--insecure-ignore-tlog отключает только Rekor-lookup; подпись, identity подписи и RFC3161-таймстемп по-прежнему проверяются. Подпись из шага 1 — криптографический якорь; provenance и SBOM привязаны к тому же digest.
Подпись и provenance записываются в публичный transparency-log Rekor (открывается в новой вкладке). Полный разбор и нашу CVE-политику (открывается в новой вкладке) см. в SECURITY.md репозитория runner-images; build-workflow (открывается в новой вкладке) и весь репозиторий открыты на github.com/tempusbuild/runner-images (открывается в новой вкладке).
Данные и tenancy
- Расположение. Compute — bare-metal-серверы в ЕС (Hetzner, Финляндия); бэкапы хранятся в ЕС.
- Секреты зашифрованы. Секреты Kubernetes зашифрованы at rest в хранилище кластера, операционные учётные данные зашифрованы через age (sops) и никогда не попадают в Git в открытом виде.
- В транзите. Дашборд и API отдаются по TLS (Let’s Encrypt), с HSTS. Внутренние endpoint’ы метрик и health недоступны из публичного интернета.
- Секретам вашего CI неоткуда у нас утечь. Мы их не получаем и не храним: GitHub доставляет их напрямую в micro-VM вашего job-а, которая уничтожается по его завершении.
- Just-in-time-токены job-а. Раннер получает только короткоживущий per-job registration-токен. Постоянного платформенного токена на раннере нет.
- Данные арендаторов. Данные платформы — история job-ов, балансы, ledger — изолированы по арендаторам, так что данные одного клиента недоступны из контекста другого.
- Хранение и удаление. Биллинговые записи и ledger хранятся установленный законом срок; метаданные job-ов — пока активен аккаунт. Сессии истекают через 30 дней неактивности (не позже 90). Удаление аккаунта и псевдонимизация персональных данных — по запросу; записи, обязательные по закону, сохраняются без привязки к личности.
- Восстанавливаемые бэкапы. База непрерывно бэкапится с point-in-time recovery и окном хранения 30 дней.
Compliance и аудиты
Мы указываем, что есть сегодня и что в роадмапе, — и ничего, чего не заслужили.
Доступно сейчас
- Проверяемый supply chain — подписанные образы, SLSA provenance и SBOM, которые можно проверить самостоятельно (выше).
- Открытые образы раннеров — окружение исполнения публично и читаемо.
- Опубликованная политика раскрытия уязвимостей (ниже).
- Публичная статус-страница — доступность сайта и история инцидентов на status.tempus.build; мониторинг дашборда и раннеров добавляем.
В роадмапе
- Независимый аудит изоляции — сторонний пентест модели изоляции.
- SOC 2 — работаем над ним.
Мы не сертифицированы по SOC 2 или эквиваленту на сегодня. Claim’ы на этой странице — те, что вы можете проверить напрямую уже сейчас. Отчёты об аудитах, когда появятся, предоставляются под NDA:
Запросить security-отчёт — на этой странице нет lead-capture формы.
Ответственное раскрытие
Нашли уязвимость в платформе, образах раннеров или supply-chain-пайплайне? Сообщите ответственно:
- Email: security@tempus.build
- security.txt: tempus.build/.well-known/security.txt (RFC 9116)
- Образы раннеров: приватно через GitHub Security Advisories в tempusbuild/runner-images (открывается в новой вкладке)
Пожалуйста, не открывайте публичный issue по неисправленной уязвимости. Мы подтвердим получение и будем держать вас в курсе триажа и фикса.
Субпроцессоры
Мы используем небольшое число сторонних обработчиков для работы сервиса. Персональные данные обрабатываются только в объёме, нужном для его предоставления.
| Субпроцессор | Назначение | Расположение |
|---|---|---|
| Hetzner | Compute и бэкапы | ЕС |
| GitHub | Исходный код, identity (OAuth / GitHub App), доставка CI-секретов | США |
| Mailgun | Транзакционная почта и уведомления | ЕС |
| DodoPayments | Обработка платежей (merchant of record) | США |
| Аналитика сайта (Google Analytics): до вашего выбора — агрегированные сигналы без cookie; cookie — только с согласия | США | |
| Yandex | Аналитика сайта (Yandex Metrica), только с вашего согласия | Россия |
| Sentry | Мониторинг ошибок: стек ошибок и GitHub id/login; без email и IP | ЕС (Германия) |
| OpenRouter (→ Anthropic) | LLM-инференс для AI-советника по расходам (включён для всех) — получает агрегированные метрики расходов, имена репозиториев/workflow и текст вопроса, если вы его задаёте; без исходного кода, секретов и данных пользователей | США |
Список версионируется; существенные изменения отражаются здесь с датой ревизии выше.