Total Pageviews

Search: This Blog, Linked From Here, The Web, My fav sites, My Blogroll

22 July 2010

OpenBSD --- How Eliminate Root privilege issues?

The root password can be a cause of contention in any organization . Many system administrators hate giving it out, even to people who are responsible for maintaining part of the system. If this sort of system administrator doesn't know how to properly manage things, this reluctance can keep people from being able to do their jobs. Many other system administrators hand out root to dang near anyone who wants to use it, and then complain when the system becomes unstable.

by Michael W. Lucas

Using Groups

Unix has powerful facilities for removing the need to use the root password. In the next few articles, we're going to consider minimizing use of the root password.
    One common situation is where a junior administrator is responsible for a particular portion of the system. i.e  DNS administrators;
    these people don't ever install software, recompile the kernel, or do other low-level system tasks. They just answer email, update the zone files on the nameservers, and reload named.
    New junior administrators frequently seem to think that they need root to do this sort of work. With proper use of groups, and a bit of scheduling, you don't need to hand out root at all! Here, we're going to implement group-based security for managing DNS files. The same techniques can be applied to almost any other section of the system.
    Unix classifies users into groups, each group consisting of people who perform similar administrative functions. You can have a group called Web, which includes the people who edit Web pages, and a group called dns that includes the people who manage your nameserver. Depending on your operating system, you might already have groups with similar names.
For example, NetBSD and OpenBSD both include a user and a group named, while FreeBSD has a user and group called bind, all for use by the nameserver. 
These predefined users and groups are generally used by programs on the system. Web servers generally run as the www user, for example.

For our purposes, we'll want to define a separate group for users who need access to files used by these programs. We don't need a matching user account, however. Group information is in /etc/group. Each line in /etc/group contains four colon-delimited fields.
  1. The first is the group name. Group names are fairly arbitrary: you could give your DNS managers the group name "losers" if you wished. It's a good idea, however, to choose group names that give you some idea of what they're for; while you might remember that the group xyzzy manages your email system today, will you remember it six months from now? Choose group names that mean something.
  2. The second field contains the group's encrypted password. Group passwords encouraged poor security practices, so most modern Unixes don't support them. As with many other things in Unix, however, this field has always been there and so we're stuck with it. Rather than leave this field blank, we use an asterisk (*) as a placeholder.
  3. The third field holds the group's unique numeric ID (GID). Many of FreeBSD's internal programs use this GID, rather than names, to identify groups. /etc/groups is sorted in order by GID.
  4. Last is a list of all the users in that group. To add a user to a group, simply add the username to this list, separated from other names with commas.
To create a group, you just need to pick a unique group ID number. You'll want to pick a number that isn't likely to be taken by a user or some other program. For groups like the dns group we're creating, which are closely related to another group in the system, I'll frequently pick a GID that's off by one from its related group.
    For example, on FreeBSD the bind user has a GID of 53 (from the network port number nameservers use). Our new dns group will have a GID of 54. I want to add the local users "chris", "phil", and "michael" to this group, so our new entry will look like this.
After editing /etc/group, it's a good idea to make sure you haven't made a mistake. FreeBSD includes chkgrp(8), which checks the syntax of the groups file; if it runs silently, you haven't shot yourself in the foot.
    Now that you have a group, you can use it to assign ownership of files. Every file is owned by both a user and a group. You can see the existing ownership of a file with ls -l. Many new system administrators pay close attention to the owner, and to the word permissions, but gloss over the group permissions.
# ls -l
total 29
-rw-------  1 root  wheel   27136 Sep 14 09:36 file1
-rwxrwxr--  1 root  wheel    1188 Sep 14 09:35 file2
 Here, file1 can only be read or written to by root. file2 can be read by root or any member of the group wheel. If you're in the wheel group, you don't need to become root to edit or read file2 file; you can just open your text editor and go!
 To change a group owner on a file, use chgrp(1)
# chgrp groupname filename

