为了保证缓存中数据的安全性,私密性。我们的需求是打开Ignite的安全认证机制,不允许非法的Ignite节点或者JDBC连接能够连上我们的生产Ignite集群;必须持有有效的身份信息(用户名、密码)才能够连上现有集群。
为了实现这一需求,我首先从Ignite文档入手,文档推荐修改配置,添加插件,实现接口。。我跟着一步步实现了,但是到最后需要在Ignite启动时声明SecurityCredentials(用户名,密码)的时候,所有文档和社区中完全找不到一种有效方式能够实现,我自己调查了半天也没有思路。于是我转向stackoverflow,终于在一个post中找到了一种解决方案,这个方案跟文档指定的思路完全不同。。并且比文档的实现思路要简单很多很多。。。
所以直接把这个链接发出来,如果有人需要实现Ignite认证的话可以直接参照这个post来:
https://stackoverflow.com/questions/51261521/authentication-for-apache-ignite-2-5
下面是文档的解决思路,目前不知道怎么走通这条线。但还是记录一下过程,未来也许会解决。
IgniteConfiguration中把这个开关打开:
,
其实只是管控住了JDBC连接,比如我通过DBeaver这种工具,连接localhost:10800时,会强制我输入用户名密码。这里如果用IgniteThinClient的话应该也会受限制,我还没有试,因为它也是通过JDBC创建连接。
但是,别的Ignite Server/Client节点加入进来还是不受管控。如果想要在这一层也做安全管控的话,还是要通过实现Ignite的GridSecurityProcessor接口来做一个插件来完成。
接下来会不断尝试如何实现这一步。我用的是Ignite当前最新版本2.7
首先基本大家都能找到这篇文章:http://smartkey.co.uk/development/securing-an-apache-ignite-cluster/
这篇写得比较早,当时还是Ignite 1.5版本,现在升级后不能完全适用,但是能给大家带来一个好的开始。
然后我按照这篇文章指导之后,发现无法加载到自定义的插件。
最后查阅社区,发现是Ignite文档中放置路径没写对。文件应该这样放:
放对位置之后,发现能够加载到插件了。此时在Ignite启动日志中会打印出来:
这里打印出来的是name, version, copyright,你都可以随便写。
以下是根据上面文章中生成的代码:
import org.apache.ignite.plugin.PluginConfiguration;
import org.apache.ignite.plugin.PluginProvider;
public class WhiteListPluginConfiguration implements PluginConfiguration {
public Class extends PluginProvider> providerClass() {
return WhiteListPluginProvider.class;
}
}
import java.io.Serializable;
import java.util.UUID;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.processors.security.GridSecurityProcessor;
import org.apache.ignite.plugin.CachePluginContext;
import org.apache.ignite.plugin.CachePluginProvider;
import org.apache.ignite.plugin.ExtensionRegistry;
import org.apache.ignite.plugin.IgnitePlugin;
import org.apache.ignite.plugin.PluginContext;
import org.apache.ignite.plugin.PluginProvider;
import org.apache.ignite.plugin.PluginValidationException;
public class WhiteListPluginProvider implements PluginProvider {
@Override
public String name() {
return "WhiteListSecurityProcessor";
}
@Override
public String version() {
return "0.0.1";
}
@Override
public String copyright() {
return "Pilot FAST team - Jeff Jiao";
}
@SuppressWarnings("unchecked")
@Override
public T plugin() {
return (T) new WhiteListSecurityProcessor();
}
@Override
public void initExtensions(PluginContext ctx, ExtensionRegistry registry) throws IgniteCheckedException {
// TODO Auto-generated method stub
}
@Override
public T createComponent(PluginContext ctx, Class cls) {
if (cls.isAssignableFrom(GridSecurityProcessor.class)) {
return (T) new WhiteListSecurityProcessor();
} else {
return null;
}
}
@Override
public CachePluginProvider createCacheProvider(CachePluginContext ctx) {
// TODO Auto-generated method stub
return null;
}
@Override
public void start(PluginContext ctx) throws IgniteCheckedException {
// TODO Auto-generated method stub
}
@Override
public void stop(boolean cancel) throws IgniteCheckedException {
// TODO Auto-generated method stub
}
@Override
public void onIgniteStart() throws IgniteCheckedException {
// TODO Auto-generated method stub
}
@Override
public void onIgniteStop(boolean cancel) {
// TODO Auto-generated method stub
}
@Override
public Serializable provideDiscoveryData(UUID nodeId) {
// TODO Auto-generated method stub
return null;
}
@Override
public void receiveDiscoveryData(UUID nodeId, Serializable data) {
// TODO Auto-generated method stub
}
@Override
public void validateNewNode(ClusterNode node) throws PluginValidationException {
// TODO Auto-generated method stub
}
}
import java.util.Collection;
import java.util.UUID;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.processors.security.GridSecurityProcessor;
import org.apache.ignite.internal.processors.security.SecurityContext;
import org.apache.ignite.lang.IgniteFuture;
import org.apache.ignite.plugin.IgnitePlugin;
import org.apache.ignite.plugin.security.AuthenticationContext;
import org.apache.ignite.plugin.security.SecurityCredentials;
import org.apache.ignite.plugin.security.SecurityException;
import org.apache.ignite.plugin.security.SecurityPermission;
import org.apache.ignite.plugin.security.SecuritySubject;
import org.apache.ignite.spi.IgniteNodeValidationResult;
import org.apache.ignite.spi.discovery.DiscoveryDataBag;
import org.apache.ignite.spi.discovery.DiscoveryDataBag.GridDiscoveryData;
import org.apache.ignite.spi.discovery.DiscoveryDataBag.JoiningNodeDiscoveryData;
public class WhiteListSecurityProcessor implements IgnitePlugin, GridSecurityProcessor {
@Override
public void start() throws IgniteCheckedException {
// TODO Auto-generated method stub
}
@Override
public void stop(boolean cancel) throws IgniteCheckedException {
// TODO Auto-generated method stub
}
@Override
public void onKernalStart(boolean active) throws IgniteCheckedException {
// TODO Auto-generated method stub
}
@Override
public void onKernalStop(boolean cancel) {
// TODO Auto-generated method stub
}
@Override
public void collectJoiningNodeData(DiscoveryDataBag dataBag) {
// TODO Auto-generated method stub
}
@Override
public void collectGridNodeData(DiscoveryDataBag dataBag) {
// TODO Auto-generated method stub
}
@Override
public void onGridDataReceived(GridDiscoveryData data) {
// TODO Auto-generated method stub
}
@Override
public void onJoiningNodeDataReceived(JoiningNodeDiscoveryData data) {
// TODO Auto-generated method stub
}
@Override
public void printMemoryStats() {
// TODO Auto-generated method stub
}
@Override
public IgniteNodeValidationResult validateNode(ClusterNode node) {
if (!node.attribute("assertion").equals("IgniteClient")) {
return new IgniteNodeValidationResult(node.id(), "Access denied", "Access denied");
} else {
return null;
}
}
@Override
public IgniteNodeValidationResult validateNode(ClusterNode node, JoiningNodeDiscoveryData discoData) {
// TODO Auto-generated method stub
return null;
}
@Override
public DiscoveryDataExchangeType discoveryDataType() {
// TODO Auto-generated method stub
return null;
}
@Override
public void onDisconnected(IgniteFuture> reconnectFut) throws IgniteCheckedException {
// TODO Auto-generated method stub
}
@Override
public IgniteInternalFuture> onReconnected(boolean clusterRestarted) throws IgniteCheckedException {
// TODO Auto-generated method stub
return null;
}
@Override
public SecurityContext authenticateNode(ClusterNode node, SecurityCredentials cred) throws IgniteCheckedException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isGlobalNodeAuthentication() {
return false;
}
@Override
public SecurityContext authenticate(AuthenticationContext ctx) throws IgniteCheckedException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection authenticatedSubjects() throws IgniteCheckedException {
// TODO Auto-generated method stub
return null;
}
@Override
public SecuritySubject authenticatedSubject(UUID subjId) throws IgniteCheckedException {
// TODO Auto-generated method stub
return null;
}
@Override
public void authorize(String name, SecurityPermission perm, SecurityContext securityCtx) throws SecurityException {
// TODO Auto-generated method stub
}
@Override
public void onSessionExpired(UUID subjId) {
// TODO Auto-generated method stub
}
@Override
public boolean enabled() {
return true;
}
}
最后跑起来时候,进入authenticateNode方法时,传入的credential参数一直为null,无法插入,卡在了这里。
无法通过userAttribute插入,因为credential的默认key值被Ignite预留了,不让用户使用。