Working in a Secure Legion Environment

Working in a Secure Legion Environment


Table of Contents
  Obtaining a user-id
Logging in to the system
Running applications
Changing object permissions
Security Exceptions
Quick Reference

The publicly available Legion networks (such as vanet) will run with the security capabilities of the Legion system enabled from November, 1998, forward. This will significantly change the way you use the system in a number of respects. This document contains some usage notes and answers to frequently asked questions, and should help you use the security features of the system as well as minimize the impact of the move to secure Legion.


Obtaining a user id

Before using the system, you will need to obtain a Legion user-id from the Legion admin user (Norm Beekwilder). To make life easier, you should tell the admin user what initial password you would like to use. After system startup (or, in the event of a system crash, restart), your account will be set to this default starting password. You can then use legion_passwd to set your actual password.
NOTE: New accounts take about five minutes to become valid throughout the system. This is an artifact of the way that Legion implements groups. If you try to log in and use Legion before the magic five minute mark, you'll see security exceptions. Nothing is wrong and you needn't report these exceptions as errors--the system is behaving normally and after five minutes the exceptions will stop. You needn't log out and log in again if this happens: your current login session will automatically start working.

Logging in to the system

Whenever you open a new shell in which you will do Legion work, you must log in. If your Legion user-id is /users/foo, for example, you log in by running
$ legion_login /users/foo
The command will prompt for your password.

After you log in, you'll notice two annoying problems: your shell aliases are not set and you will still be in the root context. These are easily solved.

  1. Shell aliases (including Legion alias commands) and Legion environment variables are not set. This includes environment variables, such as $LEGION, and aliased commands, such as legion_tty, legion_tty_off, and legion_set_context. The loss of environment variables and shell aliases is a bug that will be fixed in the next version of legion_login. For now, to re-set the Legion environment variables and alias commands, you must re-source the set-up script for your system. If you are running your own private Legion system, you must run:
    $ . $LEGION/bin/legion_env.sh (in /bin/sh derivatives)
    or
    $ source ${LEGION}/bin/legion_env.csh (in csh derivatives)
    You do not need to re-source legion_context_env.[sh|csh].

    If you are using one of the public Legion systems, such as vanet, you must source the setup.[sh|csh] script for that system.

    If you are running on vanet, you'll need to run

    $ . ~vanet/secure_setup.sh

    or

    $ source ~vanet/secure_setup.csh
  2. Even though you have logged in, you will still be in the root context (/). This isn't inherently wrong (any user can list the contents of the root context), but it is inconvenient since you can't write in the root context (only the admin user has that privilege). Before doing any real work, you should move to your home context. For example, if your Legion user-id is /users/foo, you should run:
    $ legion_set_context /home/foo
    Before doing so, see point 1, above.

    If you ever need to find out if a shell is logged-in to Legion, you can run the command legion_whoami. If this displays your Legion user-id, you are logged in. If it returns without displaying a Legion user-id, the shell is not logged in.

Running applications

Applications will work as they did before. However, if your application reads or writes context space (for example, file objects), you will need to make sure that it can be configured to work in contexts below your home directory. Your objects can not write in contexts such as /.

NOTE:You should make sure that your application uses full context paths. Relative paths will not work since the current working context does not propagate to remote objects. For example, if you set your current context to be your home context, then start an MPI program, the remote MPI tasks will still run in the root context! To avoid causing security exceptions, use full context paths.


Security Exceptions

You will almost certainly see security exceptions as you use the system. These may seem like nasty error messages, but they are very valuable. With a bit of careful reading, you can use these to get a sense of what went wrong. Here's an example of a security exception:
Legion ExoEvent Caught:
Type             : "Exception:Security:MayI"
Description      : "Security fault, MayI failed"
Source Loid      : 1.363b2f7b.06.05632e5c.000001fc09fe3c15bda52f100e3a4
		   bfb8b604d82fb0bf23fc460be7ba86ffeb9ac4db4a0b44625211
		   a2d6b75f2c2a06ea9696b823299ca12193c6b51ebb67b40735cc
		   4d3
