Istio安全主要包括认证和授权,有关授权的RBAC
使用参考之前的文章【Istio安全】服务间访问控制-RBAC
,不过RBAC
已经准备废弃被Authorization
替代,
认证则分为服务间身份验证和来源身份认证,服务间身份验证Istio提供了双向TLS方案,其中涉及的秘钥管理服务,主要由istio/security
模块的
Citadel
和Node Agent
提供,本文主要分析这部分的源码实现。
- Istio 1.14.0
PKI
首先参考官方文档[en]看下几种不同场景的方案,其中Kubernetes 方案
最简单,
Kubernetes 中的代理节点
更适合生产,具体优势参考[en]。
- Kubernetes 方案
- Citadel 监视 Kubernetes apiserver,为每个现有和新的服务帐户创建 SPIFFE 证书和密钥对。Citadel 将证书和密钥对存储为 Kubernetes secret。
- 创建 pod 时,Kubernetes 会根据其服务帐户通过 Kubernetes secret volume 将证书和密钥对挂载到 pod 上。
- Citadel 监视每个证书的生命周期,并通过重写 Kubernetes secret 自动轮换证书。
- Pilot 生成安全命名信息,该信息定义了哪些 Service Account 可以运行哪些服务。Pilot 然后将安全命名信息传递给 envoy sidecar。
- 本地机器方案
- Citadel 创建 gRPC 服务来接受证书签名请求(CSR)。
- 节点代理生成私钥和 CSR,并将 CSR 及其凭据发送给 Citadel 进行签名。
- Citadel 验证 CSR 承载的凭证,并签署 CSR 以生成证书。
- 节点代理将从 Citadel 接收的证书和私钥发送给 Envoy。
- 上述 CSR 过程会定期重复进行证书和密钥轮换。
- Kubernetes 中的代理节点
- Citadel 创建一个 gRPC 服务来接受 CSR 请求。
- Envoy 通过 Envoy secret 发现服务(SDS)API 发送证书和密钥请求。
- 收到 SDS 请求后,节点代理会创建私钥和 CSR,并将 CSR 及其凭据发送给 Citadel 进行签名。
- Citadel 验证 CSR 中携带的凭证,并签署 CSR 以生成证书。
- 节点代理通过 Envoy SDS API 将从 Citadel 接收的证书和私钥发送给 Envoy。
- 上述 CSR 过程会定期重复进行证书和密钥轮换。
CA管理-Citadel
Citadel(源码入口istio/security/cmd/istio_ca
)是Istio自带的秘钥管理服务,使用代理节点也支持外部CA系统,如:VaultCA和GoogleCA。
包括以下能力:
- 证书管理:
pki/ca
- 工作负载的证书轮换:
k8s/controller
- 证书签名服务:
server/ca
TODO 配图
IstioCA
IstioCa支持两种方式:
- 自签名证书,自动轮换SelfSignedCA
- 外部文件证书
SelfSignedCA
自签名证书,自动轮换管理由SelfSignedCARootCertRotator
实现,默认1小时
做一次证书的检查。
SecretController
在Kubernetes方案中工作负载的证书管理,Citadel通过修改secret
对工作负载的证书进行管理,SecretController
监控ServiceAccount
的创建、删除,
Secret
的删除、更新,以及Namespace
的更新,在产生变更时修改secret
完成证书的轮换,同时Pilot Agent
会监控secret
的变更,并重启Envoy使配置生效,完成证书的轮换。
Server
证书服务,与nodeagent
的caclient
交互,包括服务的认证及鉴权等
gRPC服务如下:
- CertificateService
- CreateCertificate(context.Context, *IstioCertificateRequest) (*IstioCertificateResponse, error)
- CAService
废弃
- HandleCSR(context.Context, *CsrRequest) (*CsrResponse, error)
Authenticator
gRPC服务认证,默认一个ClientCertAuthenticator
,当启动SDS时添加了KubeJWTAuthenticator
Authorizer
gRPC服务CAService
和CertificateService
的鉴权
服务的
Authorizer
都是TODO
状态
registry提供了一个身份授权的注册表
- kube/ServiceController
- 监控
Service
创建、删除与修改
- 监控
- kube/ServiceAccountController
- 监控
ServiceAccount
创建、删除与修改
- 监控
Node Agent K8S
NodeAgent(源码入口istio/security/cmd/node_agent_k8s
)是Citadel在工作负载node
或者网关pod
中的代理,为Envoy提供SDS
服务,并与Citadel交互发起CSR
请求。
使用Kubernetes中的代理节点模式时Citadel可以运行为server-only
模式,即不做工作负载的证书管理。
TODO 配图
Node Agent源码均在
nodeagent
目录
CA Client
提供CSR签名接口,服务实现支持citadel
、google
、vault
Client接口
// Client interface defines the clients need to implement to talk to CA for CSR.
type Client interface {
CSRSign(ctx context.Context, csrPEM []byte, subjectID string,
certValidTTLInSec int64) ([]string /*PEM-encoded certificate chain*/, error)
}
Secret Fetcher
作为Workload代理时根据不同的Provider实例化CA Client,或者作为Ingress Gateway代理时监控secret
变更,并通知到secretcache
- Workload代理以
DaemonSet
在node
上运行,使用CA Client与CA Server交互 - Ingress Gateway代理与Workload部署方式不同,代理在Pod内运行,而不是
DaemonSet
Secret Cache
秘钥缓存,负责秘钥的轮换
- 默认
10分钟
做一次检查,对即将过期的做轮换,默认1小时
后过期的证书就做更新- 如果轮询时
token
过期会返回secret=nil
,这时SDS服务在收到notify
后需要将连接断开重连
- 如果轮询时
- 产生轮换时通过
sds.NotifyProxy
通知到SDS服务,SDS服务通过connKey
找到对应的client
,并通过SDS的StreamSecrets
将新的证书推送到Pod
- 在
generateSecret
时,如果检测到rootCert
为nil
或者与certChainPEM
的不一致,将触发rootCert
的更新- SDS服务将新的
rootCert
加入到可信CA
- SDS服务将新的
SecretManager接口
// SecretManager defines secrets management interface which is used by SDS.
type SecretManager interface {
// GenerateSecret generates new secret and cache the secret.
GenerateSecret(ctx context.Context, connectionID, resourceName, token string) (*model.SecretItem, error)
// ShouldWaitForIngressGatewaySecret indicates whether a valid ingress gateway secret is expected.
ShouldWaitForIngressGatewaySecret(connectionID, resourceName, token string) bool
// SecretExist checks if secret already existed.
// This API is used for sds server to check if coming request is ack request.
SecretExist(connectionID, resourceName, token, version string) bool
// DeleteSecret deletes a secret by its key from cache.
DeleteSecret(connectionID, resourceName string)
}
SDS Service
SDS服务实现
NotifyProxy
接收secret
变更的通知- 查找
client
的connection
,通过pushChannel
将secret
变更事件分发给SDS服务接口StreamSecrets
,然后推送到Envoy - 事件类型:
Secret_TlsCertificate
TLS证书Secret_ValidationContext
可信CA
- 查找
- 接收Envoy对SDS服务
StreamSecrets
和FetchSecrets
请求,SecretManager.GenerateSecret()
生成秘钥