如何深度解析Istio中的安全模块

72次阅读
没有评论

共计 7982 个字符,预计需要花费 20 分钟才能阅读完成。

今天就跟大家聊聊有关如何深度解析 Istio 中的安全模块,可能很多人都不太了解,为了让大家更加了解,丸趣 TV 小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

单体应用拆分为微服务之后,提高了开发效率,增加系统系统稳定性,提高运维效率等等一系列的好处,但随之也带来了安全方面的风险,之前都是本地调用,现在都改为走网络协议调用接口,今天着重介绍的是微服务架构中的新贵 Istio 中安全模块分析,Istio 安全的三大目标:

默认安全(Security by default):应用程序代码和基础结构无需更改。

深度防御(Defense in depth):与现有安全系统集成,提供多层防御。

零信任网络(Zero-trust network):在不受信的网络上,构建安全解决方案。

架构

如何深度解析 Istio 中的安全模块

如上图,Istio 安全涉及到组件有:

Citadel 用于密钥和证书的管理。

Proxy 实现客户端与服务器端安全通信。

Pilot 将授权策略和安全命名信息分发给代理。

Mixer:校验授权和审计。

Istio 身份

身份信息

身份信息是安全基础架构的基本概念,在服务和服务的通信开始前,双方必须用其身份信息交换凭证,以达到相互认证的目的,根据安全信息达到鉴权的目的,同时根据身份信息可以进行审计,在 kubernetes 的环境下 Istio 身份标识使用 Service Account。

PKI

PKI(Public Key Infrastructure)建立在 Istio citadel 之上,Istio 使用 X.509 证书来携带 SPIFFE 格式的身份信息,PKI 还可以大规模自动化地进行密钥和证书轮换。

证书生成流程

基于 kubernetes 环境下证书生成流程如下:

如何深度解析 Istio 中的安全模块

citadel 同时也会监听每个证书的生命周期,通过重写 Kubernetes secret 自动轮换证书。Pilot 生成安全信息即授权信息,Pilot 将授权信息分发给 envoy 每个命名空间下有个 default serviceaccount,citadel 会为它创建一个名为 istio.default 的 secret。

[root@kube01 ~]$ kubectl -n foo get secrets 
NAME TYPE DATA AGE 
default-token-bdpmg kubernetes.io/service-account-token 3 8d 
istio.default istio.io/key-and-cert 3 8d

默认在该命名空间下新建的 istio 应用都使用该 secret。

istio-certs:
 Type: Secret (a volume populated by a Secret)
 SecretName: istio.default
 Optional: true

当为 deployment 指定了非默认 serviceaccount,则秘钥也将使用新的 secret。

istio-certs:
 Type: Secret (a volume populated by a Secret)
 SecretName: istio.bookinfo-productpage
 Optional: true

认证

Istio 提供两种类型的身份验证:

传输身份验证,也称为服务到服务身份验证:验证直接客户端进行连接。Istio 提供相互 TLS 作为传输身份验证的完整堆栈解决方案。

源身份验证,也称为最终用户身份验证:验证将请求作为最终用户或设备的原始客户端。

具体信息参见官网,本文章主要介绍第一种。

相互 TLS 身份验证(mTLS)

mTLS 本身流程如下图所示:

如何深度解析 Istio 中的安全模块

在 Istio 握手期间,客户端 envoy 还进行安全命名检查,验证服务器证书中提供的服务账户是否有权限运行目标服务。

认证架构

通过 yaml 文件配置身份认证策略,部署后策略保存在 Istio 配置存储中,Pilot 监听配置存储,当发生变化后 Pilot 将策略转变为适当的配置(envoy 识别的配置等),再通知 envoy 如何执行身份认证机制,Pilot 提供 Istio 系统管理的密钥和证书的路径,并将它们安装到应用程序 mesh 以进行相互 TLS。Istio 通过异步发送配置到目标端点,代理收到消息后,新的身份认证立即生效。

认证架构如下图所示:

如何深度解析 Istio 中的安全模块

部署影响

在部署 Istio 平台时,通过 yaml 则是 istio-demo-auth.yaml,该 yaml 安装为所有控制面板中 envoy 添加了 tls 相关信息,在 helm 中则是 global.controlPlaneSecuretyEnable: true,开启后实质是为 controlPlaneAuthPolicy: MUTUAL_TLS,分析添加该属性后发生的变化如下:

控制面板

Istio-policy,istio-telemetry,istio-pilot,三个组件在 istio-proxy 中 envoy 进程启动时会指定配置文件,依次为 envoy_policy.yaml,envoy_telemetry.yaml,envoy_pilot.yaml,在这些文件中相同都增加如下:

