Istio安全
将单一应用程序分解为微服务可提供各种好处,包括更好的灵活性、可伸缩性以及服务复用的能力。但是,微服务也有特殊的安全需求:1)为了抵御中间人攻击,需要流量加密。2)为了提供灵活的服务访问控制,需要双向 TLS 和细粒度的访问策略。3)要审核谁在什么时候做了什么,需要审计工具。istio安全整体概述
Istio 中的安全性涉及多个组件:1)Citadel 用于**和证书管理。2)Sidecar 和周边代理 实现客户端和服务器之间的安全通信。3)Pilot 将授权策咯和安全信息发给代理。4)Mixer 管理授权和审计
上图Istio 安全架构。在服务间通信开始时,双方必须与其身份信息交换凭证以用于相互认证目的。在客户端,根据安全信息检查服务器的标识,以查看它是否是该服务的授权运行程序。在服务器端,服务器可以根据授权策略确定客户端可以访问哪些信息,审核谁在什么时间访问了什么,根据服务向客户收费并拒绝任何未能支付账单的客户访问服务。Istio 身份模型中,Istio 可以使用可以对服务实例进行分组的其他身份,例如服务名称。不同平台上的 Istio 服务标识:1)Kubernetes: Kubernetes 服务帐户。2)GKE/GCE: 可以使用 GCP 服务帐户。3)GCP: GCP 服务帐户。4)AWS: AWS IAM 用户/角色帐户。5)本地(非 Kubernetes): 用户帐户、自定义服务帐户、服务名称、Istio 服务帐户或 GCP 服务帐户。自定义服务帐户引用现有服务帐户,就像客户的身份目录管理的身份一样。
SPIFFE:一种标准,提供了一个框架规范,该框架能够跨异构环境引导和向服务发布身份。Istio 安全性和 SPIRE(是 SPIFFE 的实现)在 PKI 实现细节上有所不同。Istio 提供更全面的安全解决方案,包括身份验证、授权和审计。PKI:Istio PKI 建立在 Istio Citadel 之上,可为每个工作负载安全地提供强大的工作负载标识。Istio 使用 X.509 证书来携带 SPIFFE 格式的身份。PKI 还可用于大规模自动化**和证书轮换。Istio 支持在 Kubernetes pod 和本地计算机上运行的服务。目前每个方案使用不同的证书**配置机制。Kubernetes 方案: 1) Citadel 监视 Kubernetes apiserver,为每个现有和新的服务帐户创建 SPIFFE 证书和**对。Citadel 将证书和**对存储为Kubernetes secret。2) 创建 pod 时,Kubernetes 会根据其服务帐户通过Kubernetes secret volume 将证书和**对挂载到 pod 上。3) Citadel 监视每个证书的生命周期,并通过重写 Kubernetes secret 自动轮换证书。4) Pilot 生成安全命名信息,该信息定义了哪些 Service Account 可以运行哪些服务。Pilot 然后将安全命名信息传递给 envoy sidecar。
认证: Istio 提供两种类型的身份验证:传输身份验证,也称为服务间身份验证:验证建立连接的直接客户端。 Istio 提供双向TLS作为传输身份验证的完整堆栈解决方案。 无需更改服务代码即可打开此功能。这个解决方案:1)为每个服务提供强大的身份,表示其角色,以实现跨群集和云的互操作性。2)保护服务到服务通信和最终用户到服务的通信。3)提供**管理系统,以自动执行**和证书生成,分发和轮换。来源身份认证,也称为最终用户身份验证:验证作为最终用户或设备发出请求的原始客户端。Istio 通过 JSON Web Token(JWT)验证和 ORY Hydra、Keycloak、Auth0、Firebase Auth、Google Auth 和自定义身份验证来简化开发人员体验,并且轻松实现请求级别的身份验证。在这两种情况下Istio都通过自定义 K8s API 将身份认证策略存储在 Istio 配置存储中。Pilot 会在适当的时候为每个代理保持最新状态以及**。此外Istio 支持在宽容模式(permissive mode)下进行身份验证,帮助了解策略更改在其生效之前如何影响安全状态。双向 TLS 认证:Istio 隧道通过客户端和服务器端进行服务间(service-to-service)通信Envoy代理。为了使客户端通过双向 TLS 调用服务端,遵循以下步骤:1、Istio 将出站流量从客户端重新路由到客户端的本地 sidecar Envoy。2、客户端 Envoy 与服务器端 Envoy 开始双向 TLS 握手。在握手期间,客户端 Envoy 还做了安全命名检查,以验证服务器证书中显示的服务帐户是否被授权运行到目标服务。3、客户端 Envoy 和服务器端 Envoy 建立了一个双向的 TLS 连接,Istio 将流量从客户端 Envoy 转发到服务器端 Envoy。4、授权后,服务器端 Envoy 通过本地 TCP 连接将流量转发到服务器服务。宽容模式:Istio 双向 TLS 具有一个宽容模式(permissive mode),允许 service 同时接受纯文本流量和双向 TLS 流量。这个功能极大的提升了双向 TLS 的入门体验。安全命名:安全命名信息包含从编码在证书中的服务器标识到被发现服务或 DNS 引用的服务名称的 N-到-N 映射。从身份 A 到服务名称 B 的映射意味着“允许 A 并授权其运行服务 B。Pilot 监视 Kubernetes apiserver,生成安全的命名信息,并将其安全地分发给 sidecar Envoy。
认证架构:网格操作者使用 .yaml 文件来指定策略。部署后策略将保存在 Istio 配置存储中。Pilot、Istio 控制器监视配置存储。一有任何的策略变更,Pilot 会将新策略转换为适当的配置,告知 Envoy sidecar 代理如何执行所需的身份验证机制。Pilot 可以获取公钥并将其附加到 JWT 验证配置。或者Pilot 提供 Istio 系统管理的**和证书的路径,并将它们挂载到应用程序 pod 以进行双向 TLS。Istio 异步发送配置到目标端点。代理收到配置后新的身份验证要求会立即生效。发送请求的客户端服务负责遵循必要的身份验证机制。对于源身份验证(JWT),应用程序负责获取 JWT 凭据并将其附加到请求。对于双向 TLS,Istio 提供目标规则。可以使用目标规则来指示客户端代理使用 TLS 与服务器端预期的证书进行初始连接。
Istio 将两种类型的身份验证以及凭证中的其他声明(如果适用)输出到下一层:授权。此外可以指定将传输或原始身份验证中的哪个身份作为委托人使用。认证策略:认证策略是对服务收到的请求生效的,要在双向 TLS 中指定客户端认证策略,需要在 DetinationRule 中设置 TLSSettings。和其他的 Istio 配置一样,可以用 .yaml 文件的形式来编写认证策略,然后使用部署。策略存储范围:Istio 可以在命名空间范围或网络范围存储中存储身份认证策略,命名空间范围存储中的策略只能影响同一命名空间中的服务。网格范围内的策略可以影响网格中的所有服务。为防止冲突和滥用,只能在网格范围存储中定义一个策略。该策略必须命名为 default 并且有一个空的 targets: 部分。传输认证:peers: 部分定义了策略中传输身份验证支持的身份验证方法和相关参数。该部分可以列出多个方法,并且只有一个方法必须满足认证才能通过。但是从 Istio 0.7 版本开始,当前支持的唯一传输身份验证方法是双向 TLS。默认的双向 TLS 模式为 STRICT。因此,mode: STRICT 等效于以下内容:- mtls:{}、如果不指定双向 TLS 模式,则对等方无法使用 Transport 身份验证,并且 Istio 拒绝绑定到 Sidecar 的双向 TLS 连接。在应用程序层,服务仍可以处理它们自己的双向 TLS 会话。来源身份认证:部署文件- mtls: 、- mtls: null三种效果一样。origins: 部分定义了原始身份验证支持的身份验证方法和相关参数。Istio 仅支持 JWT 原始身份验证。但是策略可以列出不同发行者的多个 JWT。与传输身份验证类似,要想通过身份验证必须通过其中的一个。
授权:Istio 的授权功能为 Istio 网格中的工作负载提供网格级别、命名空间级别和工作负载级别的访问控制。它提供了:1)工作负载间和最终用户到工作负载的授权。2)一个简单的 API,它包括一个单独的并且很容易使用和维护的AuthorizationPlicy CRD。3)灵活的语义,运维人员可以在 Istio 属性上自定义条件。4)高性能,因为 Istio 授权是在 Envoy 本地强制执行的。5)高兼容性,原生支持 HTTP、HTTPS 和 HTTP2,以及任意普通 TCP 协议。istio授权架构如下
每个 Envoy 代理都运行一个授权引擎,该引擎在运行时授权请求。当请求到达代理时,授权引擎根据当前授权策略评估请求上下文,并返回授权结果 ALLOW 或 DENY。无需显式启用 Istio 的授权功能,只需在工作负载上应用 AuthorizationPolicy 即可实现访问控制。如果没有对工作负载应用 AuthorizationPolicy,则不会执行访问控制,也就是说,将允许所有请求。如果有任何 AuthorizationPolicy 应用到工作负载,则默认情况下将拒绝对该工作负载的访问,除非策略中声明的规则明确允许了。目前,AuthorizationPolicy 仅支持 ALLOW 动作。 这意味着,如果将多个授权策略应用于同一工作负载,它们的效果是累加的。授权策略:要配置 Istio 授权策略,请创建一个 AuthorizationPolicy(AP) 资源。授权策略包括选择器和规则列表。 选择器指定策略所适用的目标,而规则指定什么条件下允许谁做什么。 具体来说:目标AP里的 selector 部分,谁 from 部分来源列表。什么 rule 中的 to 部分,操作列表。条件 rule 中的 when 部分。自定义条件列表。策略目标:策略范围(目标)由 metadata/namespace 和可选的 selector 确定。metadata/namespace 告诉该策略适用于哪个命名空间。如果设置为根命名空间,则该策略将应用于网格中的所有命名空间。根命名空间的值是可配置的,默认值为 istio-system。 如果设置为普通命名空间,则该策略将仅适用于指定的命名空间。工作负载 selector 可用于进一步限制策略的应用范围。 selector 使用 pod 标签来选择目标工作负载。 工作负载选择器包含 {key: value} 对的列表,其中 key 是标签的名称。 如果未设置,则授权策略将应用于与授权策略相同的命名空间中的所有工作负载。值匹配:大部分字段都支持完全匹配、前缀匹配、后缀匹配和存在匹配,但有一些例外情况(例如,when 部分下的key 字段,source 部分下的 ipBlocks 和 to 部分下的 ports 字段仅支持完全匹配)。
在普通 TCP 协议上使用 Istio 授权:Istio 授权支持工作负载使用任意普通 TCP 协议,如 MongoDB。 在这种情况下,可以按照与 HTTP 工作负载相同的方式配置授权策略。 不同之处在于某些字段和条件仅适用于 HTTP 工作负载。 这些字段包括:1)授权策略对象 source 部分中的 request_principals 字段。2)授权策略对象 operation 部分中的 hosts、methods 和 paths 字段,如下列出了支持的条件。
| 名称 | 描述 | 支持的协议 | 示例 |
|---|---|---|---|
request.headers |
HTTP 请求头,需要用 [] 括起来 |
HTTP only |
key: request.headers[User-Agent]values: ["Mozilla/*"]
|
source.ip |
源 IP 地址,支持单个 IP 或 CIDR
|
HTTP and TCP |
key: source.ipvalues: ["10.1.2.3"]
|
source.namespace |
源负载实例命名空间,需启用双向 TLS | HTTP and TCP |
key: source.namespacevalues: ["default"]
|
source.principal |
源负载的标识,需启用双向 TLS | HTTP and TCP |
key: source.principalvalues: ["cluster.local/ns/default/sa/productpage"]
|
request.auth.principal |
已认证过 principal 的请求。 |
HTTP only |
key: request.auth.principalvalues: ["accounts.my-svc.com/104958560606"]
|
request.auth.audiences |
此身份验证信息的目标主体 | HTTP only |
key: request.auth.audiencesvalues: ["my-svc.com"]
|
request.auth.presenter |
证书的颁发者 | HTTP only |
key: request.auth.presentervalues: ["123456789012.my-svc.com"]
|
request.auth.claims |
Claims 来源于 JWT。需要用 [] 括起来 |
HTTP only |
key: request.auth.claims[iss]values: ["*@foo.com"]
|
destination.ip |
目标 IP 地址,支持单个 IP 或 CIDR
|
HTTP and TCP |
key: destination.ipvalues: ["10.1.2.3", "10.2.0.0/16"]
|
destination.port |
目标 IP 地址上的端口,必须在 [0,65535] 范围内 |
HTTP and TCP |
key: destination.portvalues: ["80", "443"]
|
connection.sni |
服务器名称指示,需启用双向 TLS | HTTP and TCP |
key: connection.snivalues: ["www.example.com"]
|
experimental.envoy.filters.* |
用于过滤器的实验性元数据匹配,包装的值 [] 作为列表匹配 |
HTTP and TCP |
key: experimental.envoy.filters.network.mysql_proxy[db.table]values: ["[update]"]
|
对双向 TLS 的依赖:Istio 使用双向 TLS 将某些信息从客户端安全地传递到服务器。在使用授权策略中的以下任何字段之前,必须先启用双向 TLS:1) source 部分下的 principals 字段,2)source部分下的 namespaces 字段。3)source.principal 自定义条件。4)source.namespace自定义条件。5)connection.sni自定义条件。如果不使用授权策略中的上述任何字段,则双向 TLS 不是必须的。