Secrets management с SOPS + age
Пошаговый guide по безопасному хранению и расшифровке секретов в git с помощью SOPS и age. Окончательный результат — зашифрованный репозиторий, готовый к CI, за 30–60 минут.
Статья была полезной?
Пошаговый guide по безопасному хранению и расшифровке секретов в git с помощью SOPS и age. Окончательный результат — зашифрованный репозиторий, готовый к CI, за 30–60 минут.
Статья была полезной?
Хранение паролей, токенов и приватных ключей прямо в репозитории приводит к рискам: утечки, ненамеренные коммиты и сложность ротации. Git сохраняет историю, и даже если удалить секрет, он останется в коммитах. SOPS (Mozilla) + age (filippo.io) предлагают простой, проверяемый и удобный для CI способ шифрования файлов, который совместим с git и не требует выделенного сервера.

Схема: разработчик шифрует секреты с sops и age, CI расшифровывает и деплоит
Подход sops+age делает файлы в репозитории безопасными: ключи age хранятся отдельно, а sops добавляет метаданные. Это минимизирует blast radius при утечке репозитория и упрощает ротацию ключей.
Команды ниже подходят для Ubuntu 22.04 и macOS 13. Устанавливайте sops 3.8.2 (релиз 2026). Ожидаемое время установки: 5–20 секунд для скачивания бинарника + 2–5 секунд на установку.
# Ubuntu (bash)
curl -L -o /usr/local/bin/sops https://github.com/ProtonMail/sops/releases/download/v3.8.2/sops-v3.8.2-linux-amd64
chmod 0755 /usr/local/bin/sops
sops --versionПояснение: команда скачивает предварительно собранный бинарник v3.8.2, устанавливает права и проверяет версию.
Ожидаемый вывод (успех):
sops 3.8.2Типовая ошибка:
curl: (22) The requested URL returned error: 404Причина и исправление: URL устарел или версия недоступна. Проверьте страницу релизов https://github.com/ProtonMail/sops/releases и используйте корректную ссылку. На macOS используйте Homebrew: brew install sops@3.8.2 или скачайте sops-v3.8.2-darwin-amd64.

Скриншот терминала установки sops 3.8.2 с выводом sops 3.8.2
Age — простая современная альтернатива PGP для шифрования. Установите age 1.0.0 (релиз 2025). Генерация ключей занимает 1–2s. Пример ниже создаст локальную пару ключей для разработчика и публичный ключ для CI.
# Установка age на Ubuntu
curl -L -o /usr/local/bin/age https://github.com/FiloSottile/age/releases/download/v1.0.0/age-v1.0.0-linux-amd64
chmod 0755 /usr/local/bin/age
age --version
# Генерация ключей
age-keygen -o ~/.config/age/keys.txt
cat ~/.config/age/keys.txtПояснение: age-keygen создаёт приватный ключ и печатает публичную часть в формате age1.... Приватный ключ храните в каталоге с правами 600. Публичный ключ можно загрузить в репозиторий или в настройки CI как секрет.
Ожидаемый вывод (успех):
# ~/.config/age/keys.txt
- type: X25519
name: "default"
public: "age1...public..."
private: "AGE-SECRET-KEY-1..."Типовая ошибка:
age-keygen: command not foundПричина и исправление: age не установлен в PATH. Убедитесь, что /usr/local/bin в PATH: echo $PATH. Перезапустите терминал или укажите абсолютный путь /usr/local/bin/age. На macOS можно установить через Homebrew: brew install age.
Храните приватный ключ age в защищённом месте: локально с правами 600 и/или в hardware token.
Пример использования публичного ключа для шифрования файла с sops:
# Создаём секрет
echo "DB_PASSWORD=supersecret" > prod.env
# Шифруем prod.env для получателя (публичный ключ age)
sops --encrypt --age "age1...public..." --output prod.env.enc prod.env
# Проверка
file prod.env.enc
sops --decrypt prod.env.encОжидаемый вывод (успех):
prod.env.enc: ASCII text
# sops --decrypt prod.env.enc выведет содержимое файла:
DB_PASSWORD=supersecretТиповая ошибка:
sops: error: No usable recipients foundПричина и исправление: неверный или отсутствующий публичный ключ. Убедитесь, что в команде вы используете корректный публичный ключ в формате age1.... Также проверьте версию sops (поддержка age появилась в SOPS 3.x).
Цель: расшифровывать секреты в GitHub Actions runner без хранения приватного ключа в репозитории. Подход: приватный ключ age (или его зашифрованный вариант) хранится как защищённый secret в GitHub и используется только в runtime.
# Пример workflow: .github/workflows/deploy.yml
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install sops & age
run: |
curl -L -o sops https://github.com/ProtonMail/sops/releases/download/v3.8.2/sops-v3.8.2-linux-amd64
chmod +x sops && sudo mv sops /usr/local/bin/
curl -L -o age https://github.com/FiloSottile/age/releases/download/v1.0.0/age-v1.0.0-linux-amd64
chmod +x age && sudo mv age /usr/local/bin/
- name: Restore private key
env:
AGE_PRIVATE_KEY: ${{ secrets.AGE_PRIVATE_KEY }} # храните как GitHub Secret
run: |
mkdir -p ~/.config/age
echo "$AGE_PRIVATE_KEY" > ~/.config/age/keys.txt
chmod 600 ~/.config/age/keys.txt
- name: Decrypt secrets
run: |
sops --decrypt --output prod.env prod.env.enc
- name: Use secrets
run: |
source prod.env
echo "DB_PASSWORD length: ${#DB_PASSWORD}"Пояснение: workflow скачивает заранее указанные версии sops и age, восстанавливает приватный ключ из GitHub Secret и расшифровывает prod.env.enc. Runner ubuntu-22.04 обеспечивает одинаковую среду для всех прогонов. Ожидаемое время выполнения стадии установки — ~10–20 секунд, расшифровка файла — <1s для небольших файлов.
Ожидаемый вывод (успех):
# В логе GitHub Actions увидите:
sops 3.8.2
age 1.0.0
# и строку из шага Use secrets, например:
DB_PASSWORD length: 11Типовая ошибка:
Error: open ~/.config/age/keys.txt: permission deniedПричина и исправление: ключ создан с неверными правами или путь недоступен. Убедитесь, что файл создаётся в шаге с корректными правами: chmod 600 ~/.config/age/keys.txt. Если runner использует ограничённую домашнюю директорию, укажите путь в workspace и установите переменную окружения AGE_KEY_FILE.
SOPS+age — lightweight решение для хранения секретов в git. Vault — полноценный секретный менеджер с динамическими секретами, ротацией и политиками доступа. Выбор зависит от задач:
Когда использовать что:
SOPS+age проще внедрить в существующие pipeline и репозитории: нет отдельной точки отказа, нет необходимости настраивать сеть и ACL, а ротация сводится к выпуску новых ключей age и перепротоколированию файлов.
Ниже — практические сценарии с указанием отличий и рекомендуемых практик.

