Skip to content

Istio安全杂谈之一:服务间认证 #3

@acappella2017

Description

@acappella2017

Why authentication and authorization

假定你有一个数据库服务(mongo-db)在你的本地kubernete集群中提供服务。你是希望所有其他的服务都能开心地访问它,还是只有直接和数据库交互的服务能访问它?如果是后者,那么你需要给服务授权(authorization)。

而认证(authentication)是授权的基础。先得知道服务的身份,才能基于身份给予相应的授权。现在问题来了,如何定义一个服务的身份呢?

每个服务都要有个身份

Istio用服务的service account来标识服务的身份。但是,仅仅用service account的名字还不足以标识不同的服务。因为Istio经常用于异构系统的服务治理。也就是说,如果Istio要同时管理两个kubernete集群,或者要处理本地kubernete集群与GKE的统一管理问题,就很有可能出现service account名字冲突的问题。

Istio使用SPIFFE(Secure Production Identity Framework for Everyone)来解决这个异构系统中的身份问题。SPIFFE提供了标准化的在异构系统中生成身份的规范和API,可以想象成身份证号生成器。istio给服务分配的身份证号格式如下:
spiffe://\<trust domain \>/ns/\<namespace\>/sa/\<serviceaccount\>

在kubernete环境中,这个身份证号格式就是
spiffe://<k8s cluster domain>/ns/<k8s namespace>/sa/<serviceaccount>

每个服务都要有张证书

有了身份证号以后,下一个问题是,如何制作身份证。Istio用X.509证书来当身份证。毕竟经过CA认证,假一罚十。每个服务都找外面的CA来申请一个证书显然是不现实的。所以Istio中的Citadel组件提供了一个内置的CA并负责所有证书的签发管理工作。

Citadel会监控Kubernete API server,每当一个新的service account被创建时, Citadel会为service account制作一个私钥和对应的SPIFFE证书,证书的SAN(Subject Alternative Name)字段是service account的SPIFFE ID。私钥与证书对会被作为kubernete secret存储。

当一个pod被创建时,私钥与证书对会作为Kubernetes secret volume挂载到对应的service account中去。

身份证颁发完毕!

交换证书

我们已经有了证书。那么如何才能安全地交换证书呢?答案是双向TLS(mTLS)。

默认情况下,TLS只提供单向校验,也就是客户端(发起TLS连接的服务)会校验服务端(接收TLS连接的服务)的证书,保证服务端是可以信任的一方。而mTLS也要求客户端在建立TLS连接时提供自己的证书给服务器,这下双方都能知道对方的身份啦。

开启服务间认证

那么,如何在istio中开启mTLS呢?

首先,为了保证安全,我们决定制定一个policy把所有没有启用mTLS的request都禁用掉(先破后立)。启用下面的Policy之后,istio-tls这个namespace中的Istio sidecar会检查每一个进入sidecar的请求(incoming request)。如果这不是一个mTLS请求,就把它拒掉。(没带身份证禁止入内)

apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
  name: "default"
  namespace: istio-tls
spec:
  peers:
  - mtls: 
      mode: STRICT

Policy决定了哪些请求会被禁掉,现在所有的请求都会收到503 error code。显然这不是我们想要的结果。下一件需要做的事是提示所有的请求启用mTLS连接。

DestinationRule决定了发起对服务的访问时,哪些情况下要带上身份证。例如,启用下面的DestinationRule后,istio-tls这个namespace中的sidecar会知道,如果要发起对别的服务的访问(outcoming request),我最好每次都启用mTLS连接。

apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
  name: "default"
  namespace: istio-tls
spec:
  host: "*.local"
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL

DestinationRule启用后,服务之间的访问又恢复正常了,并且启用了mTLS!好了,故事讲到这里,服务之间终于互相知道对方是谁了。下一篇将是如何使用服务的身份信息进行进一步的权限控制。

参考

  1. Istio concept:Policies and Security
  2. Istio Service Mesh: service to service communication
  3. 微服务安全沉思录之二:认证与鉴权

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions