1. Istio安全简介

1.1 Istio安全设计目标

单体应用拆分为微服务之后,提高了开发效率,增加系统系统稳定性,提高运维效率等等一系列的好处,但随之也带来了安全方面的风险,之前都是本地调用,现在都改为走网络协议调用接口。

Istio 安全的目标是:

  • 默认安全:应用程序代码和基础设施无需更改
  • 深度防御:与现有安全系统集成以提供多层防御
  • 零信任网络:在不受信任的网络上构建安全解决方案

说到底,Istio安全主要有两项功能:即无代码侵入前提下,实现流量加密和AAA(验证、授权、审计)。

  • 流量加密,用来解决零信任网络的问题。
  • Istio的AAA是在集成现有安全协议/标准之上实现的,这些安全协议/标准包括双向TLS,JWT,OpenID Connect等。

1.2 Istio安全体系架构

安全架构图模板 安全架构功能视图_服务器


这张图显示了Istio安全体系架构,图中非常明确的表示 Istio 所希望的是在网格中能够使用 mTLS 进行授权,而在网格外使用 JWT+mTLS 进行授权。服务间身份认证是使用 mTLS,来源身份验证中则是使用 JWT。

2. Istio身份

身份是任何安全基础架构的基本概念。在工作负载间通信开始时,双方必须交换包含身份信息的凭证以进行双向验证。

  • 在客户端,根据安全命名信息检查服务器的标识,以查看它是否是该服务的授权运行程序。
  • 在服务器端,服务器可以根据授权策略确定客户端可以访问哪些信息,审计谁在什么时间访问了什么,根据他们使用的工作负载向客户收费,并拒绝任何未能支付账单的客户访问工作负载。

Istio 身份模型使用 service identity (服务身份)来确定一个请求源端的身份。这种模型有极好的灵活性和粒度,可以用服务身份来标识人类用户、单个工作负载或一组工作负载。在没有服务身份的平台上,Istio 可以使用其它可以对服务实例进行分组的身份,例如服务名称。

下面的列表展示了在不同平台上可以使用的服务身份:

  • Kubernetes: Kubernetes service account
  • AWS: AWS IAM user/role account
  • 本地(非 Kubernetes):用户帐户、自定义服务帐户、服务名称

3.Istio认证

Istio 提供两种类型的认证:

  • Peer authentication:用于服务到服务的认证,以验证进行连接的客户端。Istio 提供双向 TLS 作为传输认证的全栈解决方案。对于双向 TLS,Istio 会自动将两个 PEPs 之间的所有流量升级为双向 TLS。

  • Request authentication:用于最终用户认证,以验证附加到请求的凭据。 Istio 使用 JSON Web Token(JWT)验证启用请求级认证,应用程序负责获取 JWT 凭证并将其附加到请求。

3.1 Peer authentication(双向 TLS 认证)

Istio 通过客户端和服务器端 PEPs 建立服务到服务的通信通道,PEPs 被实现为Envoy 代理。当一个工作负载使用双向 TLS 认证向另一个工作负载发送请求时,该请求的处理方式如下:

  1. Istio 将出站流量从客户端重新路由到客户端的本地 sidecar Envoy。
  2. 客户端 Envoy 与服务器端 Envoy 开始双向 TLS 握手。在握手期间,客户端 Envoy 还做了安全命名检查,以验证服务器证书中显示的服务帐户是否被授权运行目标服务。
  3. 客户端 Envoy 和服务器端 Envoy 建立了一个双向的 TLS 连接,Istio 将流量从客户端 Envoy 转发到服务器端 Envoy。
  4. 授权后,服务器端 Envoy 通过本地 TCP 连接将流量转发到服务器服务。

Istio PKI 使用 X.509 证书为每个工作负载都提供强大的身份标识。可以大规模进行自动化密钥和证书轮换,伴随每个 Envoy 代理都运行着一个 istio-agent 负责证书和密钥的供应。下图显示了这个机制的运行流程。

安全架构图模板 安全架构功能视图_客户端_02

  1. Envoy 向 pilot-agent 发起一个 SDS (Secret Discovery Service) 请求,要求获取自己的证书和私钥。
  2. Pilot-agent 生成私钥和 CSR (Certificates Signing Request,证书签名请求),向 Istiod 发送证书签发请求,请求中包含 CSR 和该 pod 中服务的身份信息。
  3. Istiod 根据请求中服务的身份信息(Service Account)为其签发证书,将证书返回给 Pilot-agent。
  4. Pilot-agent 将证书和私钥通过 SDS 接口返回给 Envoy。

以下对等身份验证策略要求名称空间中的所有工作负载 foo都使用双向TLS:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: "example-policy"
  namespace: "foo"
spec:
  mtls:
    mode: STRICT

3.2 Request authentication(JWT)

用于最终用户认证,以验证附加到请求的凭据。

Istio 使用 JSON Web Token(JWT)验证启用请求级认证,应用程序负责获取 JWT 凭证并将其附加到请求。

  1. 为foo namespace下的httpbin workload添加jwt token
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: "jwt-example"
  namespace: foo
spec:
  selector:
    matchLabels:
      app: httpbin
  jwtRules:
  - issuer: "testing@secure.istio.io"
    jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.10/security/tools/jwt/samples/jwks.json"
EOF
  1. 配置文件require-jwt, 要求所有到httpbin的请求都需要有合法的jwt,且jwt_iss/jwt_sub为 testing@secure.istio.io/testing@secure.istio.io
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: require-jwt
  namespace: foo
spec:
  selector:
    matchLabels:
      app: httpbin
  action: ALLOW
  rules:
  - from:
    - source:
       requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
EOF
  1. 无效的jwt token请求会被拒绝
kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -sS -o /dev/null -H "Authorization: Bearer invalidToken" -w "%{http_code}\n"
401
  1. 有效的jwt token请求被允许
$ TOKEN=$(curl https://raw.githubusercontent.com/istio/istio/release-1.10/security/tools/jwt/samples/demo.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode -
{"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"testing@secure.istio.io","sub":"testing@secure.istio.io"}

$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -sS -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
200

4. Istio授权

Istio 的授权功能为网格中的工作负载提供网格、命名空间和工作负载级别的访问控制。

安全架构图模板 安全架构功能视图_客户端_03

  • 对于未应用授权策略的工作负载,Istio 不会执行访问控制,放行所有请求。
  • 要配置授权策略,请创建一个 AuthorizationPolicy 自定义资源。 一个授权策略包括选择器(selector),动作(action) 和一个规则(rules)列表

以下示例显示了一种授权策略,当发送的请求具有有效的JWT令牌时,该策略允许两个来源( cluster.local/ns/default/sa/sleep服务帐户和dev名称空间)访问httpbin

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: ALLOW
 rules:
 - from:
   - source:
       principals: ["cluster.local/ns/default/sa/sleep"]
   - source:
       namespaces: ["dev"]
   to:
   - operation:
       methods: ["GET"]
   when:
   - key: request.auth.claims[iss]
     values: ["https://accounts.google.com"]