tls_context : {
  common_tls_context : {
  alpn_protocols :  h3 , 
 tls_certificates : {
  certificate_chain : {
  filename :  /etc/certs/cert-chain.pem 
 },
  private_key : {
  filename :  /etc/certs/key.pem 
 }
 }, 
 validation_context : { 
 trusted_ca : { 
 filename :  /etc/certs/root-cert.pem 
 },  verify_subject_alt_name : [
  spiffe://cluster.local/ns/istio-system/sa/istio-pilot-service-account 
 ] 
} 
}

在模板文件地址 实质判断 controlPlaneAuthPolicy 的值,如果这个值设置 None,则当开启网格策略 mtls 后,控制面板各个组件不支持 tls,导致转发失败,必须设置到控制面板目标规则 mode 为 DISABLE 才可以,否则会导致握手失败,报错 503,如下所示:

[2018-10-23 02:55:45.510][19][debug][connection] external/envoy/source/common/network/connection_impl.cc:466] [C127] connected 
[2018-10-23 02:55:45.510][19][debug][connection] external/envoy/source/common/ssl/ssl_socket.cc:113] [C127] handshake error: 2 
[2018-10-23 02:55:45.510][19][debug][connection] external/envoy/source/common/ssl/ssl_socket.cc:113] [C127] handshake error: 5 
[2018-10-23 02:55:45.510][19][debug][connection] external/envoy/source/common/network/connection_impl.cc:133] [C127] closing socket: 0

数据面板

数据面板中该值 controlPlaneAuthPolicy:None 不影响 mtls 功能使用(如果有误请联系更改)。

认证策略

Istio 可以在命名空间范围或网格范围中存储身份认证策略,使用官网实例 sleep 访问 httpbin 进行测试,访问过程如下图所示:

如何深度解析 Istio 中的安全模块

部署官网示例,步骤 1:

