4. Remote Cache Object Filtering

Previous chapter

Next chapter

GemStone provides object-level security by associating specific objects with an ObjectSecurityPolicy. By managing ObjectSecurityPolicies, you can prevent users from reading or modifying protected objects.

However, this does not prevent all risk of data exposure on a remote node. GemStone’s database pages may contain multiple objects, and when pages containing objects that are allowed to be read by the user session are transmitted to a remote cache, objects that cannot be read may still "ride along".

Object filtering in X509-secured environments provides specific control over exactly which objects are allowed to be transmitted to any given remote cache.

4.1 Overview

Overview of Object level security

The previously existing object level security associated each object in the repository with an instance of ObjectSecurityPolicy (known as Segments in older versions of GemStone), or with nil, which means there are no restrictions. GemStone base defines ten system ObjectSecurityPolicies, and users may define up to 64K application-specific policies.

ObjectSecurityPolicy permissions are based on the GemStone user ID. Sessions that are logged in with a specific userId will be allowed to read or modify objects if the policy associated with that object give that user read or write permission for the owner, group or world.

Persistent objects in the extents and cache are on pages, and a page may contain multiple unrelated objects. When an object is read, the entire page holding that object is loaded into the shared page cache, and/or transmitted to the remote cache. When a Gem session accesses an object, the policy for that object is checked against the Gem’s userId, before allowing the object on the page to be faulted into the application’s object space.

While this effectively prevents the user f rom accessing sensitive data, the sensitive data may still be present in a remote shared page cache. Using Object Filtering, it is possible to prevent sensitive data from being transmitted out of the Stone’s shared page cache at all.

Object Filtering

Object filtering adds another layer of protection for sensitive data. This is implemented by associating GemStone’s existing object-level security mechanism, with IP address range-based filtering policies. By configuring the IP address range to which each object may be transmitted, you can control exactly where that data can be present.

  • Object filtering is performed by the HostAgent on the Stone’s node, and only applies to X509-secured remote caches.
  • Filtering only applies to remote caches; there is (of necessity) no restriction on what is loaded into the Stone’s shared page cache
  • Objects associated with the SecurityDataObjectSecurityPolicy may never be transmitted to any host that is using x509 logins, regardless of any filtering configuration.

If a Smalltalk application with a X509-secured Gem attempts to access an object that is not allowed to be transmitted to the Gem’s host, then the application cannot read that object, regardless of the object’s object security policy read and write permissions.

If that application attempts to access an object that is allowed to be transmitted, then the object’s object security policy applies, which may allow that object to be read or not, just as in previous GemStone versions.

Object Filtering support classes

The classes IPv4Subnet, ObjectFilteringPolicy, and ObjectFilteringPolicyMap allow object filtering to be configured.

IPv4Subnet allows naming of CIDR address masks, to make management easier. (IPv6 networks are not currently supported with GemStone x509 logins).

An instance of ObjectFilteringPolicy maps every possible GsObjectSecurityPolicy to an action of ALLOW or PROHIBIT. A single instance of ObjectFilteringPolicy specifies filtering for every single object in the repository; but different remote caches may use different instances of ObjectFilteringPolicy.

There is one ObjectFilteringPolicyMap installed, which maps every possible IP address to an instance of ObjectFilteringPolicy, which is what would be used for a remote node on that IP address.

The keys in the ObjectFilteringPolicyMap are instances of IPv4Subnet, which specify ranges rather than specific IP addresses. This allows the application to define multiple overlapping policies, including policies that apply to all IP address, one specific IP address, or various ranges of IP address. When looking up the IP address for a specific remote cache, the most specific IP address range that contains that IP address is used.

The global instance of ObjectFilteringPolicyMap is installed in the image by DataCurator, using the method

ObjectFilteringPolicyMap >> installObjectFilter

The map is stored under the key named #ObjectFilter in the HostAgentUser’s UserGlobals.

Note that a new instance of ObjectFilteringPolicyMap, including the instance in new or newly upgraded repositories, has a default action of DISALLOW and may not be very usable; users with object security problems may not be able to login at all. Applications are expected to execute code to install an appropriately configured instance of ObjectFilteringPolicyMap. This default avoids inadvertent exposures at the cost of extra effort on the initial setup.

You can define and install a filter that allows all objects to be sent to remote caches on any of your organization’s internal network nodes (with IP addresses 10.*.*.*), by logging in as DataCurator and executing code such as this:

topaz 1> run
| snet pol |
snet := IPv4Subnet named: 'internal_ips' forSubnet: '10.0.0.0/8'.
pol := ObjectFilteringPolicy new 
	name: 'policy_allow_internal'; allowByDefault; 
	yourself.
