保证配置服务器的安全
在讨论安全性时,我们的架构中还有另外一个关键元素一Spring Cloud Config Server。事实上,保护配置服务器比保护发现服务更重要。为什么?因为我们通常会将它们的身份验证凭据存储到外部系统,甚至还有其他应该隐藏的数据,以防止未经授权的访问和使用。有若干种方法可以正确保护配置服务器。开发人员可以配置HTTP基本身份验证、安全SSL连接、加密/解密敏感数据,或使用之前文章中提到的“使用SpringCloudConfig进行分布式配置”中所述的第三方工具。现在来仔细看看其中的一些。
加密和解密
在开始之前,我们必须下载并安装Oracle提供的Java Cryptography Extension(JCE)。它由两个JAR文件(local policy.jar 和US_ _export_ policyjar) 组成,它们需要覆盖JRE lib/security目录中的现有策略文件。
如果存储在配置服务器上的远程属性源包含加密数据,则它们的值应以(cipher};为前缀并用引号括起来将其指定为YAML文件。.properties 文件不需要包含引号。如果无法解密这样的值,则在前缀为invalid的相同键下将其替换为附加值(通常为
在上一个示例中,我们存储了用于保护应用程序配置设置中的keystore文件的密码。将其保存为纯文本文件可能不是最好的主意,因而它是加密的第一个候选者。问题是,我们应该如何加密它?
幸运的是,SpringBoot提供了两个可以对此提供帮助的RESTful端点。
让我们来看一看它是如何工作的。首先,我们需要启动一个配置服务器实例。要完成该目标,最简单的方法是激活
--spring.profiles.active-native配置文件,该配置文件使用本地类路径或文件系统中的属性源启动服务器。现在我们可以调用两个POST端点/encrypt和/decrypt。 /encrypt 方法将我们的纯文本密码作为参数。可以使用反向操作/decrypt检查出结果,/decrypt操作会将加密的密码作为参数。
$ curl http://localhost:8888/encrypt -d 123456
AQAzI8jv26K3n6ff+iFzQA9DUpWmg7 9emWu4ndEXyvjYnKFSG7 rBmJP0oFTb8RzjZbTwt4
ehRiKWqu5qXkH8SAv/ 8mr2kdwB28kfVvPj/Ib5hdUkH1TVrylcnpZaKaQYBaxlsaORWAKQ
Dk8MQKRw1nJ5HM4LY9yjda0YQFNYAy0/KRnwUFihiV5xDk51MOiG4b77AVLmz+9aSAODKL
057wOQUzM1 tSA7109HyDQW2Hz11q93u0CaP5VQLCJAjmHcHvh1vM442bU3B2 9JNjH+2nFS
ORhEyUvpUqzo+PBi 4ROAKJH9XZ8G7RaTOeWIcJhentKRfOU/EgWIVW21NpsE2 9BHwf4F2J
ZiWY2 +WqcHuHk367X21vk11AV19tJk9aUVNRk=
这里的加密是使用公钥完成的,而解密是使用私钥完成的。因此,如果仅执行加密,则只需要在服务器中提供公钥。出于测试目的,可以使用keytool创建KeyStore。 我们之前已经创建了一些KeyStore, 因而不会遇到任何问题。生成的文件应放在类路径中,然后使用encrypt.keyStore.*属性置于config- service配置设置中。
encrypt:
keyStore :
location: classpath: /config.jks
password: 123456
alias: config
secret: 123456
现在,如果将每个微服务的配置设置移动到配置服务器,则可以加密每个密码,如以下示例片段所示。
server :
port: S{PORT:8091 }
ssl:
enabled: true
key-store: classpath:account.jks
key-store-password:
'{cipher }AQAzI8jv26K3n6ff+iFzQA9DUpWmg7 9emWu4ndEXyvj YnKFSG7 rBmJPOoFTb
8RzjZbTwt4ehRiKWqu5qXKH8SAv/ Bmr2kdwB28kfVvPj/ Lb5hdUkH1TVry1cnpZaKaQYBa
xlsa0RMAKQDk8MQKRw1nJ5HM4LY9yjdaOYQFNYAy0/KRnWUFihiV5xDk51MOiG4b77AVLm
z+9aSA0DKL057wOQUzM1 tSA7109HyDQW2Hz 11q93uOCa P5VQLCJAjmHcHvh1vM4 42bU3B2
9JNjH+ 2nFS0RhEyUvpUqzo+PBi 4ROAKJH9XZ8G7RaTOeWI cJhentKRfOU/EgWIVW2 lNpsE
29BHwf4F2JZiWY2+WqCHuHk367X21vk11AV19tJk9aUVNRK-,
key-alias: account
配置客户端和服务器的身份验证
Spring Cloud Config Server的身份验证实现与Eureka 服务器完全相同。开发人员可以使用基于标准Spring安全机制的HTTP基本身份验证。首先,需要确保spring-security工件位于类路径中:然后,应该将security .basic enabled设置为true以启用安全性,并定义用户名和密码。其示例配置设置如以下代码片段所示。
security:
basic:
enabled: true
user:
name: admin
password: admin123
还必须在客户端启用基本身份验证。它可以通过两种不同的方式实现。第一种方式是通过配置服务器URL。
spring:
cloud:
config:
uri: http://admin:adminl23@localhost:8888
第二种方法基于单独的usemame和password属性。
spring:
cloud:
config:
uri: http://localhost:8888
use rname :
admin
password: admin123
如果要设置SSL身份验证,则需要按照“保证发现服务器的安全”中所描述的步骤进行操作。使用私钥和证书生成KeyStore并设置正确的配置后,开发人员可以运行配置服务器。现在,它将通过HTTPS公开其RESTful API。唯一的区别在于客户端的实现。这是因为Spring Cloud Config 使用的是与Spring Cloud Nettlix Eureka 不同的HTTP客户端。正如你可能猜到的那样,它利用了RestTemplate, 因为它完全是在Spring Cloud项目中创建的。
要强制客户端应用程序使用双向SSL身份验证而不是标准的非安全HTTP连接,首先应该创建一个实现PropertySourceLocator接口的@Configuration bean。在这里,我们可以构建一个使用安全HTTP连接工厂的自定义RestTemplate.
@Configuration
public class ssLConfigSe rviceBootstrapConfiguration {
@Autowired
ConfigClientProperties properties;
@Bean
public ConfigServicePropertySourceLocator
configServicePropertySourceLocator() throws Exception {
final char[] password="123456" . toCharArray();
final File keyStoreFile=new
File ("src/main/ resources/discovery.jks");
SSLContext sslContext=SSLContexts . custom()
. loadKeyMaterial (keyStoreFile, password, password)
.loadTrustMaterial (keyStoreFile) .build() ;
CloseableHttpClient httpClient -
HttpClients . custom() . setssLContext (sslContext) .build() ;
HttpComponentsClienthttpRequestFactory requestFactory new
HttpComponentsClientHttpRequestFactory (httpClient) ;
ConfigServicePropertySourceLocator
configServicePropertySourceLocator=new
ConfigServicePropertySourceLocator (properties) ;
configServicePropertySourceLocator . setRestTemplate (new
RestTemplate (requestFactory) ) ;
return configServicePropertySourceLocator;
}
}
但是,默认情况下,在应用程序尝试与配置服务器建立连接之前,不会创建此Bean。要更改此行为,开发人员还应在
/src/main/resources/META-INF中创建spring. factories文件,并指定自定义引导程序配置类。
org. springf ramework. cloud . bootstrap . BootstrapConfiguration=
pl.piomin. services.account.SSLConfigServiceBootstrapConfiguration
使用OAuth2进行授权
我们已经在微服务环境中讨论了与身份验证相关的一些概念和解决方案。前文已经演示了微服务和服务发现之间,以及微服务和配置服务器之间的基本和SSL身份验证的示例。在服务间通信中,授权似乎比身份验证更重要,而身份验证则在系统的边缘实现。开发人员有必要了解身份验证和授权之间的区别。简而言之,身份验证可以验证访问者的身份,而授权则验证访问者有权执行的操作。
目前,RESTful HTTP API最流行的授权方法是OAuth2和Java Web令牌(Java Web Tokens, JWT)。它们可以混合在一起,因为它们比其他解决方案更加互补。Spring可以为OAuth提供商和使用者提供支持。使用Spring Boot和Spring Security OAuth2,开发人员可以快速实现常见的安全模式,如单点登录、令牌中继或令牌交换。但在深入了解有关这些项目的细节以及其他开发细节之前,开发人员需要掌握上述解决方案的基本知识。
OAuth2 简介
OAuth2是几乎所有主要网站目前使用的标准,允许通过共享API访问其资源。它将用户身份验证委派给存储用户凭据的独立服务,并授权第三方应用程序访问有关用户账户的共享信息。OAuth2用于为用户提供数据访问权限,同时保护其账户凭据。它为Web、桌面和移动应用程序提供流程。以下是与OAuth2相关的一些基本术语和角色。
口资源所有者( Resource Owner) :此角色将控制对资源的访问。此访问权限受到授权范围的限制。
口授予权限(Authorization Grant) :授予访问权限。可以通过多种方式确认访问,如授权代码、隐式、资源所有者密码凭据和客户端凭据等。
口资源服务器 ( Resource Server) :这是一个服务器,用于存储可以使用特殊令牌共享的所有者资源。
口授权服务器(Authorization Server) :它管理密钥、令牌和其他临时资源访问代码的分配。它还必须确保授予相关用户访问权限。
口访问令牌(AccessToken):这是允许访问资源的密钥。
为了更好地理解这些术语和角色在实践中的作用,请查看图12.3。 它可视化了使用OAuth协议的授权过程的典型流程。
现在我们来看一看之前列出的各个组件之间交互的进一步步 骤。应用程序请求资源所有者授权,以便能够访问所请求的服务。资源发送授权作为响应,然后由应用程序将其与其自身的身份一起发送至授权服务器。授权服务器将验证应用程序标识的凭据和授予的权限,然后再发送访问令牌。应用程序使用接收的访问令牌从资源服务器请求资源。最后,如果访问令牌有效,则应用程序能够调用请求服务。
构建授权服务器
从单一应用程序迁移到微服务之后,显而易见的解决方案似乎是通过创建授权服务来集中授权工作。使用Spring Boot和Spring Security, 开发人员可以轻松创建、配置和启动授权服务器。首先,需要在项目依赖项中包含以下启动器。
dependency>
使用Spring Boot实现授权服务器模式非常简单,只需要使用@EnableAuthorizationServer注解主类或配置类,然后在application.yml 文件中提供security .oauth2 cient.client-id和security, oauth2 client.client-secret属性。当然,这种变体应尽可能简单,因为它定义了客户端详细信息服务的内存实现。
本示例应用程序与本章前面的示例位于同一个存储库(
http:gitub.co/pioin/sample- spring-cloud-security.git)中,但在不同的分支中,即oauth2分支(
tps:/github.com/piomin/sample- spring-cloud- scurit/tree/oauth2)。授权服务器在auth- service模块下可用。
以下是auth-service的main类。
@SpringBootApplication
服务器@EnableAuthorizationServer
public class AuthApplication {
public static void main(string[] args) {
new
SpringApplicationBuilder (AuthApplication.class) .web(true) .run(args) ;
}
}
以下是应用程序配置设置的片段。除了客户端的ID和机密之外,我们还设置了默认范围并为整个项目启用了基本安全性。
security:
user :
name: root
password: password
oauth2:
client:
client-id: piotr . minkowski
client-secret: 123456
scope:read
运行授权服务之后,我们就可以执行一些测试。例如,可以调用POST /auth/token方法,以便使用资源所有者密码凭据创建访问令牌,就像在以下命令中一样。
$ curl piotr . minkowski : 123456@localhost: 9999/oauth/token -d
grant_ type=password -d username root -d password-pas sword
开发人员还可以通过从Web浏览器调用GET /oauth/authorize 端点来使用授权代码授予类型。
http://localhost:9999/oauth/ authorize?response type=token&
client_ id=piotr . minkowski&redirect uri=http://example 。com&scope=read
之后,开发人员将被重定向到如图12.4 所示的批准页面。现在可以确认操作并最终获得访问令牌。它将被发送到初始请求的redirect. 配置 _uri 参数中传递的回调URL。以下是笔者在测试后收到的示例回复。
http:/ /example. com/ #access_ token=dd736a4a- 1408-4f3f-b3ca-43dcc05e6df0&
token_ type-bearer&expires_ in=43200.
安全
application.yml文件中提供的相同OAuth2配置也可以按编程的方式实现。为了达到这个目的,开发人员应该声明实现
AuthorizationServerConfigurer的任何@Beans。其中之一是
AuthorizationServerConfigurerAdapter适配器,它提供了空方法,允许创建以下独立配置器的不同定义。
口
ClientDetailServiceConfigurer: 这定义了客户端详细信息服务。可以初始化客户端详细信息,也可以只引用现有存储。
口
AuthorizationServerSecurityConfigurer: 这定义了令牌端点/oauth/token. _key和/oauth/check_ _token 的安全约束。
口
AuthorizationServerEndpointsConfigurer: 这定义了授权和令牌端点以及令牌服务。这种授权服务器实现的方法为开发人员提供了更多机会。例如,可以使用ID和密码定义多个客户端,如以下代码片段所示。下文将介绍一些更高级的示例。
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends Authori zati onSe rverConfigurerAdapter
{
@override
public void conf igure (AuthorizationServersecurityConfigurer
oauthServer) throws Exception {
oauthServer
. tokenKeyAccess ("permitA1l()")
. checkTokenAccess (" isAuthenticated()");
}
@Override
public void configure (ClientDetailsServiceConfigurer clients) throws
Exception {
clients . inMemory()
. withClient ("piotr . minkowski") .secret ("123456")
.scopes ("read")
.authorities ("ROLE CLIENT")
.authorizedGrantTypes ("authorization code" ,
"refresh_ token", "implicit")
. autoApprove (true)
.and( )
.withClient ("john. smith") .secret ("123456")
.scopes ("read", "write")
. authorities ("ROLE CLIENT")
. authorizedGrantTypes ("authorization code",
"refresh_ token", "implicit")
.autoApprove (true);
}
}
必须为授权服务器配置的最后一项是 Web安全性。在扩展
WebSecuriyConfigurerAdapter的类中,我们定义了内存中的用户凭据存储和访问特定资源的权限,如登录页面。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter (
@Autowired
private AuthenticationManager authenticationManager ;
@Override
protected void configure (HttpSecurity http) throws Exception {
http. requestMatchers( )
. antMatchers ("/login", "/oauth/authorize")
.and( )
.authorizeRequests ()
. anyRequest () . authenticated()
.and ()
.formLogin() .permitAll ();
}
@Override
protected void configure (AuthenticationManagerBuilder auth) throws
Exception {
auth. parentAuthenticationManager (authenticat ionManager)
. inMemoryAuthentication()
.withUser ("piotr . minkowski") .password ("123456")
. roles ("USERS") ;
}
}
客户端配置
应用程序可以使用以两种不同方法配置的OAuth2 客户端。第一种方法是通过@EnableOAuth2Client注解,它将创建一个ID为oauth2ClientContextFilter的过滤器bean,负责存储请求和上下文。它还管理应用程序和授权服务器之间的通信。但是,我们将要讨论的却是第二种方法,即通过@EnableOAuth2Sso实现0Auth2客户端。单点登录(Single Sign-On,SsO) 是一种众所周知的安全模式,它允许用户使用一组登录凭据来访问多个应用程序。此注解提供了两个功能一OAuth2 客户端和身份验证。身份验证功能模块使开发人员的应用程序可以符合典型的Spring Security机制(如表单登录)。客户端模块则具有与@EnableOAuth2Client提供的功能相同的特性。所以,开发人员可以将@ EnableOAuth2Sso视为比@EnableOAuth2Client更高级别的注解。
在下面的示例代码片段中,我们已经注解了使用@EnableOAuth2Sso扩展
WebSecurityConfigurerAdapter的类。由于此扩展,Spring Boot 配置了带有OAuth2身份验证处理程序的安全过滤器链(Security Filter Chain)。在这种情况下,仅允许对/login页面的请求,而所有其他请求都需要身份验证。可以使用security .oauth2 sso login-path属性覆盖表单登录页面路径。在覆盖它之后,开发人员还应该记得在WebSecurityConfig中更改路径模式。
@Configuration
@EnableOAuth2Sso
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure (HttpSecurity http) throws Exception {
http.antMatcher("/**)
. authorizeRequests ()
. antMatchers("/login**")
.permitAll ()
. anyRequest ()
. authenticated() ;
还有一些需要设置的配置设置。首先,应该禁用基本身份验证,因为我们已经启用了表单登录方法和@EnableOAuth2Sso注解。然后,必须提供一些基本的OAuth2客户端属性,如客户端凭据和授权服务器公开的HTTPAPI端点的地址。
security:
basie:
enabled: false
oauth2:
client:
clientId: piotr .minkowski
clientSecret: 123456
accessTokenUri: http://localhost :9999/oauth/token
userAuthorizationUri: http://loca1host:9999/oauth/authorize
resource:
userInfoUri: http://localhost: 9999/user
application.yml文件片段中的最后一个属性是security .oauth2. resource.userInfoUri,它需要服务器端的其他端点。通过UserController 实现的端点将返回java.security Principal对象,指示当前经过身份验证的用户。
@RestController
public class UserController {
eRequestMapping (" /user")
public Principal user (Principal user) {
return user;
}
}
现在,如果调用由我们的某个微服务公开的任何端点,都将自动重定向到登录页面。由于我们为内存客户端的详细信息存储设置了autoApprove选项,因而将自动生成授予的权限和访问令牌,而无须用户进行任何交互。在登录页面提供凭据后,开发人员应该从请求的资源处获得响应。
本文给大家讲解的内容是保证配置服务器的安全下篇文章给大家讲解的是使用JDBC后端存储;觉得文章不错的朋友可以转发此文关注小编,有需要的可以私信小编获取资料;感谢大家的支持!
版权声明:本文来自互联网整理发布,如有侵权,联系删除
原文链接:https://www.yigezhs.comhttps://www.yigezhs.com/qingganjiaoliu/15173.html