Permission denied при доступном файле: проверяем права каталогов по пути
У конфигурации стоит режим 644: читать может любой пользователь. Но приложение под systemd всё равно получает Permission denied. Проверка только последнего файла пропускает важную часть доступа: ядру сначала нужно пройти через каждый каталог по пути.
Для каталога бит x означает право поиска и прохода к известному имени. Бит r позволяет читать список имён. Это разные действия. Можно знать точный путь к файлу и читать его без права перечислить весь каталог, если проход разрешён. И наоборот, список имён может быть виден, но открыть вложенный объект без x не получится.
Посмотрим путь целиком
namei -l /srv/releases/current/config/app.yaml
id app
sudo -u app test -r /srv/releases/current/config/app.yaml
printf 'readability status=%s\n' "$?"
Имена app и путь здесь пример. namei показывает компоненты пути с владельцами и правами, включая встреченные символические ссылки. Найдите первый каталог, через который пользователь сервиса не может пройти. id показывает группы учётной записи, а test проверяет доступ в выбранном пользовательском контексте.
Ненулевой статус test сам по себе не называет виновный компонент. Он подтверждает воспроизведение отказа для этого пользователя. Выполняйте проверку без последующей команды между test и чтением $?, иначе напечатаете чужой статус. Также учитывайте, что sudo-проверка не воспроизводит все sandbox-ограничения unit.
Разберём типичный случай
Пусть /srv/releases принадлежит deploy и имеет 700. Вложенный app.yaml с режимом 644 недоступен app, поскольку чужой пользователь не проходит через releases. Изменение прав самого app.yaml ничего не даст. Нужно согласовать доступ к каталогу: через подходящую группу, ACL или другую структуру размещения.
Не расширяйте права всего дерева командой chmod -R 777. Помимо лишнего доступа, такая команда меняет режимы объектов с разными назначениями: конфигурации, приватных ключей и исполняемых файлов. Исправление должно соответствовать конкретному действию пользователя и конкретному компоненту пути.
Для создания нового файла нужны права записи и поиска в родительском каталоге. Право записи на уже существующий файл решает другую операцию. Переименование и удаление также связаны с каталогом и могут зависеть от sticky bit. Поэтому сначала установите, что именно делает приложение: читает, создаёт, заменяет через rename или удаляет.
Проверим ACL и реальную идентичность процесса
getfacl /srv/releases systemctl show myapp.service -p User -p Group -p SupplementaryGroups ps -o pid,user,group,comm -p 1234
PID 1234 замените действующим процессом. ACL может добавлять права или ограничивать эффективные разрешения через mask. Поэтому одних девяти битов из ls иногда недостаточно. Сравните владельца, группу, ACL и набор групп процесса, а не только текущей интерактивной сессии администратора.
Если учётную запись недавно добавили в группу, уже запущенный процесс может продолжать работать со старым набором групп. Сначала установите его фактический контекст, затем планируйте штатный перезапуск. Проверка id из нового терминала не доказывает, что работающий сервис получил те же группы.
Если обычные права подходят
Проверьте, видит ли сервис тот же путь. RootDirectory, private mount namespace, ProtectHome и InaccessiblePaths способны менять доступную часть файловой системы. Символическая ссылка current может вести в место, закрытое для сервиса. В контейнере также важно соответствие UID/GID на volume.
Отказ могут дополнительно задавать SELinux или AppArmor. Для них ищите соответствующее сообщение в журнале и проверяйте политику для конкретного пути и операции. Увеличение обычных Unix-прав не исправляет автоматически отдельный запрет. Не отключайте политику целиком ради подтверждения догадки на рабочем сервере.
После узкого исправления повторите исходное действие приложения и чтение от его пользователя. Открытие файла администратором не служит критерием успеха. Когда вы связали операцию, путь и идентичность процесса, Permission denied превращается из загадочного сообщения в конкретную проверку доступа.
Ещё по теме
- No space left on device при свободном месте: проверяем inode
- Bash-скрипт сообщил об успехе после ошибки: код возврата и pipefail
Продолжить изучение
Хотите перейти от отдельных команд к сопровождению Linux-серверов? Работа с системой, скриптами и сервисами входит в программу «Linux и Bash для DevOps-инженеров».
Продолжить на практике
- Linux и Bash для DevOps-инженеров ↗
Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.