Now, in BSD wheel is a system group. Wheel is the group of users who may use the root password. You don't want to go generically making files writable by wheel; this would strongly violate the principle of least privilege.
    Similarly, bind is a group used by the nameserver program. You don't want the nameserver program to be able to write DNS zone files; if someone compromises the nameserver, then the nameserver would be able to write files directly to the disk. This would be bad. But consider the following permissions scheme on the zone file for
-rw-rw-r--  1  mwlucas   dns   486 Jun  7 10:14
This file is owned by me, as the senior administrator, but it's writeable by anyone in the dns group. (You could also set up a particular user to own these files.) Anyone in the dns group can read and write to this file, without using the root password. Finally, this file can be read by the nameserver.
    The only thing the DNS administrators need the root password for now is to restart the nameserver. This is easily dealt with by setting up a cron job to reload the nameserver. These administrators still might want to reload the nameserver manually on occasion, however. We'll look at allowing them to do so without using the root password in the next article....

Using sudo

While proper implementation of groups can help reduce the need for the root password, at times, users must absolutely run commands as another user (usually root). As the system administrator, you're stuck between deciding to hand out the root password or doing everything for your users.
    sudo provides a third way, one that can help solve this dilemma. It's a tricky program, however, and needs some care in implementation. sudo is integrated into OpenBSD, and is an add-on package for just about every other Unix-like operating system out there.

sudo is a setuid root wrapper that implements fine-grained access control for commands that need to be run as root. It takes the command you want to run and compares it to its internal list of permissions. If sudo's permissions allow that particular user to run that command, sudo runs that command for you, with its privileges. As root can run commands as any user, sudo can execute commands as any arbitrary system user.
    With proper setup, the system administrator can allow any user to run any command as any other user.  
sudo is a very powerful tool, and can be configured to allow or deny almost any set of commands. As a result of this flexibility, the documentation tends to scare off new users. 
We're going to do a basic sudo setup that will cover almost all uses, but you should be aware that many more combinations are possible, and are documented in sudo(8) and sudoers(5).
    Other than the obvious fine-grained access control sudo provides, there are a few other benefits to using sudo.
  • One of the biggest advantages is the command logging. Every sudo command is logged, making it very easy to track who made what changes. 
  • And once you have sudo configured correctly, you can change the root password and not give it to anyone. Nobody should need the root password if they have the correct sudo permissions, after all! Reducing the number of people who have the root password can help improve security. 
  • Finally, a single sudo configuration file can be used on all of these systems, vastly easing administrator overhead.
The most overwhelmingly common disadvantage to sudo is that users and junior administrators don't like it. If people have traditionally had root access on a system, they will perceive that they're losing something when you implement sudo.
    The key to overcoming this is to make sure that people have the ability to do their jobs. If users think that they need the root password to perform other tasks, then your need to settle just who is responsible for what. These users may have been taking extra duties upon themselves, rather than troubling you with jobs that you should do.
    A faulty sudo setup can create security holes. A thoughtless configuration will create holes in the system that a clever user can use to actually become root. This problem is best dealt with by a combination of careful configuration and administrative policy. sudo has three pieces.
  1. The first is the actual sudo(8) command, the setuid root wrapper that users will actually use. 
  2. There's also sudo's configuration file, /etc/sudoers. This file is sudo's permissions table, saying who may run what commands as which user, and is fully documented in sudoers(5)
  3. Finally, the visudo(8) command allows administrators to edit the sudoers file without risking locking themselves out of the system. 
