Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: August 31, 2025
Privilege separation is a core security principle in Linux and Unix-like operating systems. By design, users are given limited privileges so their actions are confined to their environment, preventing impact on the entire system. The sudoers file determines which users and groups can execute commands with the sudo command.
To manage these permissions, the visudo command is utilized to edit the sudoers file safely. We should avoid editing the sudoers file directly with a regular text editor because it can lead to disastrous consequences, including locking ourselves out of sudo access. Instead, we should use the visudo command because it validates the file syntax before saving any changes.
In this tutorial, we’ll explore how the visudo command works and why it’s important. In addition, we’ll provide practical examples of how to use it effectively.
The sudoers file is a system configuration file in the /etc/sudoers directory. It defines which users or groups can run commands as the superuser or other users. Furthermore, it sets the policies and access controls for the sudo command, allowing users to execute commands with elevated privileges.
Let’s see an example of a typical entry in the sudoers file:
user host = (run_as_user : run_as_group) commands
Following is a breakdown of the directive above:
As an illustration, let’s see a line that grants privileges to a specified user called johndoe:
johndoe ALL=(ALL:ALL) ALL
This line grants the user permission to run any command from any terminal as any other user, including root, after authenticating with their password.
Similar to how the vipw command safely edits the passwd file, visudo ensures the safe editing of the sudoers file. Specifically, it locks the file to prevent multiple simultaneous edits. It also performs basic sanity checks and can roll back changes if a syntax error is detected. This prevents the corruption of the file.
Finally, visudo uses a predefined list of text editors set at compile time, with the default editor typically being vi.
Naturally, we need to have root privileges to run the visudo command:
$ sudo visudo
Running the command without options opens the sudoers file in the default text editor, usually vi or nano.
However, we can change the default editor by setting the EDITOR environment variable:
$ export EDITOR=nano
This command sets nano as the default editor for the current shell session.
Perhaps the most common use case for the visudo command is granting a user or a group sudo access. By default, only users in the sudo group have root privileges.
We can grant a specific user sudo access by using ALL in the sudoers file:
johndoe ALL=(ALL:ALL) ALL
This gives the user johndoe full sudo privileges, allowing this user to run any command as any other user.
Similarly, we can also grant sudo access to a group of users:
%developers ALL=(ALL) ALL
This command grants all users in the group developers sudo privileges. Notably, we use the % symbol to distinguish groups from regular users.
We can also limit the commands a user can run with sudo by specifying the ones that are allowed.
Let’s look at an illustration of how to limit the commands a user can run with root privileges:
johndoe ALL=(ALL) /bin/ls, /bin/cat
In this configuration, johndoe can only run the ls and cat commands with sudo. Any attempt to run other commands with sudo should be denied.
For convenience, we can also configure passwordless sudo for specific users or groups. This can be especially useful for scripts or automation tasks where entering a password isn’t feasible or appropriate.
To allow a user to run sudo commands without a password prompt, we can add the NOPASSWD directive:
johndoe ALL=(ALL) NOPASSWD:ALL
This way, we provide a way for the user johndoe to execute any command with sudo without a password input requirement.
Alternatively, we can also restrict passwordless access to specific commands:
johndoe ALL=(ALL) NOPASSWD:/bin/ls
In this example, johndoe can only run the ls command without a password prompt.
For larger systems with several users and commands, it can be tedious to list every command explicitly multiple times. We use command and user aliases to simplify the configuration of such a scenario.
For example, let’s create an alias for a specific set of commands:
Cmnd_Alias FILEOPS = /bin/cp, /bin/mv, /bin/rm
Next, we can reference FILEOPS in the user permissions:
johndoe ALL=(ALL) FILEOPS
Thus, we allow johndoe to run cp, mv, and rm with sudo.
Similarly, we might want to create user aliases:
User_Alias ADMINS = johndoe, janedoe
ADMINS ALL=(ALL) ALL
These lines grant both johndoe and janedoe full sudo privileges without repeating their permissions.
In environments with multiple machines, we can restrict users to running sudo commands only on specific hosts.
As an illustration, let’s look at how to restrict sudo access of a user to a specific host:
johndoe webserver01=(ALL) ALL
This way, we limit the user johndoe to using sudo on the machine named webserver01.
Let’s look at some of the best practices for configuring and using the visudo command.
Granting users or groups unrestricted access can pose a significant security risk. Instead, we should limit permissions to specific commands necessary for their tasks.
For example, we can grant a user privileges to only the apt-get and journalctl commands:
johndoe ALL=(ALL) /usr/bin/apt-get, /bin/journalctl
This restricts johndoe to package management and viewing logs, keeping the system more secure.
Even in medium-sized deployments, assigning privileges to groups rather than individual users often simplifies administration.
For instance, if we have a group of system managers who need access to certain commands, we can create a group and then assign privileges to that group:
%sysadmins ALL=(ALL) /usr/bin/docker, /usr/bin/kubectl
This way, we grant all members of the sysadmins group the ability to run docker and kubectl commands. This method is usually easier to manage than writing several lines for each user.
Before we make critical changes, we can test how a specific user’s sudoers permissions will apply using the -l option:
$ sudo -l -U johndoe
Matching Defaults entries for johndoe on johndoe-HP-ProBook-440-G7:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User johndoe may run the following commands on johndoe-HP-ProBook-440-G7:
(ALL : ALL) ALL
This command lists all the commands johndoe is permitted to run based on the current configuration of the sudoers file.
As with any critical configuration file, we should always back up the current sudoers file before making any changes:
$ sudo cp /etc/sudoers /etc/sudoers.bak
This line creates a backup file called sudoers.bak local to the original sudoers configuration.
In case of any errors, we can restore the backup and recover the system:
$ sudo cp /etc/sudoers.bak /etc/sudoers
This gives us a quick way of restoring the sudoers file in case we make any errors.
In summary, controlling user access to different parts of the environment is an important security principle in all systems. It ensures that users operate within restricted boundaries, protecting the system from undue influence. Furthermore, the visudo command plays a crucial role in managing these privileges by safely editing the sudoers file. By using visudo, administrators can maintain the integrity of the sudoers file and ensure accurate configurations.
In particular, the sudoers file enables precise control over user permissions. For instance, using directives such as johndoe ALL=(ALL:ALL) ALL grants comprehensive access, whereas %admin ALL=(ALL) ALL provides specific group-based permissions.
Overall, by understanding and correctly implementing these directives, administrators can ensure effective privilege management. Consequently, this approach not only enhances system security but also enables flexible and precise administrative control.