(ObjectFilteringPolicyMap new)
	atSubnet: snet putPolicy: pol;
	installObjectFilter.
System commit.
%

The newly added filtering classes and objects are themselves in a new GsObjectSecurityPolicy, HostAgentDataSecurityPolicy. This security policy is mapped to PROHIBIT, since they are never needed outside of the Stone’s node.

4.2 Details on Classes that implement Object Filtering

Object filtering is implemented using several classes that allow you to specify the particular filtering requirements, and map these to one or more GsObjectSecurityPolicies.

IPv4Subnet

An IPv4Subnet allows subnets to be associated with names. This avoids the need to remember IP specific address ranges in a large network, and reduces the risk of errors.

Public class messages:

IPv4Subnet class >> named: nameString forSubnet: cidrString
This is the public instance creation message. The nameString argument can be any string. The cidrString must be a string specifying a valid CIDR subnet.

IPv4Subnet >> name
Answers the receiver’s name string.

IPv4Subnet >> cidrString
Answers the receiver’s CIDR string.

ObjectFilteringPolicy

An instance of ObjectFilteringPolicy maps all possible GsObjectSecurityPolicies to a filtering action of ALLOW or PROHIBIT.

When a particular ObjectFilteringPolicy is in use for a remote cache, an object’s GsObjectSecurityPolicy will map to either ALLOW or PROHIBIT, which will determine if that particular object will be transmitted to that remote cache.

Creation

ObjectFilteringPolicies are created using ObjectFilteringPolicy class >> new. A newly-created ObjectFilteringPolicy maps all GsObjectSecurityPolicies to an action of PROHIBIT (with some exceptions).

Each ObjectFilteringPolicy has a name, by default nil. It is recommended to give each ObjectFilteringPolicy a unique name to make them easier to manage and validate.

name: aString
Sets the name of the policy.

name
Answers the name of the policy, or nil if no name has been set.

Specifying mappings

An ObjectFilteringPolicy has two collections of GsObjectSecurityPolicies: one collection whose action should be ALLOW and another whose action should be PROHIBIT. There is a default action of ALLOW or PROHIBIT which applies to any GsObjectSecurityPolicy that has not specifically been added to either collection.

The following methods are used to define the mappings:

allowByDefault
Sets the default action of the receiver to ALLOW.

prohibitByDefault
Sets the default action of the receiver to PROHIBIT.

allow: aGsObjectSecurityPolicy
Adds the given security policy to the ALLOW collection, and removes it from the PROHIBIT collection (if there).

prohibit: aGsObjectSecurityPolicy
Adds the given security policy to the PROHIBIT collection, and removes it from the ALLOW collection (if there).

allowAll: aCollection
Add every security policy in aCollection to the ALLOW collection, and remove from the PROHIBIT collection if present.

prohibitAll: aCollection
Add every security policy in aCollection to the PROHIBIT collection, and remove from the ALLOW collection if present.

ObjectFilteringPolicyMap

An ObjectFilteringPolicyMap maps every possible IPv4 address to an ObjectFilteringPolicy that should be used for a host at that IPv4 address.

The ObjectFilteringPolicyMap keys are subnet masks (instance of IPv4Subnet), rather than specific IPv4 addresses. There may be more than one mapping that applies to a specific address, if the keys have different mask integers.

At runtime, when the map is queried for the ObjectFilteringPolicy to be used for a specific IP address, it returns the most selective entry, which is the entry with the largest mask integer that includes the argument.

For example, a ObjectFilteringPolicyMap may includes entries for the following subnets:

0.0.0.0/0 -> anObjectFilterPolicy1
10.0.0.0/8 -> anObjectFilterPolicy2
10.12.0.0/16 -> anObjectFilterPolicy3
10.12.241.0/24 -> anObjectFilterPolicy4
10.12.241.67/32 -> anObjectFilterPolicy5

In this case, querying for the IP address 10.12.241.67 would return anObjectFilterPolicy5, and for the IP address 10.12.112.17 would return anObjectFilterPolicy3.

Each instance of ObjectFilteringPolicyMap always contains a mapping for subnet 0.0.0.0/0 (which is the CIDR subnet containing the entire IPv4 address space). This mapping will normally be overridden, but ensures that any well-formed IPv4 address has a mapping.

Specifying and looking up policies within a map

ObjectFilteringPolicyMap >> atSubnet: anIPv4Subnet putPolicy: anObjectFilteringPolicy
Add a mapping for the given subnet, or replace the mapping for the subnet if the receiver already has a mapping for that subnet.

ObjectFilteringPolicyMap >> policiesForSubnet: anIPv4Subnet
Answer a collection of Associations. Each association’s key is an IPv4Subnet, and its value is an ObjectFilteringPolicy. The result will include mappings for all the policies in effect for all addresses in the subnet anIPv4Subnet.

