Custom Authentication Security Plug-in in Ignite

Keywords: Big Data JDBC xml Apache REST

After Ignite cluster is built, the application can access the cluster for various operations. But the default cluster has no security protection mechanism. Any application and client supporting JDBC can access the cluster as long as they know the IP address of the cluster node, which creates a certain security risk, which is sensitive to holding number. According to users, it is obviously unacceptable.

Ignite itself has a simple security module, which provides an authentication mechanism based on username/password. However, in actual business scenarios, the requirements are often more complex. This paper takes the white list authentication as an example to illustrate how to meet their business needs by customizing security plug-ins.

Plug-in unit

Ignite has a well-designed modular architecture and plug-in mechanism. It can configure different modules or customize its own plug-ins. This article describes how to replace the default security implementation.

The first step is to inject a plug-in into Ignite Configuration. This example uses an XML-based configuration, which is as follows:

<bean id="ignite" class="org.apache.ignite.configuration.IgniteConfiguration"
      p:gridName="mygrid">

    <property name="pluginConfigurations">
        <bean class="ignite.WhiteListPluginConfiguration"/>
    </property>
</bean>

The implementation of this configuration class is nothing special, just to create a plug-in provider:

public class WhiteListPluginConfiguration implements PluginConfiguration {
    @Override
    public Class<? extends PluginProvider> providerClass() {
        return WhiteListPluginProvider.class;
    }
}

The plug-in provider class will be initialized by IgniteKernal at startup, allowing you to create plug-ins that support different interfaces. This article is interested in security plug-ins, so we will create an implementation of GridSecurity Processor:

public class WhiteListPluginProvider
                  implements PluginProvider<WhiteListPluginConfiguration> {

    @Override
    public String name() {
        return "WhiteListSecurity";
    }

    @Override
    public String version() {
        return "1.0.0";
    }

    @Nullable
    @Override
    public Object createComponent(PluginContext ctx, Class cls) {
        if (cls.isAssignableFrom(GridSecurityProcessor.class)) {
            return new WhiteListSecurityProcessor();
        } else {
            return null;
        }
    }

    @Override
    public IgnitePlugin plugin() {
        return new WhiteListAuthenticator();
    }

    //all other methods are no-op
}

Notice the createComponent method and plugin method here.

Most of the other methods on this class are empty implementations.

WhiteListSecurityProcessor

So far, security plug-ins have been created and installed in Ignite, and the rest is to implement specific authentication and authorization logic. This paper only focuses on authentication, which will grant all permissions after the authentication is passed.

The following are the main code snippets:

public class WhiteListSecurityProcessor
                          implements DiscoverySpiNodeAuthenticator,
                                     GridSecurityProcessor,
                                     IgnitePlugin {

    //the hosts that will be allowed to join the cluster
    private Set<String> whitelist = new HashSet<>();

    private boolean isAddressOk(Collection<String> addresses) {
        //return true if the address is in the whitelist
    }

    @Override
    public SecurityContext authenticateNode(ClusterNode node,
                                                SecurityCredentials cred)
                                                throws IgniteException {

        return new SecurityContext(new SecuritySubject() {

            @Override
            public SecurityPermissionSet permissions() {
                if (isAddressOk(node.addresses())) {
                    return WhiteListPermissionSets.ALLOW_ALL;
                } else {
                    return WhiteListPermissionSets.ALLOW_NONE;
                }
            }

            //all other methods are noop

        });
    }

    @Override
    public boolean isGlobalNodeAuthentication() {
        //allow any node to perform the authentication
        return true;
    }

    @Override
    public void start() throws IgniteCheckedException {
        //load the whitelist
        //check that this process is running on a white listed server
        //if there's a problem throw new IgniteCheckedException
    }

    @Nullable
    @Override
    public IgniteSpiNodeValidationResult validateNode(ClusterNode node) {
        if (!isAddressOk(node.addresses())) {
            return new IgniteSpiNodeValidationResult(node.id(),
                                                     "Access denied",
                                                     "Access denied");
        } else {
            return null;
        }
    }

    //all other methods are noop

}

This is just a pseudo code, the specific implementation needs developers to play according to their own needs.

The start method is called when Ignite starts, so this is the right place to load the whitelist IP address. It can also be used to verify whether the process is running on a whitelist server, and if there is any problem, an IgniteCheckedException exception can be thrown, which can cause the process to terminate and output error messages.

When a new node starts and tries to access, the authenticateNode and validateNode methods are invoked sequentially. Calling authenticateNode requires returning a security context that identifies the permissions granted to the process. For security, an ALLOW_NONE policy is returned if the IP address is not on the whitelist. Then call validateNode, where you can get the IP address of the connecting node and determine whether it can join the cluster.

For an example of how to create a policy list, see Ignite's GridOsSecurity Processor class.

Similarly, there are many non-operational approaches that need to be implemented, but they have nothing to do with the topic of this article.

Last

This is just a simple example of how to customize Ignite plug-ins, especially authentication plug-ins. If a node failure is used to handle authentication, a new node is selected and the service is restored.

Posted by adamwhiles on Tue, 17 Sep 2019 22:56:05 -0700