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 认证向另一个工作负载发送请求时,该请求的处理方式如下:
- Istio 将出站流量从客户端重新路由到客户端的本地 sidecar Envoy。
- 客户端 Envoy 与服务器端 Envoy 开始双向 TLS 握手。在握手期间,客户端 Envoy 还做了安全命名检查,以验证服务器证书中显示的服务帐户是否被授权运行目标服务。
- 客户端 Envoy 和服务器端 Envoy 建立了一个双向的 TLS 连接,Istio 将流量从客户端 Envoy 转发到服务器端 Envoy。
- 授权后,服务器端 Envoy 通过本地 TCP 连接将流量转发到服务器服务。
Istio PKI 使用 X.509 证书为每个工作负载都提供强大的身份标识。可以大规模进行自动化密钥和证书轮换,伴随每个 Envoy 代理都运行着一个 istio-agent 负责证书和密钥的供应。下图显示了这个机制的运行流程。
- Envoy 向 pilot-agent 发起一个 SDS (Secret Discovery Service) 请求,要求获取自己的证书和私钥。
- Pilot-agent 生成私钥和 CSR (Certificates Signing Request,证书签名请求),向 Istiod 发送证书签发请求,请求中包含 CSR 和该 pod 中服务的身份信息。
- Istiod 根据请求中服务的身份信息(Service Account)为其签发证书,将证书返回给 Pilot-agent。
- 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 凭证并将其附加到请求。
- 为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
- 配置文件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
- 无效的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
- 有效的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 的授权功能为网格中的工作负载提供网格、命名空间和工作负载级别的访问控制。
- 对于未应用授权策略的工作负载,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"]