Перейти к содержанию

Секреты, пользователи и права

У приложения появились база и изменения схемы. Значит, теперь важны не только файлы, но и права отдельных участников. Издатель доставляет код, процесс обслуживает запросы, администратор меняет систему, а миграция изменяет таблицы. Если всем выдать одну административную учётную запись, любое обычное действие получит больше возможностей, чем ему нужно.

В этом уроке уточним границы release-lab. Никаких настоящих ключей и паролей в примерах нет. Рассмотрим их расположение и право использования. Это часть обычной подготовки выпуска: секрет не должен попадать в публичный архив, а приложению не требуется менять собственный код ради записи загруженного файла.

Разделить возможности, а не только имена

У статического publisher есть право готовить каталоги выпусков. Nginx читает публичные файлы. У releaseapp есть право исполнять прикладной код и писать только в согласованные постоянные или временные каталоги. Администратор устанавливает пакеты и системные настройки. Имена сами по себе не создают ограничений: если releaseapp может через sudo выполнить любую команду без пароля, отдельная учётная запись мало меняет последствия ошибки приложения.

В базовом дереве каталог кода принадлежит издателю, а процесс приложения получает чтение и проход. Для uploads выделяют отдельное место, принадлежащее прикладной роли. Эта папка не должна исполняться как PHP или попадать внутрь сменяемого образа. Временные файлы могут жить в /tmp или отдельном ограниченном каталоге; они не являются резервным источником постоянных данных.

Учебное разделение
publisher: готовит releases/, выбирает выпуск установленным способом
www-data: читает статическое public/
releaseapp: читает код, пишет только разрешённые данные
роль миграции: меняет согласованную схему базы
роль приложения в БД: выполняет необходимые прикладные операции

Это модель прав, которую затем проверяют фактическими владельцами и разрешениями. Разрешение прохода требуется по всему пути к файлу. Один неверный родительский каталог способен дать 403 при правильных правах самого HTML. Не следует исправлять такую ошибку общим chmod 777: сначала находят недоступное звено и дают нужной роли конкретную возможность.

Секрет относится к окружению

Пароль базы, ключ API и закрытый ключ подключения не нужны в публичном дереве. Для systemd мы предусмотрели /etc/release-lab/app.env. Его может читать управляющий менеджер, который передаёт переменные процессу; открывать файл всем локальным пользователям не требуется. Если приложение самостоятельно читает отдельный файл секрета, права согласуются с его пользователем, а не копируются из другого сценария.

sudo install -d -o root -g root -m 0700 /etc/release-lab
sudo install -o root -g root -m 0600 prepared-app.env \
  /etc/release-lab/app.env

Листинг предполагает уже подготовленный непубличный файл с реальными значениями на будущем стенде. Значения в статье не представлены и команды не выполнялись. Файл переменных не является произвольным shell-скриптом: его синтаксис должен соответствовать использующему механизму. Передача через переменные удобна, но не скрывает секрет от самого процесса и уполномоченных администраторов машины. Поэтому дополнительно ограничивают права и журналирование.

Секреты в Compose

В прошлом уроке пароль PostgreSQL подключался как Compose secret из файла. Сервис получает доступ только к объявленному секрету, а путь в контейнере отличается от пути хоста. Такой механизм упрощает разграничение, но не создаёт автоматически внешнее зашифрованное хранилище на любой машине. Сам исходный файл всё ещё нужно хранить с подходящими правами и включить в защищённый план восстановления. Документация секретов Docker Compose.

Официальный образ PostgreSQL создаёт пользователя из POSTGRES_USER с высокими начальными полномочиями. В нашем учебном примере release_lab нужен для инициализации и административных упражнений, а не как рекомендуемый пользователь веб-приложения. Для постоянной работы создают отдельную роль с необходимыми правами на таблицы. Владелец схемы или роль миграции выполняет изменения, которые обычному обработчику запросов не нужны. Поведение официального образа PostgreSQL.

Пример SQL ниже показывает только идею чтения для условного публичного каталога. Пароль и права записи определяются отдельно по реальным функциям приложения. Если оно должно редактировать статьи, добавляют согласованные операции и права на последовательности, а не оставляют ему полномочия всего кластера. Не следует представлять минимальный фрагмент как законченный проект авторизации.

CREATE ROLE release_reader LOGIN;
GRANT CONNECT ON DATABASE release_lab TO release_reader;
GRANT USAGE ON SCHEMA public TO release_reader;
GRANT SELECT ON articles TO release_reader;

Переменные CI и их границы

В GitLab секреты могут храниться как переменные с ограничением окружения, защищённым доступом и маскированием. Эти свойства решают разные задачи. Маскирование помогает не показывать подходящие значения в обычном журнале, но не препятствует коду задания отправить секрет наружу или изменить его представление. Поэтому нельзя давать production-доступ любому конвейеру из неизвестного изменения и рассчитывать только на скрытые звёздочки. Официальная документация переменных GitLab CI.

Задание упаковки из седьмого урока вообще не нуждается в пароле сервера. Доступ появляется только у отдельно разрешённой публикации. Для неё полезен собственный ключ с ограниченным назначением и известным отпечатком сервера. Автоматическое принятие любого host key устраняет проверку узла и может направить артефакт вместе с учётными данными не туда. Предварительно проверенный ключ сохраняют как часть конфигурации окружения.

Что делать при ошибочном раскрытии

Если секрет попал в журнал или историю Git, удаление строки не возвращает конфиденциальность уже полученной копии. Нужно отозвать или заменить значение и проверить, какие компоненты используют его. Для смены пароля или ключа иногда требуется переходный период двух значений: новый доступ подключают, проверяют, затем прекращают старый. Конкретный способ зависит от сервиса; его нельзя заменить универсальной командой редактирования файла.

В журналах приложения не выводят всю среду для удобства диагностики. Достаточно названия отсутствующей настройки или безопасного признака подключения. Отчёт об инциденте может сохранять идентификатор ключа и момент ротации без самого значения. Это помогает разбору и не создаёт новую копию секрета. Архив резервирования с настройками получает соответствующие ограничения и понятного владельца восстановления.

Проверить возможности на практике

На будущем стенде проверяют ожидаемые отказы: прикладной пользователь не меняет каталог кода, издатель не читает несвязанные секреты, публичный HTTP не отдаёт файл настроек. Проверка только успешных действий не показывает границу. При этом команды не запускаются в ходе написания курса: результатом здесь является согласованная модель и примеры. Следующий урок добавит ещё одну границу — право конвейера выбрать выпуск при конкурирующих и устаревших заданиях.