安全

1. 保护SBA服务端的安全

由于在分布式web应用中,有好几种可以解决身份认证和授权的方法,所以Spring Boot Admin没有默认为您选择它们中的哪一个。 默认情况下可以使用 spring-boot-admin-server-ui 来提供一个登录页面和注销按钮。

下面是一个针对Spring的安全配置示例:

@Configuration(proxyBeanMethods = false)
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {

	private final AdminServerProperties adminServer;

	private final SecurityProperties security;

	public SecuritySecureConfig(AdminServerProperties adminServer, SecurityProperties security) {
		this.adminServer = adminServer;
		this.security = security;
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
		successHandler.setTargetUrlParameter("redirectTo");
		successHandler.setDefaultTargetUrl(this.adminServer.path("/"));

		http.authorizeRequests(
				(authorizeRequests) -> authorizeRequests.antMatchers(this.adminServer.path("/assets/**")).permitAll() (1)
						.antMatchers(this.adminServer.path("/actuator/info")).permitAll()
						.antMatchers(this.adminServer.path("/actuator/health")).permitAll()
						.antMatchers(this.adminServer.path("/login")).permitAll().anyRequest().authenticated() (2)
		).formLogin(
				(formLogin) -> formLogin.loginPage(this.adminServer.path("/login")).successHandler(successHandler).and() (3)
		).logout((logout) -> logout.logoutUrl(this.adminServer.path("/logout"))).httpBasic(Customizer.withDefaults()) (4)
				.csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) (5)
						.ignoringRequestMatchers(
								new AntPathRequestMatcher(this.adminServer.path("/instances"),
										HttpMethod.POST.toString()), (6)
								new AntPathRequestMatcher(this.adminServer.path("/instances/*"),
										HttpMethod.DELETE.toString()), (6)
								new AntPathRequestMatcher(this.adminServer.path("/actuator/**")) (7)
						))
				.rememberMe((rememberMe) -> rememberMe.key(UUID.randomUUID().toString()).tokenValiditySeconds(1209600));
	}

	// Required to provide UserDetailsService for "remember functionality"
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser(security.getUser().getName())
				.password("{noop}" + security.getUser().getPassword()).roles("USER");
	}

}
1 对所有静态资源和登录页面进行放行处理。
2 其它所有请求都必须经过身份认证。
3 配置登录和注销逻辑。
4 开启HTTP-Basic认证。这是Spring Boot Admin客户端所需的。
5 启用Cookie的CSRF保护
6 禁用Spring Boot Admin客户端对于注册(注销)请求的CSRF保护
7 禁用Spring Boot Admin客户端对于actuator接口的CSRF保护

如果使用Spring Boot Admin客户端,它还需要添加访问服务端的凭证:

application.yml
spring.boot.admin.client:
   username: sba-client
   password: s3cret

有关完整的示例,请查看 spring-boot-admin-sample-servlet

如果你想要保护 /instances 接口,那么不要忘了在SBA客户端使用 spring.boot.admin.client.usernamespring.boot.admin.client.password 配置用户名和密码。

2. 保护客户端默认Actuator接口

当actuator默认接口使用HTTP Basic身份认证进行安全保护时候,SBA就需要凭证才能访问它们了。 你可以在注册应用的时候在元数据中提交这个凭证。 之后 BasicAuthHttpHeaderProvider 就会使用元数据中提供的信息,在header中添加 Authorization 然后访问客户端应用的actuator接口了。 你也可以自定义一个 HttpHeadersProvider 来改变这个默认的行为(例如添加一些加密揭秘的逻辑)或者是在header中添加额外信息。

SBA服务端会屏蔽元数据中的一些信息,以防止敏感信息的泄漏。
在元数据提交身份凭证时,应该为SBA服务端(或者是服务发现)配置HTTPS。
使用Spring Cloud服务发现的时候,你必须随时注意,任何可以查询服务注册的人都可以看到你的认证信息。
使用这种方法SBA服务端就可以决定用户能否访问已注册的应用。 还有更加复杂的解决方案(使用OAuth2)来让客户端决定用户能否访问接口。 关于这一点,请参考 joshiste/spring-boot-admin-samples

2.1. SBA客户端

application.yml
spring.boot.admin.client:
    url: http://localhost:8080
    instance:
      metadata:
        user.name: ${spring.security.user.name}
        user.password: ${spring.security.user.password}

2.2. SBA服务端

你可以通过admin服务端的配置文件来指定凭证。

你可以将它与 spring-cloud-kubernetes 结合起来一起使用,这样就能从 secrets 中读取凭证了。

要想从配置文件读取凭证,需要将 spring.boot.admin.instance-auth.enabled 设置为 true (默认情况就是这样)。

如果客户端通过元数据提供了凭证(例如通过服务注解),那么元数据将会替换配置文件中的配置。

你可以通过使用 spring.boot.admin.instance-auth.default-user-namespring.boot.admin.instance-auth.default-user-password 来提供默认的用户名和密码。 你也可以选择使用 spring.boot.admin.instance-auth.service-map.*.user-name 为指定名称的服务提供凭证,记得将 * 替换为服务名。

application.yml
spring.boot.admin:
  instance-auth:
    enabled: true
    default-user-name: "${some.user.name.from.secret}"
    default-password: "${some.user.password.from.secret}"
    service-map:
      my-first-service-to-monitor:
        user-name: "${some.user.name.from.secret}"
        user-password: "${some.user.password.from.secret}"
      my-second-service-to-monitor:
        user-name: "${some.user.name.from.secret}"
        user-password: "${some.user.password.from.secret}"

2.3. Eureka

application.yml
eureka:
  instance:
    metadata-map:
      user.name: ${spring.security.user.name}
      user.password: ${spring.security.user.password}

2.4. Consul

application.yml
spring.cloud.consul:
  discovery:
    metadata:
        user-name: ${spring.security.user.name}
        user-password: ${spring.security.user.password}
Consul在元数据不允许使用点 (".") 作为key,应该使用减号(横杠)代理。

2.5. 默认Actuator接口的CSRF保护

一些actuator接口 (例如 /loggers) 是支持POST请求的。 在使用Spring Security时需要禁用这些actuator接口的CSRF保护,因为Spring Boot Admin服务端目前缺乏对这方面的支持。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf()
        .ignoringAntMatchers("/actuator/**");
}

3. 使用自定义TLS

SBA还可以在访问actuator接口的时候使用客户端证书进行身份认证。 在提供了 ClientHttpConnector bean时,Spring Boot就会用它自动配置 WebClient.Builder,之后供Spring Boot Admin使用。

@Bean
public ClientHttpConnector customHttpClient() {
    SslContextBuilder sslContext = SslContextBuilder.forClient();
    //Your sslContext customizations go here
    HttpClient httpClient = HttpClient.create().secure(
        ssl -> ssl.sslContext(sslContext)
    );
    return new ReactorClientHttpConnector(httpClient);
}