This will always include the mapping for 0.0.0.0/0, and may include multiple mappings that apply to some or all of the addresses described by anIPv4Subnet. If there was no policy specified for the given anIPv4Subnet, then there will be no mapping with that key; only the mappings that cover that particular range are returned.

ObjectFilteringPolicyMap >> policyForIP: ipAddrString
Answers the policy for the given IP address string, which must be a valid dotted-quad string. The policy answered will be the policy defined for the smallest mapped subnet which contains the given IP address, that is, the one with the largest mask integer. Any well-formed IPv4 address string will always map to a policy, since the mapping for 0.0.0.0/0 covers all possible addresses.

Note that there is no API for removing mappings. It is recommended to maintain Smalltalk scripts to build and rebuild the map as security properties are updated. Reviewing Smalltalk code is less error-prone than making ad-hoc adjustments to a complex data structure.

Installing and finding out about the defined map/ObjectFilter

The following methods allow you to set and fetch the information about the current instance of ObjectFilteringPolicyMap. Note that these names are subject to change in later alpha versions.

ObjectFilteringPolicyMap >> mappingReport
Answers a string detailing the policies for all subnets.

ObjectFilteringPolicyMap >> installObjectFilter
Install the receiver into HostAgentUser’s UserGlobals at: #ObjectFilter. Once committed, this will be the filter for newly started HostAgents.

Note that this does NOT affect existing HostAgents. You must restart the HostAgent on the Stone’s node in order for the new filter map to be in effect.

ObjectFilteringPolicyMap class >> installedObjectFilter
Return the currently installed instance of ObjectFilteringPolicyMap, from HostAgentUser’s UserGlobals at: #ObjectFilter.

UnauthorizedObjectStub

When the HostAgent filters objects from the results sent to the remote node, an instance of UnauthorizedObjectStub represent objects for which an object fault would signal a SecurityError for no read authorization.

This instance is in the data page, and will only be visible to a Gem on that node if the Gem attempts to access the object. If the UnauthorizedObjectStub is replacing an object on a page that happens to be "riding along" with data that a user does have authorization to see, the presence of the UnauthorizedObjectStub will be unnoticeable to the user.

4.3 ObjectFilter internal and usage details

GemStone may have a maximum of 65536 (64K) GsObjectSecurityPolicies, which allows a ObjectFilteringPolicy to be converted into a 8192-byte ByteArray, which has 64K bits. Each bit represents a possible GsObjectSecurityPolicy. It is likely most of them will not be in use, and be set according to the default action for the ObjectFilteringPolicy. Each bit is either 0 to allow objects with the associated security policy to be transmitted, or 1 to disallow transmission.

When a HostAgent is started up for a specific remote node, it looks up that node’s IP address in the installed ObjectFilter. This returns the object filtering policy that applies for the remote node.

The filter is converted into a ByteArray, which is passed to the page server thread in the HostAgent that serves that remote node. As processes on the remote node request pages, each object on the page is examined, and for any objects that are disallowed for transmission, it will replace an UnauthorizedObjectStub for that object on that portion of the page.

Changing the ObjectFilter

Changes to ObjectFilter during the lifetime of a HostAgent have no effect, since the ObjectFilter map is only consulted at HostAgent startup. After an ObjectFilter is reinstalled, all existing HostAgents will continue to use the old policies, but any newly-created HostAgents will use the new policies.

To update the policy for a remote node, shut down all Gems and the shared page cache on the remote node machine, then stop the HostAgent’s session. The next restart of the NetLDI on the remote node, or new login using the existing NetLDI, will restart the cache and HostAgent, which will use the new ObjectFilter.

Filtering and mid level caches

When a mid level cache is used, there can be two transmissions of objects:

  • from the stone host to the mid level cache host
  • from the mid level cache host to the leaf cache host.

To prevent inconsistencies between the contents of pages in the mid level cache and pages in the leaf caches it serves, ObjectFilteringPolicy for the mid level cache host must be equal to the ObjectFilteringPolicy of each of its leaf caches. This restriction is enforced by HostAgents on the Stone’s node.

When a Gem on a leaf cache attempts to connect to a mid-level cache, and the ObjectFilteringPolicy for the Gem’s leaf cache does not match the ObjectFilteringPolicy for the mid-level cache node, the Stone’s HostAgent will reject the request.

Since the mid level cache and all of the leaf cache hosts it serves have equivalent ObjectFilteringPolicies, mid level cache hosts do not need to perform filtering when sending pages to leaf hosts. The Mid-level cache HostAgent does not do any filtering.

 

Previous chapter

Next chapter