Destination Loid : 1.363b2f7b.05.04000000.000001fc0cb1996920d29ee5dde5b
		   d91c96b081e681a7826498c313885fd9f82dfa4eb2370851e3c0
		   ef4f4fd690967b086c92adf87aada668a4f25c0d22dac45b6386
		   5b5
Function Id      : _i_3add_20LegionPackableString_10LegionLOID
$
Given this exception, we'd like to know what method we were trying to call, and on what object. This may help us understand why the request was denied. As a first step, we can try to figure out which object raised the exception. The LOID of this object is listed in the Destination Loid field of the exception. We can use legion_list_names to figure out which context names exist for this LOID:
$ legion_list_names -l 1.363b2f7b.05.04000000.000001fc0cb1996920d29ee5d
  de5bd91c96b081e681a7826498c313885fd9f82dfa4eb2370851e3c0ef4f4fd690967b0
  86c92adf87aada668a4f25c0d22dac45b63865b5
/hosts
$
We now know that the context object called /hosts raised the objection. The Function Id field in the exception tells us that the exception was raised when we tried to call the add method on /hosts. So, this exception tells us that normal users are not allowed to write entries into /hosts (only admin can do this).

You may find that this kind of analysis is not always profitable. It may be difficult or impossible to find the excepting object's context names (or anything else about it, for that matter): legion_list_names may run into additional exceptions and be unable to tell you anything useful. If you cannot determine the nature of a security exception or you believe that it may be in error, you should report it to legion-help@virginia.edu. Please include a report of the command that was run, the text of the security exception, and the output of legion_whoami from the shell in which you were working to help us determine what went wrong. You may have found a problem in the system security configuration, or a bug in the security enforcement code. More likely, you may be seeing some quirk in the behavior of the security code that one of the system hackers can clarify for you.


Changing object permissions

Modifying Access Control Lists
Object permissions are stored within each object in the form of an Access Control List (ACL) for the object. The ACL is basically a list of the users and/or groups that are allowed or forbidden to call each method that the object supports. You can view and modify ACLs with the Legion ContextMgr Java applet (i.e., the Legion GUI). To do so, select the object in the window and run View/Modify ACL from the Edit menu. In practice, direct manipulation of ACLs using the ContextMgr is difficult and unnecessary.

The preferred mechanism for configuring access to your objects is the command legion_change_permissions. This command classifies methods as read, write, or execute operations. It allows you to configure access to these types of methods using a single command. For example, to grant a user /users/adam access to your file /home/foo/tst.txt, you would run:

$ legion_change_permissions +r /users/adam /home/foo/tst.txt
To grant all users in the system read and write access to the same file, you would run:
$ legion_change_permissions +rw /users /home/foo/tst.txt
To deny write access to the same file to /users/andrew, run:
$ legion_change_permissions -w /users/andrew /home/foo/tst.txt
Deny access takes precedence over allow access, so if we had executed both of the two previous commands (granting read and write access to everyone, then denying it to /users/andrew), /users/andrew would not be able to write /home/foo/tst.txt.

Read and write permissions are defined intuitively for a number of types of objects. Read and write permissions for File objects use the usual definition. Read permission for a Context object allows you to list its entries (with legion_ls), whereas write permission allows you to add and delete entries to and from the context. Read permissions for a TTY object allow you to view output written to the TTY, whereas write permission allows you to send output to the TTY. Similar definitions hold for other types of objects such as Hosts, Vaults, and Implementation objects.

