实现actuator访问安全
actuator被用于实现程序的监控,但是直接暴露相关接口非常危险,此处就需要探讨一下如何保证安全
危险来源
在SpringCloud的常规架构中,使用Gateway对外暴露服务,其他服务由Gateway代为转发。再搭建Admin用于GUI展示,利用注册中心获取实例地址端口。
一般情况下,只有Gateway会提供外网访问,其他微服务仅在内网访问,而Admin访问的时候也是获取的内网地址,比较安全。
所以最危险的就是Gateway。
最简单直接的安全方案,就是给Gateway加上Security,Admin访问的时候带上认证信息。
但是该方案过于繁琐,不是很和我心意。
经过一番搜索后,找到另一种方案,actuator支持使用别的端口。
更换端口
只需要如下配置
1 | |
这样程序会使用两个端口,一个普通的请求端口,一个actuator使用的端口。
但是,经过我的测试,实际上两个端口都能访问actuator,意思就是不管哪个端口,都可以访问http://ip:port/actuator/health等url。
关闭普通端口访问
既然新端口可以访问,那就把原本端口的相关路由给关闭了即可,给Gateway加入以下代码
1 | |
这里使用了一个过滤器,直接返回404状态。
admin访问
关闭的普通端口的访问,同时Admin那边也不能访问了,因为Admin还在访问原端口。
在翻阅admin文档后,只要在注册中心中把使用的新端口带上即可。于是增加以下配置:
1 | |
现在基本就可以正常访问了。但是我还想将这个新端口随机化,将来如果网关如果要更新,也能少设置一个端口,减少端口冲突的风险
随机端口
只需要port=0就是随机端口了。
但是这又有一个新问题,由于配置文件将端口设置为0,那么注册中心记录的端口也还是0,admin就无法访问了。
解决思路是将端口的获取由代码完成,并且将端口写入配置项中。
这里可以采用jasypt,这是一套主要用于配置项加密的库,但是两项功能没有本质区别。只需要实现一个自定义的解密器用来获取随机端口,后续的写入配置项操作就由库负责处理。
正如我之前不愿意引入security一样,引入jasypt也不和我心意。
于是我自己琢磨出了一套方案,使用EnvironmentPostProcessor,实现方法如下:
创建一个
EnvironmentPostProcessor实现类,基本代码如下1
2
3
4
5
6
7
8
9
10
11
12
13public class PortEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, S> pringApplication application) {
Properties properties = new Properties();
int availableTcpPort = SocketUtils.findAvailableTcpPort(6001, 12999);
properties.put("management.server.port",availableTcpPort);
properties.put("eureka.instance.metadata-map.management.port",availableTcpPort);
PropertiesPropertySource source = new PropertiesPropertySource("CONSUME", properties);
environment.getPropertySources().addFirst(source);
}
}创建META-INF/spring.factories文件,内容如下
org.springframework.boot.env.EnvironmentPostProcessor=cn.inkroom.study.cloud.gateway.PortEnvironmentPostProcessor
需要特别注明几点:
- 是否覆盖原本配置文件中的某个配置项是有调用addFirst还是addLast方法决定的,越在前面的优先级越高
- 默认情况下,自定义的
PortEnvironmentPostProcessor总是在第一个被调用,因此无法获取其他配置项,意思是不能用于加解密,但是可以用于提供一些来自别的途径,较为动态的配置项
除了更换端口外,还可以更换context-path,但是我就没有再做测试了。