Что означает ошибка Permission denied в cron
Когда планировщик задач пытается запустить ваш скрипт, ядро Linux отклоняет запрос с сообщением /bin/sh: 1: /путь/к/скрипту: Permission denied и кодом выхода 126. Это стандартная реакция системы на отсутствие необходимых прав доступа, неверного владельца или блокировку модулями безопасности (SELinux/AppArmor).
Обычно ошибка появляется в системных логах (/var/log/syslog или /var/log/cron) либо приходит на почту пользователя cron, если настроен вывод. Задача не выполняется, а вы теряете данные или пропускаете резервное копирование без явного уведомления в консоли.
Причины возникновения
- Отсутствует бит исполнения. Файл был загружен, скопирован или создан с правами
644(-rw-r--r--), что разрешает только чтение. - Несоответствие владельца. Скрипт принадлежит
root, а задача добавлена в crontab обычного пользователя, или наоборот. - Использование относительных путей. Cron запускает команды из домашней директории пользователя, не инициализируя переменную
$PATH. Символ~или./в расписании не сработают. - Блокировка SELinux или AppArmor. В корпоративных дистрибутивах политики безопасности строго контролируют запуск исполняемых файлов из нестандартных каталогов.
- Скрипт находится в защищённой файловой системе. Раздел смонтирован с флагом
noexec(часто встречается в/tmpили/home).
Способы решения
Способ 1: Корректировка прав и владельца
Сначала убедитесь, что файл действительно является исполняемым и принадлежит тому пользователю, под которым работает cron.
- Проверьте текущие права:
ls -l /opt/scripts/my_task.sh - Если бит
xотсутствует, добавьте его:chmod +x /opt/scripts/my_task.sh - Измените владельца на учётную запись, от имени которой выполняется задача:
sudo chown username:username /opt/scripts/my_task.sh
💡 Совет: Для системных задач, добавленных через
sudo crontab -e, оставляйте владельцемroot. Для пользовательских задач используйте обычного пользователя.
Способ 2: Явный вызов интерпретатора и абсолютные пути
Даже при правильных правах cron может не найти исполняемый файл или зависимости. Всегда указывайте полные пути.
Откройте редактор crontab:
crontab -e
Замените строку вида:
*/5 * * * * ./backup.sh
На:
*/5 * * * * /usr/bin/bash /opt/scripts/backup.sh >> /var/log/backup_cron.log 2>&1
Перенаправление вывода в лог поможет отследить дальнейшие ошибки без захламления почты.
Способ 3: Проверка и настройка политик безопасности
Если права выставлены верно, но ошибка сохраняется, проверьте, не блокирует ли выполнение модуль безопасности.
Для SELinux (RHEL/CentOS/Fedora):
- Убедитесь в статусе модуля:
sestatus - Найдите блокировки за последние 10 минут:
ausearch -m AVC -ts recent - Если в выводе есть
denied { execute }для вашего скрипта, разрешите выполнение:
Для постоянного применения используйтеsudo chcon -t bin_t /opt/scripts/my_task.shsemanage fcontextиrestorecon.
Для AppArmor (Ubuntu/Debian):
- Проверьте статус профиля:
sudo aa-status - Если скрипт попадает под строгий профиль, добавьте исключение в
/etc/apparmor.d/local/usr.bin.cronили переведите профиль в режим жалоб (complain):sudo aa-complain /usr/bin/cron
Способ 4: Запуск через run-parts или оболочку sh
Иногда проще не менять права, а передать скрипт оболочке, которая сама обработает выполнение. Это особенно полезно, если файл размещён на сетевом диске или в /tmp.
*/10 * * * * /bin/sh /tmp/temp_script.sh
Или используйте стандартную утилиту run-parts для каталогов:
0 * * * * /usr/bin/run-parts /etc/cron.hourly
Этот метод автоматически применяет стандартные политики запуска и упрощает аудит задач.
Профилактика
Чтобы ошибка не возвращалась, придерживайтесь нескольких простых правил при настройке автоматизации:
- Храните скрипты в выделенных каталогах, например
/opt/scripts/или/usr/local/bin/, где права наследуются предсказуемо. - Добавляйте в начало каждого скрипта
#!/usr/bin/env bashили#!/bin/sh, чтобы система точно знала, какой интерпретатор использовать. - Не монтируйте каталоги с флагом
noexec, если в них планируются автоматические запуски. - Регулярно проверяйте логи планировщика:
sudo journalctl -u cron -fилиsudo journalctl -u crond -f. - Перед добавлением в расписание всегда тестируйте команду вручную от имени того пользователя, под которым она будет работать:
su - username -c "/usr/bin/bash /opt/scripts/test.sh".