跳转到内容
Nacos 配置中心安全问题汇总及解决方案 点此了解

配置变更

配置变更插件

社区中一直以来都希望Nacos配置中心能在配置发生变更时,通知一些特定系统,用于发送记录、警告等审计功能。在2.3.0版本前,只能通过模拟Nacos客户端订阅配置的方式,对核心配置的变更操作进行订阅,在收到变更通知后,进行发送记录、警告等功能的执行。

这种实现方式有几个比较大的问题,第一是监听的配置需要逐个添加,难以对所有配置变更进行获取;第二是只能在配置变更后执行功能逻辑,无法做到前置的操作,如格式校验,白名单校验等。

因此Nacos在2.3.0版本后,支持通过SPI注入配置变更插件,允许用户通过自定义插件的方式,对配置变更前,和变更完成后分别执行一些自定义逻辑,如格式校验,白名单校验,webhook等。

配置变更插件中的概念

Nacos的配置变更插件,参考了面向切面编程AOP的设计思想,将配置的变更操作(如新增,更新,删除)作为切点(PointCut),并在这些切点前(Before)后(After)织入插件。

配置变更切点(ConfigChangePointCutTypes)

Nacos根据配置变更的行为和来源,将配置变更操作在com.alibaba.nacos.plugin.config.constants.ConfigChangePointCutTypes中定位为了数个配置变更切点(ConfigChangePointCutTypes),具体内容如下:

切点名称描述起始版本
PUBLISH_BY_HTTP配置通过HTTP接口进行发布,包含了创建配置及修改配置2.3.0
PUBLISH_BY_RPC配置通过GRPC接口进行发布,包含了创建配置及修改配置2.3.0
REMOVE_BY_HTTP配置通过HTTP接口进行删除2.3.0
REMOVE_BY_RPC配置通过GRPC接口进行删除2.3.0
IMPORT_BY_HTTP配置通过HTTP接口进行导入2.3.0
REMOVE_BATCH_HTTP配置通过HTTP接口进行批量删除2.3.0

配置变更织入类型(ConfigChangeExecuteTypes)

Nacos的配置变更插件需要在配置变更切点之前或之后进行执行,即需要选择配置变更织入类型(ConfigChangeExecuteTypes),定义在com.alibaba.nacos.plugin.config.constants.ConfigChangeExecuteTypes中,具体内容如下:

织入类型描述起始版本
EXECUTE_BEFORE_TYPE插件实现在配置变更切点执行2.3.0
EXECUTE_AFTER_TYPE插件实现在配置变更切点执行2.3.0

插件开发

开发Nacos服务端配置变更插件,首先需要依赖配置变更插件的的相关API

<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-config-plugin</artifactId>
<version>${project.version}</version>
</dependency>

${project.version} 为您开发插件所对应的Nacos版本,2.3.0及以上。

随后实现com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService接口,该接口需要实现的方法如下:

方法名入参内容返回内容描述
getServiceTypevoidString插件的名称,用于区分不同类型的插件实现
getOrdervoidint插件的执行顺序,配置变更插件采用链式插件设计,多个插件实现时会按照顺序执行,getOrder越小,顺序越靠前
executeTypevoidConfigChangeExecuteTypes插件实现的配置变更织入类型
pointcutMethodNamesvoidConfigChangePointCutTypes[]插件实现织入的配置变更切点
executeConfigChangeRequest,ConfigChangeResponsevoid实际插件执行的逻辑

其中ConfigChangeRequestConfigChangeResponse分别为执行逻辑时传入的内容及执行结果,

ConfigChangeRequest的具体内容如下:

字段名字段类型描述
requestTypeConfigChangePointCutTypes本次配置变更的切点类型
requestArgsHashMap<String, Object>本次配置变更的实际参数,主要包含有namespace,group,dataId,content等内容,不同的切点类型参数存在不同

ConfigChangeResponse 的具体内容如下:

字段名字段类型描述
responseTypeConfigChangePointCutTypes本次配置变更的切点类型
isSuccessboolean执行是否成功,当返回值为false时,将会拦截本次配置变更,并直接返回失败的结果
retValObject返回内容,预留字段,暂未启用
msgString执行结果信息,在isSuccessfalse时获取,用于返回给客户端的信息
argsObject[]配置变更操作的执行参数,在EXECUTE_BEFORE_TYPE的插件类型时生效,可用于修改实际执行的配置变更时的内容,如将content中的某些内容修改为其他值

加载插件

插件开发完成后,需要打包成jar/zip,放置到nacos服务端的classpath中,如果您不知道如何修改classpath,请直接放置到${nacos-server.path}/plugins

放置后,需要修改${nacos-server.path}/conf/application.properties中的以下配置

### 所启用的Nacos的配置变更插件的名称,与com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService 的getServiceType 返回值对应
nacos.core.config.plugin.${configChangePluginName}.enabled=true

随后重启nacos集群,启动完成后,可在${nacos-server.path}/logs/nacos.log日志中看到如下日志。

[ConfigChangePluginManager] Load ${className}(${classFullName}) ConfigChangeServiceName(${configChangePluginName}) successfully.

插件自定义参数传递

部分插件可能希望通过配置文件设置一些参数,自定义插件可以通过修改${nacos-server.path}/conf/application.properties中的以下配置完成:

### 所启用的Nacos的配置变更插件的名称,与com.alibaba.nacos.plugin.config.spi.ConfigChangePluginService 的getServiceType 返回值对应
nacos.core.config.plugin.${configChangePluginName}.${propertyKey}=${propertyValue}

之后能在ConfigChangeRequest中,通过下述方法获取该参数:

final Properties properties = (Properties) configChangeRequest.getArg(ConfigChangeConstants.PLUGIN_PROPERTIES);
final String ${propertyKey} = properties.getProperty("${propertyKey}");

插件DEMO实现

nacos-group/nacos-plugin中,有一个demo的配置变更插件的实现,该demo插件实现了对配置内容格式的校验、配置导入名称白名单的校验、以及变更后回调webhook。打包成jar/zip,放置到nacos服务端的classpath中,在${nacos-server.path}/conf/application.properties中的加入以下配置:

# webhook
#nacos.core.config.plugin.webhook.enabled=true
# It is recommended to use EB https://help.aliyun.com/document_detail/413974.html
#nacos.core.config.plugin.webhook.url=http://${webhookIp}:${webhookPort}/${webhookUri}?token=***
# The content push max capacity ,byte
#nacos.core.config.plugin.webhook.contentMaxCapacity=102400
# whitelist
#nacos.core.config.plugin.whitelist.enabled=true
# The import file suffixs
#nacos.core.config.plugin.whitelist.suffixs=xml,text,properties,yaml,html
# fileformatcheck,which validate the import file of type and content
#nacos.core.config.plugin.fileformatcheck.enabled=true