如何实现ignite的安全插件(security plugin)
Ignite可以实现自定义的安全插件,以下实现在2.13.0测试可行。
1.如何实现自定义的安全插件
第一步:需要定义一个提供插件的类,它会被IgniteKernal在启动时调用,主要实现的是createComponent和plugin方法
public class NodeAuthenticationPluginProvider implements PluginConfiguration, PluginProvider<IgniteSecurityPluginProvider> { ... @Override public IgnitePlugin plugin() { return new NodeAuthenticationProcessor(); } ... @Override public Object createComponent(PluginContext ctx, Class cls) { if (cls.isAssignableFrom(GridSecurityProcessor.class)) { return new NodeAuthenticationProcessor(); } else { return null; } } }
可以通过以下两种方法:
1)IgniteConfiguration.setPluginProviders()
2)Service loader
早期版本的官网推荐的是方式二,目前最新版本的官网推荐的是方式一(参考:https://ignite.apache.org/docs/latest/plugins)
鉴于方式一可以在官网查询,所以介绍下方式二如何注册:
配置META-INF/services/org.apache.ignite.plugin.PluginProvider
yourpackage.NodeAuthenticationPluginProvider
第三步:实现具体的安全插件类 NodeAuthenticationProcessor, 具体的插件类需要实现GridSecurityProcessor和IgnitePlugin 接口,它主要有几个需要override的函数
函数名 | 作用 |
authenticateNode |
当任何ignite server还是clinet node需要加入ignite topology,这个函数会被调用: 如果node允许加入需要返回一个SecurityContextImpl对象 |
authenticate |
当client需要连接到ignite server或者jetty server,那么这个函数会被调用; 这个和之前的client node的区别是这个client并不会加入到ignite topology里,只是连接; 典型的场景:运行自带的 control.sh / Rest API |
enabled |
必须返回true! 只有这个返回true,这个自定义的plugin才会被ignite使用,否则ignite会new一个NoOpIgniteSecurityProcessor对象 |
validateNode |
当任何ignite server还是clinet node需要加入ignite topology,这个函数会被调用: 如果node允许加入需要返回一个null,如果不同意加入,那么返回一个IgniteNodeValidationResult |
isGlobalNodeAuthenticatio n |
如果是false,只有coordinator 运行authentication; 如果是true,那么所有node都可以运行authentication; |
securityContext |
如果是true,那么所有node都可以运行authentication;当一个thin client连接到ignite的时候,这个函数就会被调用,如果允许thin client连接,那么返回一个SecurityContextImpl对象 |
(为啥这样,是因为我们公司在ignite 2.7.5的版本就实现了这个plugin,当时借用的是validateNode这个函数,所以在新版本保持和老版本一致的功能...)
public class NodeAuthenticationProcessor implements GridSecurityProcessor, IgnitePlugin { ... @Override //Current implementation allows any Ignite node to join the Ignite Cluster Topology without authentication check public SecurityContext authenticateNode(ClusterNode clusterNode, SecurityCredentials securityCredentials) throws IgniteCheckedException { return new SecurityContextImpl(clusterNode.id(), new InetSocketAddress(F.first(clusterNode.addresses()), 0)); } @Override //Current implementation allows any client to connect without authentication check public SecurityContext authenticate(AuthenticationContext authenticationContext) throws IgniteCheckedException { return new SecurityContextImpl(authenticationContext.subjectId(),authenticationContext.address()); } @Override //Set to true to let the plugin inject into ignite public boolean enabled() { return true; } @Nullable @Override //It will be called to judge if a node can join topology public IgniteNodeValidationResult validateNode(ClusterNode clusterNode) { //Failed validation if(!nodeCanJoin(clusterNode)){ String msg = "Access denied by " + this.getClass().getCanonicalName(); return new IgniteNodeValidationResult(clusterNode.id(), msg, msg); //Pass validation }else return null; } //Current implementation always return SecurityContext because we don't really authenticate thin client. @Override public SecurityContext securityContext(UUID subjId) { return new SecurityContextImpl(subjId,null); } @Override /* false means only coordinator should run the authentication for joining node; true means all nodes can run the authentication for joining node; */ public boolean isGlobalNodeAuthentication() { return false; } ... }
第四步:传递一个SecurityCredentials 给ignite node
虽然我们不用SecurityCredentials 来验证一个node能不能加入到ignite cluster,但是在你实现了pulgin后,要想它能work,必须传递一个SecurityCredentials 给 ignite node;
因为在 ignite 2.13.0的源码里, 第一个加入到topology的node会检查自己是否有SecurityCredentials(在 localAuthentication() 这个函数里),源代码具体如下:
private void joinTopology() throws IgniteSpiException { ... while (true) { if (!sendJoinRequestMessage(joinReqMsg)) { if (log.isDebugEnabled()) log.debug("Join request message has not been sent (local node is the first in the topology)."); if (!auth && spi.nodeAuth != null) //call localAuthentication to check if it contains SecurityCredentials localAuthentication(locCred); ... } private void localAuthentication(SecurityCredentials locCred) { try { locNode.setAttributes(withSecurityContext( authenticateLocalNode(locNode, locCred, spi.nodeAuth), locNode.attributes(), spi.marshaller() )); } catch (IgniteException | IgniteCheckedException e) { throw new IgniteSpiException("Failed to authenticate local node (will shutdown local node).", e); } } ...
所以需要有一个方法来传递SecurityCredentials,比较常见的一个方式(来自于网络搜索)是定义一个继承自TcpDiscoverySpi 类去传递SecurityCredentials,代码如下:
public class CustomTcpDiscoverySpi extends TcpDiscoverySpi { //The SecurityCredentials is added in order to pass assert code in ignite; private final SecurityCredentials securityCredentials = new SecurityCredentials(); @Override protected void initLocalNode(int srvPort, boolean addExtAddrAttr) { super.initLocalNode(srvPort, addExtAddrAttr); passSecurityCredentialsToNodeAttributes(); } private void passSecurityCredentialsToNodeAttributes() { Map<String,Object> attributes = new HashMap<>(locNode.getAttributes()); attributes.put(IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS, securityCredentials); this.locNode.setAttributes(attributes); } }
然后把以上自定义的类设置到ignite-config.xml里
... <bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration"> ... <property name="discoverySpi"> <bean class="com.tekcomms.ia.provisioning.lookup.jcache.CustomTcpDiscoverySpi"> ...
2.自定义的安全插件是如何在ignite work的
参考以下Ignite的源码(IgniteKernal.class)
private
GridProcessor securityProcessor()
throws
IgniteCheckedException {
/*If custom plguin proveider is defined, it's createComponent method will be called;
In our case, it will call NodeAuthenticationPluginProvider.createComponent to
return custom defined NodeAuthenticationProcessor object which implements GridSecurityProcessor.
*/
GridSecurityProcessor prc = createComponent(GridSecurityProcessor.
class
, ctx);
if
(cfg.isAuthenticationEnabled() && !(prc
instanceof
IgniteAuthenticationProcessor)) {
throw
new
IgniteCheckedException(
"Invalid security configuration: both authentication is enabled"
+
" and external security plugin is provided."
);
}
//Custome implemented GridSecurityProcessor will be pass to create IgniteSecurityProcessor object.
return
prc !=
null
&& prc.enabled()
?
new
IgniteSecurityProcessor(ctx, prc)
:
new
NoOpIgniteSecurityProcessor(ctx);
}
posted on 2022-12-11 23:23 cherryjing0629 阅读(260) 评论(0) 编辑 收藏 举报