Таблица сравнения: sops+age vs Vault — характеристики, требования, сценарии
Для хранения секретов приложений в Kubernetes SOPS может применяться совместно с Kustomize или Helm: шифруйте values.yaml и расшифровывайте в CI перед применением манифестов. Для таких сценариев укажите runner с 2 CPU и 4 GB RAM при деплойменте больших кластеров (100+ манифестов).
Если приватный ключ потерян и у вас нет бэкапа, расшифровать файлы, зашифрованные для этого ключа, невозможно. Решение — создавать ключи с несколькими получателями (несколько публичных ключей в метаданных sops), хранить резервные private keys в безопасном бэкапе (например, hardware token или защищённый секретный хранилище). Регулярно проверяйте, что у каждого участника есть действующий публичный ключ и выполните план ротации ключей. При потере ключа без бэкапа придётся перегенерировать новые ключи и перешифровать файлы, потеря старых расшифровок неизбежна.
Оба подхода имеют плюсы и минусы. Отдельные файлы (например, per-service env) упрощают ограничение доступа и ротацию — вы перешифровываете только конкретный файл. Один большой файл удобен для небольших проектов, но повышает blast radius и усложняет ротацию. Для enterprise практик чаще рекомендуют модульную структуру: per-environment, per-service, с привязкой публичных ключей конкретных команд.
Age спроектирован как простая, безопасная и современная альтернатива PGP. У него лаконичный формат ключей, меньше подводных камней в реализации, более простые сценарии использования с sops и CI. PGP остаётся мощным инструментом для сложных цепочек доверия, но age требует меньше ментальных расходов и проще в автоматизации. Для большинства кейсов разработчиков и CI age предоставляет достаточную безопасность при удобстве эксплуатации.
Рекомендуемая практика: ротация приватных ключей не реже чем раз в 6–12 месяцев для продакшн-секретов и при каждом подозрении на компрометацию. План ротации включает: генерацию новой пары age, добавление публичного ключа в sops meta, перешифрование файлов, проверку работоспособности через CI и удаление старого ключа после успешной проверки. Время выполнения ротации — от 10 минут для простого репозитория до нескольких часов для множества сервисов.
Дополнительные материалы по теме и примеры интеграции доступны в разделах: Проекты и Разборы на сайте. Рекомендую сохранять приватные ключи в зашифрованных резервных хранилищах и применять политику least privilege при выдаче доступа в CI.
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…