We'll consider each component in turn: visudo, the sudoers file, and sudo itself.
If the syntax in your sudoers file is incorrect, sudo will not run. If you're relying on sudo to provide access to the sudoers file, and you corrupt the sudoers file, you can lock yourself out of root-level activities on the system and be unable to correct your error. This is bad. visudo(8) provides some protection against this sort of error.
Much like vipw(8), visudo(8) locks the file so only one person can edit the configuration file at a time. It then opens the sudo configuration file in an editor (vi(1) by default, but it respects the $EDITOR environment variable).
   When you exit the editor, visudo parses the file and confirms that there are no sudo syntax errors (This is not a guarantee that the configuration will do what you want, merely a confirmation that the file is actually a valid). visudo(8) will accept a configuration file that says "nobody may do anything via sudo" if the rules are properly formatted.
    If visudo finds an error when you exit the editor, it will print out the line number and ask you what you want to do:
# visudo
>>> sudoers file: syntax error, line 44 <<<
What now?
Here, we've made an error on line 44. You have three choices:
  1. edit the file again, 
  2. quit without saving any of the changes you made, or 
  3. forcing visudo to write the sudoers file you created.
If you press e, visudo will send you back to the editor. You can go to the line it complained about, and try to find your error.
    If you enter x, visudo will quit and revert the configuration file to what it was before you started editing. Your changes will be lost, but that may be all right. It's better to have the old, working configuration, than have a new, non-functional configuration.
    Entering Q forces visudo to accept the file, syntax error and all. If your configuration file has an error, sudo will not run. Essentially, you're telling visudo to break sudo until such time as you log in as root to fix the problem. This is almost certainly not what you want to do!

The sudoers file tells sudo who may run which commands as which users. OpenBSD stores the sudoers file as /etc/sudoers, FreeBSD stores it as /usr/local/etc/sudoers 
    Never edit this file directly, even if you think you know exactly what change you want to make; always use visudo(8).
    The sudo permissions syntax can be confusing until you understand it. Getting everything correct can be difficult the first time. Once you understand how sudo sets things up, however, it's very quick and easy.
    The various sample sudoers files you'll find on the Internet frequently look quite complicated and difficult to understand, as they demonstrate all the nifty things you can do with sudo. The basic syntax is very simple. Each rule entry in sudoers has the following format:
