30、微服务安全与可观测性全解析

微服务安全与可观测性实践

微服务安全与可观测性全解析

1. 使用JWT访问受保护资源

当从OAuth 2.0授权服务器获取到JWT访问令牌后,可使用以下cURL命令访问受保护资源。请确保将 $TOKEN 替换为有效的访问令牌:

curl -k -H "Authorization: Bearer $TOKEN" https://localhost:9443/order/11

响应示例:

{"customer_id":"101021","order_id":"11","payment_method":{"card_type":"VISA", 
"expiration":"01/22","name":"John Doe","billing_address":"201, 1st Street, 
San Jose, CA"},"items":[{"code":"101","qty":1},{"code":"103","qty":5}], 
"shipping_address":"201, 1st Street, San Jose, CA"}
2. 控制微服务的访问

控制微服务的访问有多种方式,下面将介绍基于范围和用户角色的访问控制。

2.1 基于范围的访问控制
  • 获取带范围的JWT令牌 :使用以下命令获取具有 foo 范围的JWT访问令牌,需正确替换 $CLIENTID $CLIENTSECRET 的值,并确保授权服务器 sample01 正在运行。
curl -v -X POST --basic -u $CLIENTID:$CLIENTSECRET -H "Content-Type: 
application/x-www-form-urlencoded;charset=UTF-8" -k -d "grant_type=client_
credentials&scope=foo" https://localhost:8443/oauth/token
  • 启用范围访问控制 :在订单处理微服务 sample02 中,需在 sample02/src/main/java/com/apress/ch12/sample02/OrderProcessingApp.java 类中添加 @EnableGlobalMethodSecurity 注解。
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableResourceServer
public class OrderProcessingApp {
}
  • 方法级范围控制 :在 sample02/src/main/java/com/apress/ch12/sample02/service/OrderProcessing.java 类的方法上使用 @PreAuthorize 注解,要求访问该方法需要 bar 范围。
@PreAuthorize("#oauth2.hasScope('bar')")
@RequestMapping(value = "/{id}", method= RequestMethod.GET)
public ResponseEntity<?> getOrder(@PathVariable("id") String orderId) {
}
  • 测试范围控制 :使用仅具有 foo 范围的JWT访问令牌执行以下命令,会因令牌不包含所需范围而报错。
curl -k -H "Authorization: Bearer $TOKEN" https://localhost:9443/order/11

响应:

{"error":"access_denied","error_description":"Access is denied"}
2.2 基于角色的访问控制
  • 获取带角色的JWT令牌 :使用密码授权类型获取JWT访问令牌,需正确替换 $CLIENTID $CLIENTSECRET $USERNAME $PASSWORD 的值。
curl -v -X POST --basic -u $CLIENTID:$CLIENTSECRET -H "Content-Type: 
application/x-www-form-urlencoded;charset=UTF-8" -k -d "grant_type=password
&username=$USERNAME&password=$PASSWORD&scope=foo" https://localhost:8443/
oauth/token
  • 启用角色访问控制 :同样在 OrderProcessingApp.java 类中添加 @EnableGlobalMethodSecurity 注解。
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableResourceServer
public class OrderProcessingApp {
}
  • 方法级角色控制 :在 OrderProcessing.java 类的方法上使用 @PreAuthorize 注解,要求访问该方法需要 USER 角色。
@PreAuthorize("hasRole(USER)")
@RequestMapping(value = "/{id}", method= RequestMethod.GET)
public ResponseEntity<?> getOrder(@PathVariable("id") String orderId) {
}
  • 测试角色控制 :使用具有 foo 范围且颁发给具有 USER 角色用户的JWT访问令牌执行以下命令,应能成功响应。
curl -k -H "Authorization: Bearer $TOKEN" https://localhost:9443/order/11
2.3 范围和角色组合控制

若要同时基于范围和角色控制对方法的访问,可在相应方法上使用以下注解:

@PreAuthorize("#oauth2.hasScope('bar') and hasRole('USER')")
3. 保障服务间通信安全

保障服务间通信安全有两种方法,分别基于JWT和TLS相互认证。

3.1 基于JWT的服务间通信

在该场景中,订单处理微服务接收到订单后会与库存微服务通信以更新库存,会将获取的访问令牌传递给库存微服务。
- 库存微服务配置 :库存微服务代码位于 ch12/sample03 目录,要启用JWT认证,需在 sample03/src/main/resources/application.properties 文件中取消以下属性的注释。

security.oauth2.resource.jwt.keyUri: https://localhost:8443/oauth/token_key
  • 启动库存微服务 :在 sample03 目录下使用以下Maven命令启动服务,服务将在HTTPS端口 10443 启动。
mvn spring-boot:run
  • 端到端流程测试 :先获取具有 foo bar 范围的JWT访问令牌:
curl -v -X POST --basic -u $CLIENTID:$CLIENTSECRET -H "Content-Type: 
application/x-www-form-urlencoded;charset=UTF-8" -k -d "grant_type=password
&username=$USERNAME&password=$PASSWORD&scope=foo bar"  
https://localhost:8443/oauth/token

然后使用该令牌向订单处理微服务下单:

curl -v  -k -H "Authorization: Bearer $TOKEN" -H "Content-Type: 
application/json" -d '{"customer_id":"101021","payment_method":{"card_type": 
"VISA","expiration":"01/22","name":"John Doe","billing_address":"201, 1st 
Street, San Jose, CA"},"items":[{"code":"101","qty":1},{"code":"103", 
"qty":5}],"shipping_address":"201, 1st Street, San Jose, CA"}' https://
localhost:9443/order

