istio 作为服务网格的开放平台,安全性是其不容忽视的一点,本文将概览一下 istio 的安全策略和配置。
微服务的安全需求
微服务是由以前的较大的单体应用拆分而来,相应的组件间原本的内部调用也会转换为不同服务间的调用,其主要的安全性需求如下:
- 需要流量加密,防止中间人攻击
- 为了提供灵活的服务访问控制,他们需要双向TLS和细粒度的访问策略。
- 需要审计工具,知道谁在何时做了什么事情
Istio 通过身份认证,授权、多种安全策略和审核(AAA)工具,来保证微服务的安全。其目标是
- 代码无侵入性
- 基于0信任网络
- 与现有的安全系统集成以提供多层防御
istio 证书管理
istio 使用 x509 证书为不同组件认证和授权。证书的颁发、签字、认证、流转等动作完全依靠工作负载的sidecar来完成。下图是istio 官方给出的身份提供流程:
istiod 提供 grpc 服务来接受证书签名请求(CSR),且 istiod 中的 Certificate Authority 可以为证书签名。签发证书流程如下:
- envoy 通过 sds api 发送证书和密钥请求
- istio agent 收到请求后,会生成一个密钥和证书签名请求,然后将带有凭据的CSR 发送给 istiod 进行签名。
- istiod 收到 CSR 后,对凭据进行认证,若检测通过则对CSR进行签名,生成一个签名证书
- istio agent 收到签名证书后,将密钥和签名证书一起发给 envoy
对于证书和密钥轮换,上述CSR过程会定期重复。
认证
istio 提供了两种认证方式:
- 对等认证: 即服务到服务的认证。istio 为每个服务提供标识用于认证身份,提供密钥管理系统以自动执行密钥和证书的生成,分发和轮换
- 请求认证:用于对客户端的认证。Istio通过JSON Web令牌(JWT)验证启用请求级身份验证,且允许使用自定义身份验证程序或任何OpenID Connect程序简化的开发。
在所有情况下,Istio都会通过自定义的Kubernetes API将身份验证策略存储在Istio配置存储中。Istiod 组件会保存每个envoy代理的最新状态,并在适当的地方向envoy代理提供密钥。此外,Istio在 permissive模式下支持身份验证,以实现从非tls流量向 tls流量转换。
mtls 认证
双向tls认证用于工作负载与工作负载间的通信。当工作负载使用双向TLS身份验证将请求发送到另一个工作负载时,该请求的处理方式如下:
Istio将来自客户端的出站流量重新路由到客户端的本地Sidecar Envoy。
客户端Envoy与服务器端Envoy开始相互TLS握手。在握手期间,客户端Envoy还会进行安全命名检查,以验证服务器证书中提供的服务帐户是否有权运行目标服务。
客户端Envoy和服务器端Envoy建立了双向TLS连接,Istio将流量从客户端Envoy转发到服务器端Envoy。授权后,服务器端Envoy通过本地TCP连接将流量转发到服务器服务。
安全命名检查:
由于服务名称可以通过服务发现或DNS获得,但服务是由谁来启动运行的客户端无法得知。因此存在一个安全隐患:
假设团队A运行了一个合法服务A,团队A有合法的身份证书和密钥,然而恶意用户拥有测试团队身份的证书和密钥,则恶意用户可以使用证书和测试团队身份的密钥来部署伪造的恶意服务A。此时恶意用户可以通过DNS欺骗,BGP /路由劫持,ARP欺骗等手段将原本访问合法服务A的流量重定向到恶意服务A。
Istiod 中会维护一个服务身份与服务名称的映射,并将其下发到envoy代理中,从而防止HTTPS流量受到一般性的网络劫持。此外也可以在一定程度上防止TCP流量网络劫持,但是由于TCP流量不包含主机名信息,因此安全命名无法防止DNS欺骗。
istio 认证机制
Istio 在控制平面保存、更改和下发安全配置,在 K8s 集群中通过 PeerAuthentication 和 RequestAuthentication 资源来进行管理。
使用对等身份验证策略和双向TLS时,Istio将身份从对等身份验证提取到source.principal中。使用请求身份验证策略时,Istio会将JWT中的身份分配给request.auth.principal。使用这些主体设置授权策略并作为遥测输出。
对于双向tls,envoy 代理会自动将流量升级为 tls流量。双向tls策略可以作用于工作负载的某个端口、工作负载、namespace和整个istio网格中,Istio 也提供了三种tls模式:
- Strict:工作负载只接收 tls 流量
- Permissive:可以接收非tls流量,该模式主要用于工作负载的tls迁移过程:没有Sidecar的工作负载无法使用双向TLS,当工作负载使用Sidecar注入后,应将模式切换为STRICT。
- Disable:禁止使用tls
对于请求认证,istio需要校验请求中的 JWT 信息,因此在策略中需要提供以下配置:
令牌在请求中的位置
发行人或请求
公用JSON Web密钥集(JWKS)
授权/访问控制
Istio 提供 网格级别、namespace级别以及工作负载级别的访问控制。其授权及访问控制主要基于 K8s 的rbac功能实现。
每个Envoy代理都运行一个授权引擎,该引擎在运行时对请求进行授权。当请求到达代理时,授权引擎会根据当前的授权策略评估请求上下文,并返回授权结果ALLOW或DENY。
在istio中添加授权策略则会默认开启授权机制。
istio 授权配置
Istio 通过 AuthorizationPolicy 的CRD 定义授权规则,其主要包括四部分:
Target:规则的作用目标,可以是workload、namespace或集群
Source:请求源,可以是某个namespace、某个serviceAccont、IP段
To:请求目标动作,例如域名、端口、请求方法(GET、POST)和URL
Action:指定允许还是拒绝请求
在上述的配置中,部分策略需要开启双向tls认证策略,例如source指定serviceAccont 等。
多集群下 istio 安全策略
Istio 中多集群有两种部署架构:
-
多集群共享istio控制平面:
此种架构下,两个K8s集群共享一个 istio 控制平面,相应的 CA 证书也是共享的。这种情况下,多集群构建成为一个服务网格,因此从上向下看,跨集群的mtls通信如同在同一个集群中通信。
-
不同集群使用不同istio控制平面:
此架构下跨集群的服务通信需要mtls
多istio控制平面需要提前准备一个公用的 RootCA,每个istio控制平面的证书均需要由RootCA 生成。跨集群的 mtls 通信都是用同一个 RootCA 签发。
不同集群间的通信需要依赖istio-gateway组件完成。Cluster2 中的服务通过 ServiceEntry (类似于DNS)映射在Cluster1中。
总结
本篇文章主要介绍了 istio 安全的理论知识,总的来说istio 的安全主要分为认证和授权访问,都是通过 istio 的 CRD 实现对策略的监听,并通过 istiod 下发到 envoy 代理,具体安全操作都是由 envoy 来处理。认证分为对等认证和请求认证,用于加密 workload 间的流量和认证workload以及client,主要实现方式是通过 mTLS 以及 JWT 实现。授权访问则是对主要通过 K8s 的 RBAC 规则实现,可以限制对目标负载或namespace的访问流量。