V:4.1.3/Karajan:Service

From Java CoG Kit

Jump to: navigation, search

Karajan features a service which can be used to execute parts of a script remotely. Some of the features of the service are listed below:

Security 
The service and client use GSI security enabling strong authentication and encryption of data
Configurable communication channels 
The Karajan networking infrastructure consists of configurable communication sub-systems, which separate the high level messaging protocols from the low level implementation details. The current implementation uses SSL sockets over TCP/IP, and can be configured to use persistent connections, or callbacks, or polling (or a combination of them), and the configurations can be different for each host or for a specific domain. This provides firewall transparency when needed, yet can minimize resource consumption and maximize performance when firewalls are not involved.
Semantic transparency 
Remote execution can be seamlessly integrated with local execution, while preserving most of the system semantics, such as return values, definitions, etc.

Contents

Using the Service

The Karajan service can be accessed from Karajan scripts using the remote element.

Shared or Personal

The Karajan service can be used in two modes: personal or shared. In personal mode, the service runs under a user’s credential, loaded from a proxy certificate. It is therefore necessary that a valid proxy exists before the service is started in personal mode. In this mode, all libraries are available for use without restrictions, but the connections are limited to clients using the same credential as the one used for starting the service.

In shared mode, the service requires a host credential. In this mode, connections can be initiated by multiple users, and authorization is performed based on a grid-map file. Access to certain libraries or functions that could be used to access files, resources, or other information belonging to other users using the service are restricted. Any attempt to execute such functions will result in the execution failing. The following list enumerates libraries and elements whose use is restricted in shared mode:

In addition, the Task Library requires a special local provider, which can use operating system services to execute local tasks under non-shared privilege, achieved through grid-mapfile mapping. The service will refuse to run in shared mode if the normal local provider is detected. Details about building and configuring the secure local provider are available here.

When running in shared mode the service should be started under a non-priviledged account. Please do not run the service from the root account or any other administrative/priviledged account!

Limiting Access to Resources in Shared Mode

Using the service in shared mode has a number of security requirements:

  • Access to resources should be restricted based on user identities.
  • A user must not be able to access any other user’s data/resources. Consequently, this requirement is divided into:
    1. Restricting access to the shared environment, such that privilege escalation cannot be done in order to override any of the security measures in place
    2. Delegating certain required privileged operations (such as execution and file access) to local security domains (running privileged operations under specific user accounts)

Access restriction is achieved using a ”all-or-nothing” access control list: the grid-mapfile. A given identity (materialized in a GSI/X509 certificate) is only able to use the service if there exists an entry for that identity in the grid-mapfile.

Shared environment access restrictions is done in two ways: [1]

  1. Execution of Karajan elements that could be used for escalating privileges or accessing other users’ data/resources is prohibited. Attempts to use these will result in an error instead. For example, allowing arbitrary Java method invocations inside the shared interpreter environment (the service JVM) is prohibited. Similarly, elements that can be used to access files belonging to the account under which the shared interpreter is running is also prohibited, and their use will result in an error.
  2. Instantiation of arbitrary Java objects, regardless of the means, is restricted to known “safe” object types. A subset of the problem is presented below:

The Karajan service allows passing various arguments from the client to the service by means of serialization and de-serialization. However this process does not guarantee the invariance of all objects when copied to a different resource. It is possible, that a certain object exists within the libraries of both the client and the service, which could, through the simple process of de-serialization, be initialized with privileged data, which can later be retrieved through other means. For example, let us consider the following Java class:

public class Foo implements Serializable {
  private File file;
  private transient String contents;

  public Foo(File file) {
    this.file = file;
    this.contents = read contents of file
  }

  public String toString() {
    return contents;
  }
}

The transfer of an instance of Foo from the client to the service, by means of serialization/de-serialization will not preserve the local meaning of the file attribute. Instead, the mere instantiation of Foo combined with a seemingly unprivileged operation (print(”foo is {foo}”)) could allow access to arbitrary files in the service shared environment.

Another possible scenario is objects whose constructors implement side effects that execute privileged operations. Another Foo, should illustrate this:

public class Foo implements Serializable {
  public Foo() {
    something that amounts to "rm -rf /"
  }
}

It is clear that de-serializing an instance of the latter Foo in the service environment is undesirable, to say the least. Surely, both Foo versions are somewhat extreme, and somewhat unlikely to exist in the libraries of both the client and the service, but there is no certainty, and auditing all classes in the libraries would be very tedious if at all possible. The chosen solution to the problem is to have a set of allowed classes/packages which can be safely migrated between client and server, while excluding anything that is not explicitly in the set. A configuration file (etc/karajan-restricted-classes.properties) defines the de-serialization policies. The file allows two types of entries:

package.allow 
Define a package which is allowed. All classes in the specified package and all its sub-packages are considered safe to be de-serialized.
class.disallow 
Explicitly disallow a class from being de-serialized, even if it is contained in an allowed package.