若一切正常,cURL客户端应显示 201 HTTP状态码,库存微服务终端将打印订单号。

3.2 基于TLS相互认证的服务间通信

TLS相互认证常用于服务器到服务器的认证,JWT用于在微服务之间传递用户上下文。
- 密钥库和信任库要求 :每个服务都需有自己的密钥库 keystore.jks 和信任库 trust-store.jks 。例如,订单处理微服务与库存微服务通信时,库存微服务的信任库 sample03/trust-store.jks 中需包含订单处理微服务公钥的证书颁发机构的公共证书;订单处理微服务的信任库 sample02/trust-store.jks 中需包含库存微服务公钥的证书颁发机构的公共证书。
- 订单处理微服务配置 :在 sample02/src/main/java/com/apress/ch12/sample02/OrderProcessingApp.java 文件中设置以下属性:

System.setProperty("javax.net.ssl.trustStore", path + File.separator + 
"trust-store.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "springboot");
System.setProperty("javax.net.ssl.keyStore",  path + File.separator + 
"keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "springboot");
  • 库存微服务配置 :在 sample03/src/main/java/com/apress/ch12/sample03/InventoryApp.java 文件中设置信任库属性:
System.setProperty("javax.net.ssl.trustStore", path + File.separator + 
"trust-store.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "springboot");

sample03/src/main/resources/application.properties 文件中设置以下属性以启用TLS相互认证:

server.ssl.client-auth:need
  • 端到端流程测试 :使用有效访问令牌调用订单处理微服务进行测试:
curl -v  -k -H "Authorization: Bearer $TOKEN" -H "Content-Type: 
application/json" -d '{"customer_id":"101021","payment_method":{"card_type": 
"VISA","expiration":"01/22","name":"John Doe","billing_address":"201,  
1st Street, San Jose, CA"},"items":[{"code":"101","qty":1},{"code":"103", 
"qty":5}],"shipping_address":"201, 1st Street, San Jose, CA"}'  
https://localhost:9443/order
4. 保障执行器端点安全

Spring Boot通过执行器提供了开箱即用的监控功能。

  • 启用执行器端点 :在任何Spring Boot微服务中,添加以下依赖以激活执行器端点。
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • 启动微服务 :在 ch12/sample04 目录下使用以下命令启动订单处理微服务,服务将在HTTPS端口 8443 启动。
mvn spring-boot:run
  • 未安全配置时的测试 :执行以下cURL命令可成功获取响应。
curl -k https://localhost:8443/health

响应:

{"status":"UP"}
  • 启用安全配置 :在 sample04/pom.xml 文件中添加以下依赖。
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • 添加用户和角色 :在 sample04/src/main/java/com/apress/ch12/sample04/config/SecurityConfig.java 文件中取消 @Configuration 类级注解的注释,并添加以下代码,为系统引入一个名为 admin 且具有 ACTUATOR 角色的用户。
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
  auth.inMemoryAuthentication().withUser("admin")
                               .password("admin").roles("ACTUATOR");
}
  • 重启服务并测试 :重启服务后,使用 admin/admin 凭证执行以下cURL命令。
curl –k --basic -u admin:admin  https://localhost:8443/health

响应:

{"status":"UP"}
5. 可观测性概述

收集数据成本低,但在需要时缺乏数据可能代价高昂。可观测性是衡量从系统外部输出推断其内部状态的程度,是微服务设计中重要的一环,需要跟踪每个微服务的吞吐量、请求成功/失败数量、CPU和内存等资源利用率以及一些业务相关指标。

6. 可观测性的三大支柱

可观测性可通过日志记录、指标和跟踪这三种方式实现,它们也被称为可观测性的三大支柱。
| 支柱 | 描述 | 示例 |
| — | — | — |
| 日志记录 | 记录事件,可包含事务的时间戳、状态、发起者等元数据 | 记录每个通过微服务的事务 |
| 指标 | 由事件测量数据组合得出,反映服务运行状况,可用于设置警报 | 单位时间内处理的事务数量、事务成功率/失败率、平均延迟 |
| 跟踪 | 从日志中派生,考虑事件顺序和相互影响,有助于找出问题根源 | 跟踪计费微服务请求失败的原因到订单处理微服务 |

7. 使用Spring Cloud Sleuth进行分布式跟踪