username host = command 
  • The username is the username of the user who may execute the command.   
  • host is the hostname of the system where this rule applies. 
  • The command field lists the commands this rule applies to. You must have a full path to each command name, or sudo will not recognize it! (You wouldn't want people to be able to adjust their $PATH variable to access renamed versions of commands, now would you?)

sudo is designed so you can use one sudoers file on all of your systems. This space allows you to set per-host rules. sudo defaults to not allowing anything to happen. To let a user run a command, you must create a rule that gives that user permission on that host to run that command. If any of the three fields don't match, the user cannot run the command.
    You can use the ALL keyword in any of these fields to match all possible options. For example, suppose I trust user "chris" to run absolutely any command as root, on any system:
chris ALL = ALL 
Giving a junior system administrator total control of one of my systems isn't very likely. As senior system administrator, I should know what commands Chris needs to run to do his job. Suppose Chris is in charge of the nameserver portion of this system. We control actual editing of the zone files with group permissions, but that won't help when the nameserver must be started, reloaded, or stopped. Here, I'll give him permission to run just the name daemon controller program, ndc(8).
chris ALL = /usr/sbin/ndc 
If I'm sharing this file across several machines, it's quite probable that many of those machines are not even running a nameserver program. Here, I'll restrict which machine Chris may run this program on to the server called "dns1."
chris dns1 = /usr/sbin/ndc 
On the other hand, Chris is the administrator of the email server "mail". This server is his responsibility, and he can run any commands on it whatsoever. I can set entirely different permissions for him on the mail server, and yet use the same sudoers file on both the systems.
chris dns1 = /usr/sbin/ndc 
chris mail = ALL 
You can specify multiple entries in a single field by separating them with commas. Here, I'd like Chris to be able to mount floppy disks with mount(8), as well as control the nameserver.
chris dns1 = /usr/sbin/ndc, /bin/mount 
You can tell sudoers that a user can run commands as a particular user, instead of root, by putting the username in parenthesis before a command. For example, suppose we have our nameserver set to run as the user "named" and all commands to control the server must be run as that user:
chris dns1 = (named) /usr/sbin/ndc 
Every entry in /etc/sudoers must be on a single line. This can make the lines very long. If you have a long list of alias members or rules, you can skip to another line by using the \ character at the end of each incomplete line.
chris server1 = /sbin/fdisk,/sbin/fsck,/sbin/kldload,\ 
Now that you understand how sudo permissions are set, let's look at how to actually use sudo. Use visudo, and give your account privileges to run any command. (If you've installed sudo correctly you already have root, so this won't be a security issue.)

The first time you run sudo, sudo will prompt you for a password.
Enter the password for your own account, not the root password. 
If you give an incorrect password, sudo will insult your typing abilities, mental facilities, or ancestry, and let you try again. After three incorrect passwords, sudo gives up on you. You'll have to re-enter the command you want to run.
Once you enter a correct password, sudo records the time. If you run sudo again within five minutes, it won't ask you for a password. After you don't use sudo for five minutes, however, you must re-authenticate. 
This makes work easier when you're issuing a series of commands under sudo, but times things out quickly in case you walk away from the computer.
    When you're a regular user on a system with sudo, one thing you'll probably want to know is what commands the system administrator has permitted you to run. sudo's -l flag will tell you this.
# sudo -l
User mwlucas may run the following commands on this host:
    (root) ALL 
If you had tighter restrictions, they would be displayed.
    To run commands via sudo, just put the word "sudo" before the command you actually want to run. For example, here's how we would become root using su via sudo.
# sudo su
Using sudo to become root simply allows the senior system administrator keep the root password a closely-held secret.
This isn't entirely useful, as with unrestricted sudo access junior administrators can change the root password. 
Still, it's a start towards keeping the system more secure, and towards implementing sudo for all commands.
    You can run more complicated commands under sudo, with all of their regular arguments. For example, tail -f is excellent to view the end of a log file, and to have new log entries appear on the end of the screen. Some log files are only visible to root, or should be -- for example, the log that contains sudo use information. You might want to view these logs without bothering to become root.
# sudo tail -f /var/log/authlog
openbsd/usr/src/usr.bin/sudo;sudo tail -f /var/log/secure
Jul 29 13:24:19 openbsd sudo:  mwlucas : TTY=ttyp0 ; PWD=/home/mwlucas ;
           USER=root ; COMMAND=list
Jul 29 13:30:03 openbsd sudo:  mwlucas : TTY=ttyp0 ; PWD=/home/mwlucas ;
           USER=root ; COMMAND=/usr/bin/tail -f /var/log/authlog

You can choose to run commands as a user other than root, if you have the appropriate permissions. For example, suppose we have our database application where commands must be run as the database user. You tell sudo to run as a particular user by using the -u flag and a username. For example, the operator user has the privileges necessary to run dump and back up the system.
# sudo -u operator dump /dev/sd0s1

All this tracking and accountability is nice, but where does it account to? sudo messages are logged. Each log message contains a timestamp, the name of the user, the directory where sudo was run, and the command that was run.
Jul 29 11:21:02 openbsd sudo:    chris : TTY=ttyp0 ; PWD=/home/chris ; 
         USER=root ; COMMAND=/sbin/mount /dev/fd0 /mnt
In the worst case, you can backtrack exactly what happened when something breaks. For example, if one of my systems doesn't reboot correctly because /etc/rc.conf is missing or corrupt, I can check the sudo logs to who touched it.
Jul 29 11:34:56 openbsd sudo:    chris : TTY=ttyp0 ; PWD=/home/chris ; 
          USER=root ; COMMAND=/bin/rm /etc/rc.conf

If everyone had been using su, or even using "sudo su" instead of sudo to run each individual command, I would have had no clue as to why the system broke. With sudo logs, once I get this computer up and running again I know who to blame. This alone makes sudo worth implementing.


No comments:

Post a Comment