A third category of permissions, execute, is only used for Class objects. While Class objects use the usual read and write permissions (i.e., read permission allows you to read information about the class, such as listing the class's instances or listing its available set of implementations, and write permission allows you to modify the class's behavior by adding or removing implementations), Class objects also define execute permissions for creating and managing new instances. If you have execute permissions on a Class, you can create new instances, modify the state of your instances (e.g., activate and deactivate them), and destroy your own instances (note that execute permissions on a class do not enable a user to control other users' instances).

Below, to grant the user /users/andrew the ability to create new instances of the class /mpi/programs/mpi-FFT, we would run the following command:

$ legion_change_permissions +rx /users/andrew /mpi/programs/mpi-FFT
Note that we are also granting /users/andrew read permissions. This is usually necessary for effective use of the class: determining the binding (location) of an object, for example, requires read permissions on the class. The example above will let /users/andrew determine the locations of his own instances of /mpi/programs/mpi-FFT.

A necessary (but not immediately obvious) part of allowing another user to execute instances of your class is granting read permissions on the implementation objects associated with that class. It is not sufficient to merely grant a user permission to call methods on the class object: we must also explicitly modify the permissions of the associated implementation objects, so that the user can create instances of the class. The implementations associated with a class can be determined using the command legion_list_implementations. You might simply make a practice of keeping context links (via legion_ln) to your implementation objects in a set location--for example, /home/you/impls. The Legion command for creating implementation objects supports a flag (-c) for naming your implementation objects in context space. To give a user permission to use an implementation object, simply execute legion_change_permissions as before:

$ legion_change_permissions +r /users/andrew /home/adam/impls/mpi-FFT.linux
It is typical to grant only read permissions for other users on your implementation objects. This level of access is sufficient to use an implementation object to instantiate new objects.

Users and Groups
When configuring the access control policies for your objects, it is important to understand the system's notion of users and groups. Users are represented in the system by objects. These user objects (technically known as Authentication objects) are listed in context space. Typically, all of the user objects in a system are (at a minimum) listed in the context /users.

Under the current implementation, when you log in to the system you assume the identity of a user object within the system. When you run commands the identity of this user object propagates through any method invocations performed on your behalf. For example, if you call a Class object to create a new instance, and that Class object calls a Host object to start a process, the Host will identify the call as being performed by your user object, not by the actual caller (the Class object).

Given this model, it only makes sense to add user objects to your objects' ACLs. For example, if we tried to add the Class object to the ACL for the Host object in the above example, the method would have been denied. The Class object's identity never reaches the Host as the identity of the caller. However, if we put the calling user on the ACL for the Host object, the method would be permitted, since user-object identity propagates along with method invocations.

If you wish to add several users to an ACL, however, this method is time-consuming and difficult. Therefore, there is an important additional element that we can use for composing ACLs: groups. Groups give us a convenient mechanism for controlling access permissions of entire sets of users. For example, we may want all users from a given institution to be able to read a certain file, but we would not like to execute legion_change_permissions for every person in the organization. Furthermore, we would like access control for the object to be automatically updated when users join or leave the organization in question.

In Legion, groups are represented by Context objects: a group is simply a context object that lists a set of user objects. Every Legion system contains at least one group, the /users context. You can create new groups simply by creating new contexts (using legion_context_create), and making aliases for desired existing users to the new context (using legion_ln). You can use these new groups (or /users and groups created by other users) to configure permissions using legion_change_permissions--simply specify the name of the group instead of the name of a user. For example, if you were to run:

$ legion_context_create /home/my_group
$ legion_ln /users/andrew /home/my_group/andrew
$ legion_ln /users/adam /home/my_group/adam
You would create a new group called /home/my_group and put two users (/users/andrew and /users/adam) in the group. If you then run:
$ legion_change_permissions +rx /home/my_group /mpi/programs/mpi-FFT
You would give any members of your /my_group read and execute permissions for your class object mpi-FFT.

Quick Reference

Security-related Commands
legion_login <user-id> -- Log in to the Legion system. (See Logging In to the System.)

legion_whoami -- Display current Legion identity. No output if not logged in to Legion. (See Logging In to the System)

legion_get_acl [-c <context path> | -l <loid>] -- Display the Access Control List (ACL) for an object.

legion_change_permissions [+-rwx] <user/group context path> <target context path> -- Set the ACL for the target object, enabling or disabling read, write, and/or execute operations on the object for the specified user or group. (See Changing Object Permissions.)

Additional Related Commands

legion_list_names [-c <context path> | -l <loid>] -- List the context names associated with a given object. Useful for interpreting security exception messages. (See Security Exceptions.)

legion_list_implementations [-c <class context path> | -l <class loid>] -- List the implementation objects associated with a class. Useful in the process of enabling execute permissions for a class. (See Modifying Access Control Lists.)