为分布式系统设计一个安全的架构

保护分布式系统是一项复杂的挑战,因为涉及的组件多样且规模庞大。在多个服务跨越可能不安全的网络进行交互时,未经授权的访问和数据泄露的风险显著增加。本文探讨了一种使用开源项目保护分布式系统的实用方法。该项目展示了如何集成多种安全机制和技术,以应对常见的安全挑战,如身份验证、授权和安全通信。

理解分布式系统中的安全挑战

分布式系统涉及多个服务或微服务,必须在网络上安全地进行通信。此类架构中的主要安全挑战包括:

  1. 安全通信:确保服务之间传输的数据加密并且防止窃听或篡改
  2. 身份验证:验证用户和服务的身份以防止未经授权的访问
  3. 授权:根据角色和权限控制已验证的用户和服务允许执行的操作
  4. 策略实施:实施细粒度的访问控制和政策,以管理服务间和用户间的交互
  5. 证书管理: 管理用于加密数据和建立服务间信任的数字证书

这个开源项目 通过采用多种集成技术和解决方案来解决这些挑战。

项目设置和配置

项目的开始阶段是通过使用shell脚本和Docker来建立一个安全环境。设置过程中包括提供数字证书并启动必要的服务,以确保所有组件都准备好进行安全通信。

设置环境的步骤

1. 配置证书

该项目使用一个shell脚本(provisioning.sh)来模拟证书权威(CA)并生成服务所需的所有必要证书。

   ./provisioning.sh

2. 启动服务

使用Docker Compose启动项目中定义的所有服务,确保它们被正确配置以实现安全运行。

   docker-compose up

3. 测试服务间通信

为了验证服务间的通信是否使用证书和JWT令牌进行验证,提供了test_services.sh脚本。此脚本展示了不同服务如何使用分配给它们的证书安全地相互交互。

分布式系统中的安全挑战

该项目整合了多种关键技术来解决前面提到的主要安全挑战。以下是每个挑战是如何应对的:

1. 使用相互TLS (mTLS) 进行安全的通信

挑战

在分布式系统中,服务必须安全地通信,以防止未经授权的访问和数据泄露。

解决方案

该项目使用相互TLS (mTLS)来保护服务之间的通信。mTLS确保客户端和服务器使用各自的证书相互验证。这种相互验证阻止了未经授权的服务与合法服务进行通信。

实现

Nginx被配置为反向代理来处理mTLS。它需要客户端和服务器证书来建立一个安全的连接,确保服务之间传输的数据保持机密性和防篡改。

2. 使用Keycloak进行身份验证

挑战

正确验证用户和服务对于防止未授权访问至关重要。

解决方案

该项目利用了Keycloak,一个开源的身份和访问管理解决方案,来管理身份验证。Keycloak支持多种身份验证方法,包括OpenID Connect和客户端凭据,使其适用于用户和服务身份验证。

  • 用户身份验证:
    用户使用OpenID Connect进行身份验证。Keycloak与一个客户端(appTest-login-client)进行了配置,处理用户身份验证流程,包括登录、令牌发放和回调处理。
  • 服务身份验证:
    对于服务间的身份验证,该项目使用了一个配置为客户端凭据授权类型的Keycloak客户端(client_credentials-test)。这种方法非常适合无需用户干预即可验证服务。

身份验证流程示例

  1. 用户导航到登录页面。
  2. 登录成功后,Keycloak将用户重定向到一个回调页面,并携带一个授权码。
  3. 然后,用这个授权码换取一个JWT令牌,后续的请求将使用这个JWT令牌。nginx/njs 目录中的authn.js文件详细实现了此流程。

使用客户端凭据的服务认证示例

curl -X POST "http://localhost:9000/realms/tenantA/protocol/openid-connect/token" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "grant_type=client_credentials" \
     -d "client_id=client_credentials-test" \
     -d "client_secret=your-client-secret-here"

3. 使用Open Policy Agent (OPA)和JWT的用户授权

挑战

执行细粒度的访问控制,确保已认证的用户和服务只能访问授权的资源

解决方案

该项目使用Open Policy Agent (OPA)JWT令牌的组合来执行授权策略。该项目展示了三种不同的JWT验证策略,以确保稳健的安全性:

  1. 从Keycloak检索证书: 从Keycloak动态获取证书以验证令牌。
  2. 使用x5t (指纹): 使用令牌中嵌入的指纹从本地信任存储中检索公钥。
  3. 嵌入式证书验证:使用嵌入式证书验证令牌,确保证书与可信的证书授权中心(CA)进行验证。

有关这些策略的详细实现,请参阅nginx/njs/token.js文件。

4. 使用开放策略代理(OPA)实施策略

挑战

为服务和用户实现动态和灵活的访问控制策略

解决方案

OPA用于实施访问控制的细粒度策略。策略使用声明性语言(Rego)编写,并存储在opa/目录中。这些策略规定了服务可以进行通信的条件以及用户可以访问资源的条件,确保在整个系统中一致地应用访问控制。

5. 证书管理

挑战

为服务管理数字证书以建立信任和保障通信安全

解决方案:
项目包括一个强大的证书管理系统。使用一个 shell 脚本(provisioning.sh)模拟证书颁发机构(CA)并为每个服务生成证书。这种方法简化了证书管理,确保所有服务拥有安全通信所需的凭证。

我们还添加了一个端点,可以在不重新启动 nginx 的情况下更新服务证书。

curl --insecure  https://localhost/certs  --cert certificates/gen/serviceA/client.crt --key certificates/gen/serviceA/client.key -F cert=@certificates/gen/serviceA/client.crt -F key=@certificates/gen/serviceA/client.key

结论

构建安全的分布式系统需要仔细考虑各种安全方面,包括安全通信、身份验证、授权、策略执行和证书管理。这个开源项目提供了一个综合示例,展示如何有效地集成多种安全机制来应对这些挑战。

通过遵循本项目中的设置和配置,开发人员可以利用双向 TLS、Keycloak、Open Policy Agent 和 Nginx 构建一个强大的安全架构。这些技术结合在一起,为保护分布式系统免受多种威胁提供了坚实的基础,确保数据保护和安全访问控制。

Source:
https://dzone.com/articles/designing-a-secure-architecture-for-distributed-systems