$ kubectl create ns foo 
$ kubectl apply -f  (istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n foo 
$ kubectl apply -f  (istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo 
$ kubectl create ns bar 
$ kubectl apply -f  (istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n bar 
$ kubectl apply -f  (istioctl kube-inject -f samples/sleep/sleep.yaml) -n bar 
$ kubectl create ns legacy 
$ kubectl apply -f samples/httpbin/httpbin.yaml -n legacy 
$ kubectl apply -f samples/sleep/sleep.yaml -n legacy

此时执行,步骤 2:

for from in foo bar do for to in foo bar do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} — curl http://httpbin.${to}:8000/ip -s -o /dev/null -w sleep.${from} to httpbin.${to}: %{http_code}\n done; done

返回结果皆为 200,目前是未开启 mtls。

网格范围策略

使用 MeshPolicy,没有目标选择器部分。可以有最多一个网格范围的策略在网格中,启用 mtls 配置如下:

cat  EOF | kubectl apply -f - 
apiVersion:  authentication.istio.io/v1alpha1  
kind:  MeshPolicy  
metadata:
 name:  default  
spec:
 peers:
 - mtls: {} 
EOF

此时再次执行步骤 2 则结果都为 503,需要增加目标规则配置,如下所示:

cat  EOF | kubectl apply -f - 
apiVersion:  networking.istio.io/v1alpha3  
kind:  DestinationRule  
metadata:
 name:  default 
 namespace:  default  
spec:
 host:  *.local  trafficPolicy:
 tls:
 mode: ISTIO_MUTUAL 
EOF

此时再次执行步骤 2 则结果为 200 正常。

分析开启 mtls 后 envoy 发生的变化,在 listeners 的 filter 链中增加了 tlsContext 相关配置。

// 使用 istioctl proxy-config 分析 envoy istioctl proxy-config listeners -n foo httpbin-66dc4dd499-8fjgb --port 8000 -o json 
// 输出如下: 
... 
 filterChains : [
 {
  tlsContext : {
  commonTlsContext : {
  tlsCertificates : [
 {
  certificateChain : {
  filename :  /etc/certs/cert-chain.pem 
 },
  privateKey : {
  filename :  /etc/certs/key.pem 
 }
 }
 ],
  validationContext : {
  trustedCa : {
  filename :  /etc/certs/root-cert.pem 
 }
 },
  alpnProtocols : [
  h3 ,
  http/1.1 
 ]
 },
  requireClientCertificate : true
 } 
...

注意:当 controlPanleAuth 配置为 None 时,只是配置这两个配置访问依然为 503,原因是控制面板不支持 tls 配置,如部署影响中有讲到,如果为 None 时也想让该示例生效,需要增加目标规则,目标规则中指定到控制面板的数据流不开启 mtls,使用明文访问,如下所示:

cat  EOF | kubectl apply -f - 
apiVersion:  networking.istio.io/v1alpha3  
kind:  DestinationRule  
metadata:
 name:  istio-system-manage-dr 
 namespace:  istio-system  
spec:
 host:  *.istio-system.svc.cluster.local 
 trafficPolicy:
 tls:
 mode: DISABLE 
EOF

当拥有 sidecar 的应用开启 mtls 后想要访问非 Istio 服务,也是需要配置 tls:DISABLE,如下所示:

cat  EOF | kubectl apply -f - 
apiVersion: networking.istio.io/v1alpha3 
kind: DestinationRule 
metadata:
 name:  httpbin-legacy  
spec:
 host:  httpbin.legacy.svc.cluster.local 
 trafficPolicy:
 tls:
 mode: DISABLE 
EOF

命名空间范围策略

具有名称 default 且没有目标选择器部分。每个命名空间最多只能有一个名称空间范围的策略。它使用 kind“Policy”,需要指定命名空间名称,如下所示:

cat  EOF | kubectl apply -f - 
apiVersion:  authentication.istio.io/v1alpha1  
kind:  Policy  
metadata:
 name:  default 
 namespace:  foo  
spec:
 peers:
 - mtls: {} 
EOF

与网格范围策略一样,也需要指定目标规则,如下所示:

cat  EOF | kubectl apply -f - 
apiVersion:  networking.istio.io/v1alpha3  
kind:  DestinationRule  metadata:
 name:  default 
 namespace:  foo  
spec:
 host:  *.foo.svc.cluster.local 
 trafficPolicy:
 tls:
 mode: ISTIO_MUTUAL 
EOF

开启命名空间范围策略只是针对当前命名空间,对于控制面板下的服务没有任何影响,还是使用明文访问。

授权

Istio 授权功能,基于角色的访问控制(RBAC),为 Istio 中服务提供命名空间级别、服务级别、方法级别的访问控制,特点是:

基于角色的语义,简单易用。

服务到服务和最终用户到服务授权。

通过自定义属性支持(例如条件,角色和角色绑定)提供灵活性。

高性能,因为 Istio 授权在 Envoy 上本地执行。

授权架构

如何深度解析 Istio 中的安全模块

用户使用.yaml 配置 Istio 授权策略,部署完成后同样存储在 Istio 配置存储,Pilot 监听 Istio 授权变化,如果发生变化 Pilot 获取更新的授权策略,将 Istio 授权策略分发给与服务实例位于同一位置的 Envoy 代理,每个 Envoy 代理都运行一个授权引擎,该引擎在运行时授权请求。当请求到达代理时,授权引擎根据当前授权策略评估请求上下文,并返回授权结果,ALLOW 或 DENY。

启用授权

使用 RbacConfig 对象启用 Istio 授权,是一个单例,固定名称为 default,在 RbacConfig 中可以指定一个 mode 值,该值可以是:

OFF:禁用 Istio 授权。

ON:为网格中的所有服务启用了 Istio 授权。

ON_WITH_INCLUSION:仅对 inclusion 字段中指定的服务和命名空间启用 Istio 授权。

ON_WITH_EXCLUSION:对网格中的所有服务启用 Istio 授权,但 exclusion 字段中指定的服务和命名空间除外。

开启授权,如下所示:

apiVersion:  rbac.istio.io/v1alpha1 
kind: RbacConfig 
metadata:
 name: default 
spec:
 mode:  ON_WITH_INCLUSION 
 inclusion:
 namespaces: [default]

当开启 rbacconfig 后,正常的 bookinfo 示例已经不可以访问,提示“RBAC: access denied“。

授权策略

使用 bookinfo 测试授权策略,配置策略,使用 ServiceRole 和 ServiceRolebinding:

ServiceRole:定义一组访问服务的权限。

ServiceRoleBinding:将权限授权给特定主体,例如用户,组,服务。

ServiceRole

每条规则都以以下标准字段:

services:服务名称列表。您可以将值设置 * 为包括指定命名空间中的所有服务。

methods:HTTP 方法名称列表,对于 gRPC 请求的权限,HTTP 谓词始终是 POST。您可以将值设置 * 为包括所有 HTTP 方法。

paths:HTTP 路径或 gRPC 方法。gRPC 方法必须采用以下形式 /packageName.serviceName/methodName 并且区分大小写。

具体参考官网。

创建一个 ServiceRole,如下所示:

apiVersion:  rbac.istio.io/v1alpha1  
kind: ServiceRole 
metadata:
 name: service-viewer
 namespace: default 
spec: rules:
 - services: [*]
 methods: [GET]
 constraints:
 - key:  destination.labels[app] 
 values: [productpage ,  details ,  reviews ,  ratings]

允许只读访问 default 命名空间下所有带有指定标签的服务。

ServiceRoleBinding

ServiceRoleBinding 规范包括两个部分:

roleRef 指的是 ServiceRole 同一名称空间中的资源。

subjects 分配给该角色的列表。

如下所示:

apiVersion:  rbac.istio.io/v1alpha1  
kind: ServiceRoleBinding 
metadata:
 name: bind-service-viewer
 namespace: default 
spec:
 subjects:
 - properties:
 source.namespace:  istio-system 
 - properties:
 source.namespace:  default 
 roleRef:
 kind: ServiceRole
 name:  service-viewer

将 ServiceRole 授权给命名空间为“istio-system”和“default”。

看完上述内容,你们对如何深度解析 Istio 中的安全模块有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注丸趣 TV 行业资讯频道,感谢大家的支持。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-25发表,共计7982字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)