服务网格如何帮助微服务提升安全?

翻译:狄卫华

作者:Christian Posta

原文地址:http://blog.christianposta.com/how-a-service-mesh-can-help-with-microservices-security/

我看到很多客户转向微服务(他们是否应该是另外一个帖子的主题),他们试图通过这种方式解决一些组织化的规模问题。但是,转向微服务架构的细节往往会为新的问题带来一些旧问题。我与之交谈的大多数客户采用一种策略:架构上既有内部部署也有公共云部署。将应用程序分解为更小的服务并拥有多个部署站点/平台会带来一些更大的挑战。在我看来,像 Istio 这样的服务网格实现旨在解决这些挑战中的一些。对于Istio 和 Service Mesh ,我确实有很多话要说,所以请随时关注 @christianposta 参与并跟踪最新状态。

在微服务化的过程中您将面临的一个挑战是:安全。

我知道我知道。作为开发人员,您可能已经对安全非常憎恨 — 微服务使其更加糟糕。当我们将应用程序分解为更小的服务时,我们会增加被攻击的范围。虽然这有很多安全方面的问题(应用程序漏洞,平台漏洞,数据保护,传输/网络等),但在本帖中我将主要集中在微服务如何相互通信以及其出现的一些问题上。

传统上,我们认为网络边界足以保护我们;我们的应用程序在传输安全方面的问题不必考虑太多,因为我们处于 ”受保护的内部网络“。停下来思考一下,您是否使用 SSL/TLS 保护您的内部应用程序?我们以前通过单体程序本地调用的所有通信都将暴露在开放的网络中。首先我们要做的就是加密所有的内部流量。如果您在实施微服务上没有使用 TLS 进行传输加密,您正在将面临着令人讨厌的安全问题。

部分成熟的客户已经实现了所有微服务通信加密,这并没有带来显著成本提升。搭建公钥基础设施、签发密钥和证书、安装、轮换等都是非常大的考验。尝试配置正确的信任库/密钥库(Java)、合适的SSL算法、确保拥有正确的证书链等都是让人感到头痛的事情。我个人浪费了很多天试图让其能够正常工作 。然后当其都能正常工作以后,您不会再想去折腾它。

我也看到了开发人员使用了 SSL/TLS,然后将其代码部署到 IST/UAT等测试环境中,但是最终发现相关的安全配置在底层环境中不能够正常工作;由于着急将产品部署到生产环境中,他们会执行诸如禁用 TLS 验证的操作。哎哟。

像 Istio 这样的服务网格相当简化了这一点。借助 Istio,应用程序的所有实例都有自己的 Sidecar 容器。该Sidecar 充当所有流入和流出网络通信的服务代理。

img

在使用服务代理可以获得的诸多好处,与此文讨论相关的好处是能够透明地进行 TLS 加密。这意味着位于与应用程序请求路径中的代理承担了加密流量的责任。您的应用程序可以完全不用关心证书,信任库,密钥库等问题。 Istio 自动将证书和密钥关联到服务,代理使用它们来加密流量(提供双向TLS),并且 Istio 定期轮换密钥/证书,以减少泄露的风险。

img

举例来说,当 Istio 运行在 Kubernetes 上时,无论您何时部署应用程序,您只需要指定一个应用程序运行的服务帐户 — 之后,istio负责处理其余部分。 Istio 将为您的服务帐户创建证书/密钥对,使用根CA密钥对证书签名,并在将证书/密钥作为 Kubernets 中的密码。密码将被挂载到您的应用程序和 Istio 服务代理运行的 Pod 中,代理将使用证书/密钥来建立双向 TLS。

img

微服务的另一个安全问题是责任混淆问题。在这种情况下,终端用户已经授权服务代表它做某件事。在这种情况下,服务可能被授权执行此操作,但特定用户可能不会。我们应该以某种方式将用户身份绑定,并基于身份来评估授权。方法之一就是使用像 JWT 的令牌。

相关的有以下几点:

首先,如果您传递明文的 JWT令牌(不使用TLS/mTLS),那么您会遇到比较大的麻烦。令牌默认不进行加密(仅签名),他们很容易地被收集并重放(replay)到服务中。再次,这是 Istio mTLS 可以提供帮助的地方。但即使启用了 mTLS,令牌也可能以被其他的方式泄露(我看到令牌被硬编码到源代码中!!)。如果您的所有服务都将JWT 传递给其他所有服务,那么您将再次面临重放攻击问题。

其次,如果您试图在所有微服务器上进行 JWT 验证,则会遇到与弹性库相同的问题。每个服务都有自己的库和自己的 JWT 验证实现。尽管像 JBoss Keycloak 这样的项目提供了出色的多语言支持,但它对库维护人员以及依赖这些库的应用程序开发人员来说都是一种负担。确保它们全部实施正确,一致并统一是一个充满了问题的壮举。

值得庆幸的是,Istio 可以在这两个方面提供帮助。

首先,无论应用程序框架/语言如何,Istio 都可以为您自动进行 JWT 验证。您可以定义一个EndUserAuthenticationPolicySpec,它配置了将用于验证的身份/凭证提供者

--- 
apiVersion: config.istio.io/v1alpha2
kind: EndUserAuthenticationPolicySpec
metadata: 
  name: cars-api-auth-policy
  namespace: tutorial
spec: 
  jwts: 
    - issuer: http://keycloak:8080/auth/realms/istio
      jwks_uri: http://keycloak.tutorial:8080/auth/realms/istio/protocol/openid-connect/certs
      audiences: 
      - cars-web  

然后您可以将它绑定到具体的服务:

--- 
apiVersion: config.istio.io/v1alpha2
kind: EndUserAuthenticationPolicySpecBinding
metadata:
  name: cars-api-auth-policy-binding
  namespace: tutorial
spec:
  policies:
    - name: cars-api-auth-policy
      namespace: tutorial
  services:
    - name: cars-api
      namespace: tutorial

注意:这个例子来自我的同事 Kamesh Sampath。在这个配置中,我们已经建立了 Keycloak 成为 JWT 令牌的身份管理者和发行者(遵循OpenID Connect)。有关更多信息,请参阅此博客。当请求进入服务时,如果它没有JWT 持票人令牌,它将被拒绝。这个配置将安装 Envoy jwt过滤器,该过滤器负责验证 JWT 的签名:

img

最后,JWT 令牌是如何地传播?

Istio 默认只会将 JWT 令牌传播一次,使用 JWT 令牌的主体,并将其传递到应用程序通过单独的 header 字段。 JWT 主体将通过 header 头部中的 sec-istio-auth-userinfo 携带信息。基于终端用户的身份和服务的身份,应用程序有责任重新提交新的令牌。通过这种方式,我们可以将令牌的范围限定为单次使用,而不是将 JWT 到处传播。对此的实施仍在发展中,我强烈建议遵循这里这里

现在就是这样。 随着 Istio 内部安全性的加强,我会进一步跟进。 关注我 @christianposta 获取微服务,服务网格,Istio等等的最新信息。

发表评论

电子邮件地址不会被公开。 必填项已用*标注