
Managing Filesystem ACLs with GNU/Cfengine
by Mark Burgess Mark Burgess is associate professor at Oslo College. He has a PhD in theoretical physics and perhaps soon another one in computing. He is the author of cfengine. Mark claims to be interested in everything and is into getting the most out of life.
and Demosthenes Skipitaris Demosthenes Skipitaris has a master's degree in informatics from the University of Oslo. He has worked with UNIX systems management since 1991, and has experience with distributed filesystems like DFS. He is now partner and UNIX consultant in Nitro Media Inc.
Access control lists, or ACLs, are notoriously awkward to maintain. They can be a major headache for system administrators, and yet they are at the heart of POSIX filesystems and the DFS. Cfengine has begun a noninteractive approach to ACL management. File permissions are the simplest and most basic security mechanism after passwords. Traditionally in UNIX-like operating systems, a file has one owner, one group, and a set of access bits for the owner, members of the group, and others. This model is rather old, and, for many purposes, the scheme is not flexible enough. For ordinary users, it is inconvenient to have to define a group just to open a file to a single person. ACLs are extended file permissions. They allow you to open or close a file to a named list of users without having to create a special group. They also allow you to open or close a file for a named list of groups. Several UNIX-like operating systems have had access control lists for some time, but ACLs do not seem to have caught on for a number of reasons in the past. The tools for setting ACLs are generally interactive, and most are very awkward to use. Because a named list of users would lead to excessive verbosity in an ls -l listing, one does not normally see them. Only a + sign next to the permission tells you that the file has a full ACL. There is therefore the danger that the information hidden in an ACL would lead to undetected blunders in opening files to the wrong users. Another problem is that ACLs are different on pretty much every vendor's filesystems, and they don't work over intersystem NFS. In spite of these reservations, ACLs are a great idea. Here at Oslo College, users seem continually to be asking how they can open a file just for the one or two persons they wish to collaborate with. They have grown used to Novell/PC networks that embraced the technology from Apollo/NCS much earlier. The UNIX answer to users has always been: go ask the system administrator to make a special group for you. Then do the chmod thing. And then they would say: so what's so great about UNIX? Addressing this lack of standardization has been the job of a POSIX Draft Committee, and some vendors have made their implementations in the image of this draft. Solaris 2.6 has a good implementation, for instance. In spite of this, even these systems have only awkward tools for manipulating ACLs not the kind of thing you want to be around much if you have better things to do. But the incompatibility argument applies only to multiple vendor head butting. Some institutions that share data on a global basis opt for advanced solutions to network filesystems, such as AFS and DFS. DCE's DFS makes extensive use of file ACLs, and it is not operating system specific. Even so, DFS provides only interactive tools for examining and setting file permissions, and this is of little use to system administrators who would rather relegate that sort of thing to a script. Access Control Entries An access control list is a compound object, a bundle of information that specifies which users or groups have which permissions. The list consists of access control entries (ACEs). Each entry defines access rights to a file. Only owners or users with special authority can change the ACL. Each ACE is a set consisting of a type that tells you the kind of entry, a key that identifies the user or group for the entry, and permissions bits associated with the key. An ACE has the form type:key:permissions. Type user defines permissions for the implied user, type group defines permissions for the implied group, and type other defines permissions for others. Some systems (like DFS) have more types (for example, type unauthenticated, which applies when the accessor does not pass authentication procedures). If the key field is empty, it means the default user/group or no user/group. The permission bits are the standard UNIX read, write, and execute permissions. DCE/DFS has additional permission bits, control (c), which grants control privileges to modify the ACL, insert (i), which grants insert privileges, and delete (d), which grants delete privileges. Insert and delete refer only to directories. The ACLs also have a special mask entry. This entry indicates the maximum permissions allowed in all entries except the file owner and hence restricts the permissions specified in other entries.
Solaris ACLs are viewed with the command getfacl and set with
setfacl. DFS ACLs are examined and set with the
acl_edit command or with dcecp -c acl
In this case, the owner of the file has rw permissions. User mark and group sys has rwx permissions, but because of the mask, the effective permissions are only rx. Users in the file group iu and other users has r permissions. GNU/Cfengine Cfengine is a freely available GNU tool for administrating nonhomogeneous distributed systems. It is class based and is designed to cope with the differences in UNIX-like operating systems in as simple a manner as possible. Although cfengine is not specifically a tool for administering security (which is a perceived concept), it is a tool for administering consistency. Cfengine makes a system converge toward a user-defined state by automating a list of key tasks such as file management and editing. One of the things cfengine is useful for is checking the permissions of files in a rationalized way. ACL management seemed like the kind of thing that cfengine should address, not least because it is desirable to port cfengine to modern filesystems like the DFS and to NT. Cfengine is good at managing distributed environments, and many DFS users have adopted it. Interested in supporting their customers, Transarc contacted Mark and kindly offered to give us DFS so that we might add support for it in cfengine. We did, and the result is available from version 1.4.9, which you can pick up from GNU repositories of the from the cfengine home page. While we were at it, we added support for Solaris ACLs and tackled the most important problem: namely, how to make a common user interface for multiple vendor ACLs with a simple, manageable syntax.
Using cfengine To Manage System ACLs More Easily. A cfengine bare-bones file-checking program looks like this: # Free format cfengine program control: ActionSequence = ( files ) files: classes::
/directory/file mode=644 # ... more below This program checks the permissions and ownership of the named file on all machines that satisfyclasses. The regular file mode, owner and group are specified straightforwardly as an octal number or as an rwx string. In cfengine, you can provide a list of groups or owners that you deem acceptable for a file, using a comma-separated list. If a file does not belong to any of these, then the first object in the list is taken to be the intended owner of the file. fixall means correct both file and directory ownership and permissions if they do not conform to this specification. The new feature in cfengine is the acl directive. It is a deceptively simple looking animal, but it hides a wealth of complexity. The name zap, of course, is not an access control list. Rather, cfengine uses a system of aliases to refer to ACLs so that the clutter of the complex ACL definitions does not impair the clarity of a file command and so that they can be reused over several file commands. An ACL alias is defined in a separate part of the program that looks like this: # ...contd
acl: Because ACLs are lists, the alias objects must also know whether the items are to be appended to an existing list or whether they are to replace an existing list. Also, because the permission bits, general options, and programming interfaces are all different for each type of filesystem, we have to tell cfengine what the filesystem type is. It is possible to associate several ACL aliases with a file by adding and acl alias for each of these and a corresponding acl= option. When cfengine checks a file with ACLs, it reads the existing ACL and compares it to the new one. Files modification is attempted only if the files do not conform to the specification in the cfengine program. Let's look at a complete example:
files:
acl:
Suppose that, before running this program, our test-file had permissions:
user:*:rwx After the cfengine run, the ACL would become:
user:*:rwx In cfengine, the permissions field is a comma-separated list of permissions to add, delete, or absolute assign. Addition is specified with a plus sign (+), removals with a minus sign (-), and absolute assignments, with a equals sign (=). Adding is the default action; if no sign is given, adding is assumed. Suppose we wanted to remove the w bit for user jacobs, or make sure that it was never there. The minus sign means remove the listed permission bits. { acl_alias1
method:append Note that the method used here was append. That means that, whatever other access permissions we might have granted on this file, the user jacobs (a known cracker) will have no write permissions on the file. We append a delete of the write permission. Had we used the method overwrite above, we would have eliminated all other access permissions for every user and added only the above. If we really wanted to burn jacobs, we could remove all rights to the file like this: user:jacobs:noaccess The key word noaccess removes all bits and is equal to an absolute assignment of no permissions bits: user:jacobs:= Note that this is not necessarily the same as doing a -rwx, because some filesystems, like DFS, have more bits than this. Then, if we want to forgive and forget, the entry for user jacobs may be removed with: user:jacobs:default In Solaris, files inherit default ACLs from the directory they lie in; these are modified by the umask setting to generate their own default mask. DFS ACLs look a little different. Suppose we have a file with the following DFS ACL:
Now we want to add wx permissions for user cell_admin, add new entries with rx permissions for group acct-admin and user root, and remove the x bit for the file owner. This is done with the following ACL alias:
{ acl_alias2 The local cell name /.../iu.hioslo.no is required here. Cfengine cannot at this time change ACLs in other cells remotely unless it is started from a shell that already has cross-cell authenticated rights. However, there is nothing to stop you from creating a cfengine program that is common to all the cell servers (the same file parsed by each machine). Each server would then read and execute the same file, and each would look after its own cell. The job is then automatically distributed without the need for cross-cell authentication. This is the beauty of cfengine. After running cfengine with the above program snippet, the ACL becomes:
For the sake of simplicity, we have used only standard UNIX bits rwx here, but more complicated examples may be found in DFS, for example, user:ds:+rwx,-cid which sets the read, write, execute flags but removes the control, insert, and delete flags. In this case, this is equal to: user:ds:=rwx In the DFS, files inherit the initial object ACL of their parent directory while new directories inherit the initial container object. The objects referred to in DFS as user_obj, group_obj, and so forth refer to the owner of a file (i.e., they are equivalent to the same commands acting on the user who owns the file concerned). To make the cfengine user-interface less cryptic and more in tune with the POSIX form, we have dropped the _obj suffices. A user field of * is a simple abbreviation for the owner of the file and an empty key field. The Future A problem with any system of lists is that one can generate a sequence that does one thing and then undoes it and then redoes something else, all in the same contradictory list. To avoid this kind of accidental interaction, cfengine insists that each user has only one ACE (i.e., that all the permissions for a given user be in one entry). Several people have said it would be desirable to port cfengine to Windows NT. Although lack of time is the main reason this has not yet happened, we agree that this is just what NT is missing. The ACL model we have chosen would work equally well there and would be even more important, because NT does not have a simple chmod-like default permission. This is clearly an important project for the future.
As of now, we have implemented the ACL code for Solaris filesystems
because the latter is supposed to be essentially the POSIX draft) and
for DFS and have left stubs for people to add their own ports. Other
system types will come as we get time. Perhaps the enthusiastic
cfengine community, having been provided with the
infrastructure, Access control lists are a valuable addition to the UNIX repertoire. They are useful for aiding collaboration among users and implementing tighter security. It would be nice if vendors woke up and standardized ACLs so that we could all use them over the NFS. It would also be nice if Linux and the BSDs had ACLs. For now, cfengine will allow system administrators to reap their benefits on the systems that have them. References Cfengine homepage <http://www.iu.hioslo.no/cfengine>. M. Burgess, "A Site Configuration Engine," Computing Systems 8 (1995), p. 309. M. Burgess and R. Ralston, "Distributed Resource Administration Using cfengine," Software Practice and Experience 27(9), (1997), p. 1083. Sun Microsystems, SunOS Reference Manual (User commands). DFS documentation. Transarc Corporation. <http://www.transarc.com/afs/transarc.com/public/www/Public/Documentation>
|
|
7th July 1998 efc Last changed: 7th July 1998 efc |
|