Communication Layer Configuration

The communication layer supports three basic modes of operation, described below:

Persistent 
In this mode, connections are kept open for as long as needed. All client→server and server→client communications will re-use the same connection, even if multiple requests are sent concurrently from the client. It is also possible to keep connections open after all current communications have terminated, in the event that future communications will be needed. This mode can be safely used if the client is behind a firewall, but it may keep resources allocated unnecessarily if no communication happens between the server and the client.
Callback 
The callback mode can be used to instruct the service to initiate a connection to the client if the service needs to send any messages to the client. This type of configuration will most likely not work if a client is behind a firewall.
Polling 
Polling is somewhat similar to persistent connections in that it will safely work if the client is behind a firewall. It instructs the client to disconnect idle connections, but re-establish them at specific intervals. It is therefore more conservative in terms of resource usage, but it may cause unwanted delays.

These modes of operation can be combined. For example, a combination between using callbacks and polling will ensure that the system will work whether the client is behind a firewall or not, but it will provide better performance in the best case scenario (no firewall).

The communication layer is conservative, in the sense that before a connection is initiated, it will try to search for any other existing connection that can be used to transmit a certain bit of information, irrespective of the initiator of the connection, and only if such a search fails, will it consider establishing a new connection.

The configuration can be changed by editing etc/remote.properties. The file contains a set of pairs of domain expressions and connection properties. The entries are considered in the reverse order from that in which they appear in the file. In other words, the first entry will be considered last, only if no other matching entry can be found. The domain expression is a regular expression which is matched against the domain name of the service host. The connection properties are a set of comma separated options. These options are described in the following table:

keepalive(timeout) 
Indicates that the connection is to be kept alive. The optional timeout indicates that the connection should be also kept alive for the specified number of seconds, even if no actual data is sent through.
reconnect 
This option instructs the system to re-initiate a connection in the event that a connection loss occurs. By default, failed connections will not be re-established.
callback 
Instructs services to connect to the client if no existing connection can be used for sending data. A client will have started a local service before the first connection with the service for which a callback configuration exists is established.
poll(interval) 
Instructs the client to poll the service for updates. The service will buffer all data that it needs to send to the client, and commit the buffered data when the client initiates a polling run. The interval indicates, in seconds, the interval at which the client should initiate the polls.

An example configuration is listed below:

#default to persistent connections
#this one is reached if no other entry matches
".*" keepalive(120), reconnect

#callbacks can safely be used within our own domain
".*mydomain.com" callback

#there's a firewall between mydomain.com and otherdomain.com, so
#we poll every 2 minutes
".*otherdomain.com" poll(120)
#for the sake of this example, a combination of callback and polling
#if callbacks don't work, polling will pick things up
".*thirddomain.org" callback, poll(120)

The Secure (Grid-Mapped) Local Provider

In order to build the secure local provider, the following steps must be taken:

  • If a previous build was performed, run ant distclean
  • Edit the abstractions dependency file in cog/modules/abstraction/dependencies.xml
  • Change the dependency on the provider-local to provider-slocal:
<ant antfile="${main.buildfile}" target="dep">
  <property name="module" value="provider-slocal"/>
</ant>
  • Re-compile with ant dist

At this time, the secure local provider only implements job execution (execute). File operations are not yet implemented.

The secure local provider uses a gridmap file, which describes a maping of GSS distinguished names to local user accounts. For details about gridmap files, take a look at [Identity Mapping Information]

The actual mapping is done using sudo and a simple job wrapper. Sudo must be configured to allow the execution of the wrapper under target user accounts without a password. An example sudo configuration is shown below:

<shared_username> ALL=(<target_usernames_list>) NOPASSWD: <cog_path>/libexec/job-wrapper

Where <shared_username> is the username of the account under which the shared service is running, <target_usernames_list> is a comma separated list of user-names which the provider can map to (these must also be correctly configured in the gridmap file), and <cog_path> is the absolute path to the CoG/Karajan installation.

If the target user account is the same as the shared user account, the secure local provider can be configured to bypass sudo (which it does by default).

The provider configuration file (etc/provider-slocal.properties), supports the following properties:

grid.mapfile 
Indicates the location of the gridmap file. The default is /etc/grid-security/grid-mapfile.
sudo 
Points to the location of sudo.
nosudo 
If the target user is the same as the user under which the shared service is running, then the value of this property will be used as the path to a program used to start the wrapper.
job.wrapper 
The location of the wrapper. It defaults to <cog_path>/libexec/job-wrapper, therefore it should not be necessary to specify this property unless a non-standard configuration is used.

An example configuration file is shown below:

grid.mapfile=/etc/grid-security/grid-mapfile

sudo=/usr/bin/sudo

nosudo=/bin/bash

job.wrapper=/home/karajan/cog/libexec/job-wrapper

Notes

1. There should be a way to allow invocations of certain “safe” methods, as defined by an administrative policy
Personal tools
Collaboration and Jobs