分布式跟踪有助于跟踪跨越多个微服务的请求,在处理客户端的单个请求时,通常会涉及多个微服务。它不仅对微服务有价值,对任何分布式系统都很有用,能帮助识别和隔离与延迟、消息丢失、吞吐量等相关的问题。

graph LR
    A[客户端请求] --> B[订单处理微服务]
    B --> C[库存微服务]
    B --> D[其他微服务]
    C --> E[更新库存]
    D --> F[执行其他操作]

通过以上介绍,我们了解了微服务安全和可观测性的相关知识,包括访问控制、服务间通信安全保障以及可观测性的实现方法,这些技术对于构建健壮、安全和可监控的微服务系统至关重要。

微服务安全与可观测性全解析

8. 构建分布式跟踪系统

为了更好地实现分布式跟踪,我们可以使用 Spring Cloud Sleuth、Zipkin 和 Jaeger 来构建一个完整的分布式跟踪系统。以下是构建该系统的详细步骤:

8.1 引入依赖

在项目的 pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
8.2 配置 Zipkin 服务器

Zipkin 是一个开源的分布式跟踪系统,用于收集和展示跟踪数据。可以通过 Docker 快速启动一个 Zipkin 服务器:

docker run -d -p 9411:9411 openzipkin/zipkin
8.3 配置应用程序

在应用程序的配置文件(如 application.properties )中添加以下配置,将跟踪数据发送到 Zipkin 服务器:

spring.zipkin.base-url: http://localhost:9411
spring.sleuth.sampler.probability: 1.0
8.4 启动应用程序

启动微服务应用程序,Spring Cloud Sleuth 会自动为每个请求生成唯一的跟踪 ID 和跨度 ID,并将这些信息传递给下游服务。

8.5 查看跟踪数据

打开浏览器,访问 http://localhost:9411 ,可以看到 Zipkin 的界面。在界面中可以搜索和查看各个请求的跟踪信息,包括请求的路径、时间、延迟等。

9. 可视化、监控和警报

使用 Prometheus 和 Grafana 可以实现对微服务的可视化、监控和警报功能。以下是具体的操作步骤:

9.1 安装和配置 Prometheus

Prometheus 是一个开源的监控系统,用于收集和存储指标数据。可以通过 Docker 快速启动一个 Prometheus 服务器:

docker run -d -p 9090:9090 prom/prometheus

prometheus.yml 配置文件中添加要监控的目标:

scrape_configs:
  - job_name: 'my_microservice'
    static_configs:
      - targets: ['localhost:8080']
9.2 安装和配置 Grafana

Grafana 是一个开源的可视化工具,用于展示 Prometheus 收集的指标数据。可以通过 Docker 快速启动一个 Grafana 服务器:

docker run -d -p 3000:3000 grafana/grafana

打开浏览器,访问 http://localhost:3000 ,使用默认的用户名和密码( admin/admin )登录 Grafana。在 Grafana 中添加 Prometheus 作为数据源,并创建仪表盘来展示指标数据。

9.3 设置警报

在 Grafana 中可以设置警报规则,当指标数据超过预设的阈值时,会触发警报。可以通过配置通知渠道(如邮件、Slack 等)来接收警报信息。

10. 总结

微服务的安全和可观测性是构建健壮、可靠的微服务系统的关键。通过本文的介绍,我们了解了以下重要内容:

  • 访问控制 :可以基于范围和角色对微服务的访问进行控制,确保只有授权的用户和服务可以访问受保护的资源。
  • 服务间通信安全 :可以使用 JWT 和 TLS 相互认证来保障服务间通信的安全,防止数据泄露和中间人攻击。
  • 可观测性 :通过日志记录、指标和跟踪这三大支柱,可以实现对微服务的全面监控和分析,及时发现和解决问题。
  • 分布式跟踪系统 :使用 Spring Cloud Sleuth、Zipkin 和 Jaeger 可以构建一个完整的分布式跟踪系统,帮助我们跟踪和分析跨越多个微服务的请求。
  • 可视化、监控和警报 :使用 Prometheus 和 Grafana 可以实现对微服务的可视化、监控和警报功能,及时发现系统的异常情况。

在实际应用中,我们可以根据具体的需求和场景选择合适的技术和工具,确保微服务系统的安全和可观测性。

graph LR
    A[客户端] --> B[微服务系统]
    B --> C[访问控制]
    B --> D[服务间通信安全]
    B --> E[可观测性]
    C --> F[范围控制]
    C --> G[角色控制]
    D --> H[JWT通信]
    D --> I[TLS认证]
    E --> J[日志记录]
    E --> K[指标分析]
    E --> L[跟踪系统]
    L --> M[Spring Cloud Sleuth]
    L --> N[Zipkin]
    L --> O[Jaeger]
    E --> P[可视化监控]
    P --> Q[Prometheus]
    P --> R[Grafana]

通过以上的流程图,我们可以更清晰地看到微服务系统中各个组件之间的关系和作用。在实际开发和运维过程中,我们可以根据这个架构来构建和管理微服务系统,确保系统的安全和稳定运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值