When a user account is configured with /usr/sbin/nologin or /bin/false as their shell in /etc/passwd, standard methods like su or sudo fail because these shells prevent interactive login. However, system services and cron jobs routinely execute commands as such users - so how do they bypass this restriction?
The most straightforward solution is to force a valid shell during command execution:
su -s /bin/bash testuser -c "/path/to/script.sh"
Key parameters:
-s /bin/bash: Temporarily overrides the nologin shelltestuser: Target user account-c: Command to execute
For systems with sudo configured, you can use:
sudo -u testuser /bin/bash -c "/path/to/script.sh"
This approach is particularly useful when you need to:
- Preserve environment variables
- Execute complex commands with pipes/redirections
- Maintain strict permission controls
For persistent scripts, consider setting the script's permissions:
chown testuser:testgroup /path/to/script.sh
chmod 4750 /path/to/script.sh
This makes the script:
- Owned by the nologin user
- Executable by group members
- Run with owner's privileges via setuid bit
Database Maintenance Scenario:
#!/bin/bash
# Script to run as postgres user (nologin shell)
su -s /bin/bash postgres -c "/usr/lib/postgresql/14/bin/pg_dumpall | gzip > /backups/db-$(date +%F).gz"
Cron Job Alternative:
# In crontab -e
0 3 * * * root /bin/bash -c 'su -s /bin/sh backupuser -c "/opt/scripts/nightly-backup.sh"'
When working around nologin restrictions:
- Always specify full paths to binaries
- Limit sudo privileges to specific commands
- Avoid world-writable scripts when using setuid
- Consider creating dedicated service accounts with minimal privileges
The techniques shown here mirror how system services like MySQL, PostgreSQL, and Nginx execute commands under their respective nologin users while maintaining security boundaries.
When working with system accounts in Linux that have their shell set to /usr/sbin/nologin or /bin/false, administrators often face difficulties executing commands as these users. This is particularly common with service accounts that shouldn't have interactive login capabilities but still need to run specific processes.
The fundamental issue arises because standard methods like su or sudo typically require the target user to have a valid shell. When you try:
su -c "/bin/touch /tmp/test" testuser
You'll encounter an error if testuser has nologin shell. While changing the shell to /bin/bash temporarily would work, it's not a secure or permanent solution for service accounts.
Here are several reliable methods to execute commands as nologin users:
Method 1: Using su with Explicit Shell Specification
su -s /bin/sh testuser -c "/path/to/your/script.sh"
This forces the use of /bin/sh just for this command execution while keeping the user's shell as nologin in /etc/passwd.
Method 2: sudo with Shell Override
sudo -u testuser /bin/sh -c "/path/to/your/script.sh"
This approach is particularly useful when you have sudo privileges configured for the operation.
Method 3: Using runuser (RHEL/CentOS)
runuser -s /bin/sh -l testuser -c "/path/to/your/script.sh"
This is specific to RedHat-based distributions and provides a clean way to run commands as another user.
Let's consider a practical example where you need to run a backup script as the backupuser which has nologin shell:
#!/bin/bash
# backup_script.sh
tar -czf /backups/$(date +%Y%m%d).tar.gz /important/data
To execute this as backupuser:
su -s /bin/bash backupuser -c "/path/to/backup_script.sh"
When implementing these solutions:
- Always use full paths to scripts and binaries
- Limit sudo privileges when possible
- Consider filesystem permissions for the target user
- Audit commands run through these methods
For complex scenarios, create a wrapper script:
#!/bin/bash
# run_as_nologin.sh
USER=$1
shift
COMMAND="$@"
if grep "^$USER:" /etc/passwd | grep -q "nologin"; then
su -s /bin/sh "$USER" -c "$COMMAND"
else
echo "User $USER has valid shell, using standard su"
su - "$USER" -c "$COMMAND"
fi
Usage:
./run_as_nologin.sh testuser /path/to/script.sh arg1 arg2