"visudo" will not allow you to exit the editor with an incorrect syntax in the file.
The most commonly used syntax used can be summarised as
USER_SPACE HOST=RunAs(User) COMMANDS
OR
USER_SPACE HOST=RunAs(User:Group) COMMANDS
You can also use NOPASSWD variable if you do not want sudo to prompt for password while executing the assigned task
The syntax here would be:
USER_SPACE HOST=RunAs(User) NOPASSWD:COMMANDS
OR
USER_SPACE HOST=RunAs(User:Group) NOPASSWD:COMMANDS
Let's understand the different fields here separately
Aliases in sudoers file
Various Aliases defined in the sudoers files, these are sort of VARIABLES we use in scripts which can contain multiples entries that fit the same domain (users, hosts, commands). The aliases we have in sudoers are as below
User_Alias
Host_Alias
Cmnd_Alias
Let's go through each of the available options one by one with some examples to understand more on them.
User
You can assign sudo based permission for individual user by using the below syntax
Syntax:
user HOST=RunAs COMMAND
For example I want user "deepak" to be allowed to restart crond service so below would be the syntax I would use
deepak ALL=(ALL) /usr/bin/systemctl restart crond.service
If I want to allow him to run more commands then add below content in your sudoers file using visudo
deepak ALL=(ALL) /usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
Validate the same
[deepak@golinuxhub ~]$ sudo systemctl status crond.service
[sudo] password for deepak:
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2017-12-30 19:04:36 IST; 4min 18s ago
Main PID: 1768 (crond)
CGroup: /system.slice/crond.service
└─1768 /usr/sbin/crond -n
Dec 30 19:04:36 golinuxhub.lab systemd[1]: Started Command Scheduler.
Dec 30 19:04:36 golinuxhub.lab systemd[1]: Starting Command Scheduler...
Dec 30 19:04:36 golinuxhub.lab crond[1768]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 10% if used.)
Dec 30 19:04:36 golinuxhub.lab crond[1768]: (CRON) INFO (running with inotify support)
Dec 30 19:04:36 golinuxhub.lab crond[1768]: (CRON) INFO (@reboot jobs will be run at computer's startup.)
User Alias (User_Alias)
If we have multiple list of users for whom we want to allow certain list of commands with sudo then we can use "User_Alias" which is an internal variable of sudoers file.
Syntax:
User_Alias ALIAS_NAME = user1, user2, ...
ALIAS_NAME HOST = RunAs COMMAND
For example:
I have user "deepak" and "ankit" to whom I want to allow execute crond service related commands for restart and status using systemctl then my syntax would look like below
Look out for below section in your sudoers file using visudo
## User Aliases
## These aren't often necessary, as you can use regular groups
## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname
## rather than USERALIAS
# User_Alias ADMINS = jsmith, mikem
# The content may look little different based on your distribution, below this you can # create a new line add below content
User_Alias CROND_USER = deepak, ankit
NOTE: There is no hard and fast rule to create new rule below this section, although this helps keep every variable under its respective section so looks neat and clean which is always good
Lastly add a new line at the end of sudoers file
CROND_USER ALL = (ALL) /usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
here as you see instead of giving name of individual user I created a variable CROND_USER and added all the list of users for whom I want to give common sudo access
%Group
Assuming you already have a system group which has a list of users for whom you want to allow certain commands or tasks then instead of using User_Alias you can use the group argument using the below syntax
Syntax:
%groupname HOST=RunAs COMMAND
For example I have a group "mycompany" whose members are user "deepak" and "ankit" for whom again I want to give access to execute restart and check status of crond service
Add the below line in the sudoers file /etc/sudoers using visudo
%mycompany ALL=(ALL) /usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
NOPASSWD
By default, sudo requires that a user authenticate him or herself before running a command. This behavior can be modified via the NOPASSWD tag
Syntax for individual user:
User HOST=RunAs NOPASSWD:COMMAND
Syntax for individual group:
%group HOST=RunAs NOPASSWD:COMMAND
Syntax for User_Alias:
ALIAS_VARIABLE HOST=RunAs NOPASSWD:COMMAND
For example I have a user deepak for whom I want to give permission to restart and check status of crond service
Add the below content at the end of the line in your sudoers file using visudo
deepak ALL=(ALL) NOPASSWD:/usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
Suppose I have a set of commands out of which I want to allow deepak to run only few of the commands passwordless while for some I want the password prompt then in that case we will use below rule
deepak ALL=(ALL) NOPASSWD:/usr/bin/systemctl restart crond.service, PASSWD:/usr/bin/systemctl status crond.service
HOST
Why do we need "Host" when I know I am going to run from my machine?
Well actually the question is absolutely correct but what if you have a big network with 1000s of servers wherein each group of server have their own role for eg some can be a DNS server, some can be an apache server and we have to assign sudo roles accordingly to respective users.
Now you wouldn't want a user "deepak" who is a domain administrator having sudo access to domain server is also getting sudo access to other servers?
So I will use the "Host" section in the sudo and will make sure that user deepak to allowed to run all the needed commands as root but only on the "Domain Server"
Syntax:
User HOST=RunAs COMMAND
For example if my domain server hostname is "golinuxhub" then my sudoers would have something like
deepak golinuxhub=(ALL) <List of commands>
with this user "deepak" can run all the allowed commands on "golinuxhub" but not on other servers
For example I want "deepak" to allow restart of crond service but only on golinuxhub server
deepak golinuxhub=(ALL) /usr/bin/systemctl restart crond.service
If I want him to allow restart this server on all the hosts then this would become
deepak ALL=(ALL) /usr/bin/systemctl restart crond.service
Host_Alias
If you want to allow a user execute some tasks with sudo permission on multiple hosts then you can use the Host_Alias variable which is an sudoers based internal variable.
Syntax:
Host_Alias MAILSERVERS = smtp, smtp2, ...
Look out for below section in your sudoers file using visudo and append a new line to create a new variable for your requirement
For example I want "deepak" to run some command on dnsserver and dhcpserver then
## Host Aliases
## Groups of machines. You may prefer to use hostnames (perhaps using
## wildcards for entire domains) or IP addresses instead.
# Host_Alias FILESERVERS = fs1, fs2
# Host_Alias MAILSERVERS = smtp, smtp2
Host_Alias DEEPAK_SERVER = dnsserver, dhcpserver
deepak Host_Alias=(ALL) /usr/bin/systemctl restart crond.service
Here dnsserver and dhcpserver are the hostname of my servers, you can replace this with the hostname based on your setup
NOTE: There is no hard and fast rule to create new rule below this section, although this helps keep every variable under its respective section so looks neat and clean which is always good
RunAs(User:Group)
- A Runas_Spec determines the user and/or the group that a command may be run as.
- A fully-specified Runas_Spec consists of two Runas_Lists (as defined above) separated by a colon (‘:’) and enclosed in a set of parentheses.
- The first Runas_List indicates which users the command may be run as via sudo's -u option.
- The second defines a list of groups that can be specified via sudo's -g option.
- If both Runas_Lists are specified, the command may be run with any combination of users and groups listed in their respective Runas_Lists.
- If only the first is specified, the command may be run as any user in the list but no -g option may be specified.
- If the first Runas_List is empty but the second is specified, the command may be run as the invoking user with the group set to any listed in the Runas_List.
- If both Runas_Lists are empty, the command may only be run as the invoking user.
Syntax if only "user" section is used:
USER_SPACE HOST = RunAs(User) COMMAND
Syntax if only "group" section is used:
USER_SPACE HOST = RunAs(:Group) COMMAND
Syntax if both "user" and "group" sections are used:
USER_SPACE HOST = RunAs(User:Group) COMMAND
Let's have a look at some example
I have a test script which is owned by "deepak" user
[root@golinuxhub ~]# ls -l /tmp/deepak_script.sh
-rwxr-xr--. 1 deepak deepak 47 Dec 30 17:14 /tmp/deepak_script.sh
As you see both user and group of this script is "deepak:deepak" and both have executable permission for this script
If I run thos script as user "deepak"
[deepak@golinuxhub ~]$ /tmp/deepak_script.sh
Hello This is Deepak's fIle
So this was properly executed. Let's try to run this as some other user "ankit"
[ankit@golinuxhub ~]$ /tmp/deepak_script.sh
-bash: /tmp/deepak_script.sh: Permission denied
First thing it says is permission denied, well why not buddy since deepak is smart as he has not given executable permission to this script so there is no way so gonna mesh with his script
Now ankit attempts to run the script with sudo access hoping that might work
[ankit@golinuxhub ~]$ sudo /tmp/deepak_script.sh
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for ankit:
ankit is not in the sudoers file. This incident will be reported.
Oops that also didn't worked.
But for the sake of this article let's give Ankit "sudo" permission to execute Deepak's script (I hope he doesn't get mad!!) in the sudoers file using visudo
ankit golinuxhub=(deepak) /tmp/deepak_script.sh
Save and exit the file.
Now if you notice here I have given RunAs access to "deepak" which means if user "ankit" runs the script as "deepak" then he will be allowed to run the script.
Now let's try to execute the same file as Ankit but with sudo permission
[ankit@golinuxhub ~]$ sudo /tmp/deepak_script.sh
[sudo] password for ankit:
Sorry, user ankit is not allowed to execute '/tmp/deepak_script.sh' as root on golinuxhub.lab.
Since here ankit is trying to run deepak's script as root (if there is no -u specified then the sudo works as root user) hence the permission was denied, let's try again with "-u deepak"
[ankit@golinuxhub ~]$ sudo -u deepak /tmp/deepak_script.sh
[sudo] password for ankit:
Hello This is Deepak's fIle
So it worked this time.
Similar to this we can also give RunAs "Group" level permission
For example if I give below arguments in the sudoers file
ankit golinuxhub=(deepak:deepak) /tmp/deepak_script.sh
If you observe I have given access for both User:deepak and Group:deepak so using either Ankit can run the script
[ankit@golinuxhub ~]$ sudo -g deepak /tmp/deepak_script.sh
Hello This is Deepak's fIle
OR he can run the script as either user and group
[ankit@golinuxhub ~]$ sudo -u deepak -g deepak /tmp/deepak_script.sh
Hello This is Deepak's fIle
COMMANDS
I think I have already been giving multiple examples for this in the above sections. In the last column of sudoers syntax we provide the list of commands which we want to be allowed for a user/group.
Syntax:
USER_SPACE HOST=RunAs COMMANDS
For example I want "deepak" to allow restart of crond service
deepak ALL=(ALL) /usr/bin/systemctl restart crond.service
You can give multiple commands separated by a comma "," and followed by a whitespace.
Cmnd_Alias
If you have a set of commands for which you want to provide access so it makes sense to add them into a single variable i.e. Cmn_Alias which is an internal sudoers owned variable.
Syntax:
Cmnd_Alias VARIABLE_NAME = /path/to/command1, /path/to/command2, /path/to/command3, ...
Look out for below section in your sudoers file and append a new line to create a new variable for your requirement in the sudoers file using visudo
For example I want "deepak" to run some set of commands using a variable CROND_SERVICE
## Command Aliases
## These are groups of related commands...
Cmnd_Alias CROND_SERVICE = /usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
deepak ALL = (ALL) CROND_SERVICE
If you want to disable password prompt for the set of commands then use below line
deepak ALL = (ALL) NO_PASSWD:CROND_SERVICE
I will write a separate article with more possible examples and scenarios for sudo use case on ground zero.
I hope this article was helpful.