ID | IEP-38 |
Author | |
Sponsor | |
Created | 16.10.2019 |
Status | ACTIVE |
For now, a user-defined code that executes on a remote node can utilize all feature Java to get access to host resources.
For example, it can create/update/delete files; create sockets; read/update/delete system properties; use reflection API and so on.
That behavior leads to security lack.
To protect resources on a remote node, we should restrict the opportunities of user-defined code.
To protect crucial system resources, we should use the Java Sandbox.
The Sandbox is composed of the next elements:
Java uses a stack-based access control mechanism.
The standard security check ensures that each frame (Protection Domain) in the call stack has the required permission.
That is, the current permissions in force are the intersection of the permissions of each frame in the current access control context.
If any frame does not have permission, no matter where it lies in the stack, then the current context does not have that permission.
We have the opportunity to dynamically update the Protection Domains associated with the current AccessControlContext using the DomainCombiner interface.
A DomainCombiner is passed as a parameter to the appropriate constructor for AccessControlContext.
The newly constructed context is then passed to the AccessController.doPrivileged(..., context) method to bind the provided context (and associated DomainCombiner) with the current execution Thread.
Subsequent calls to AccessController.getContext or AccessController.checkPermission cause the DomainCombiner.combine to get invoked.
That is the basis to implement the integration of the Java Sandbox with Apache Ignite.
The main unit of the Ignite Sandbox is the IgniteSandbox interface, accessed through IgniteSecurity.
Users for this interface are components that can run a user-defined code. To run a user-defined code with restrictions,
they have to pass it to the IgniteSandbox.execute method.
There are a few conditions to run user-defined code with restrictions:
If these conditions in the place, an instance of the AccessControllerSandbox class that is the implementation of IgniteSandbox runs a user-defined code with restrictions as follow:
IgniteDomainCombiner is responsible for updating the Protection Domains with permissions of the current SecuritySubject.
A user-defined code should have the opportunity of using the public API of Ignite on a remote node.
But he may don't have some permissions to execute this operation successfully. For example, to put a value into a cache,
it requires permissions for accessing to reflection API and reading system property IGNITE_ALLOW_ATOMIC_OPS_IN_TX.
In that case, we have to use AccessController.doPrirvelged without AccessControlContext call to exclude a user-defined code from checking of permissions.
We can achieve that behavior by using a proxy of interface Ignite that executes methods inside a privileged block. Builder methods of Ignite proxy create a proxy of public interfaces (IgniteCache, IgniteCompute, and so on) that run their methods inside a privileged block too.
Additionally, using of Ignite proxy allows restricting access of a user-defined code to internal Ignite classes.
Phase 1 covers using the Sandbox for features:
The existing implementations of interfaces Runnable, IgniteRunnable,
Callable.class, IgniteCallable, ComputeTask, ComputeJob, IgniteClosure, IgniteBiClosure, IgniteDataStreamer, IgnitePredicate,
IgniteBiPredicate cannot cast the instance of Ignite to IgniteEx or IgniteKernal if the Sandbox is enabled.
https://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-spec.doc1.html#a18313
https://docs.oracle.com/javase/8/docs/api/java/security/AccessController.html
https://docs.oracle.com/javase/7/docs/api/java/security/AccessControlContext.html
https://docs.oracle.com/javase/7/docs/api/java/security/DomainCombiner.html
https://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-spec.doc6.html#a19349