envoy 中的证书验证
combined_validation_context
组合的证书验证上下文包含默认的CertificateValidationContext和SDS配置.当SDS服务器返回动态CertificateValidationContext时,动态和默认的CertificateValidationContext都将合并到新的CertificateValidationContext中以进行验证.此合并是通过Message::MergeFrom()完成的,因此动态的CertificateValidationContext会覆盖默认CertificateValidationContext中的单个字段,并将重复的字段连接到默认CertificateValidationContext中,并且逻辑OR应用于布尔字段。
validation_context_sds_secret_config
通过SDS API获取验证上下文的配置。
tls_certificate_sds_secret_configs
通过SDS API获取TLS证书的配置
default_validation_context
如何验证对等证书。
Subject Alternative Name匹配器的可选列表.envoy将验证所提供证书的Subject Alternative Name
是否与指定的匹配项之一匹配.当证书具有通配符DNS SAN条目时,为了匹配特定的客户端,应在字符串匹配器中将其配置为完全匹配类型.例如,如果证书的DNS SAN条目具有*.example.com
,则仅允许api.example.com
,则应按如下所示进行配置。
Copy match_subject_alt_names :
exact : "api.example.com"
验证下游证书配置
Copy {
"@type" : "type.googleapis.com/envoy.api.v2.auth.DownstreamTlsContext" , //验证下游,接收请求
"common_tls_context" : {
"alpn_protocols" : [
"istio-peer-exchange" ,
"h2" ,
"http/1.1"
] ,
"tls_certificate_sds_secret_configs" : [ //获取证书
{
"name" : "default" ,
"sds_config" : {
"api_config_source" : {
"api_type" : "GRPC" ,
"grpc_services" : [
{
"envoy_grpc" : {
"cluster_name" : "sds-grpc"
}
}
]
}
}
}
] ,
"combined_validation_context" : { //组合验证规则
"default_validation_context" : {
} ,
"validation_context_sds_secret_config" : { //验证CA
"name" : "ROOTCA" ,
"sds_config" : {
"api_config_source" : {
"api_type" : "GRPC" ,
"grpc_services" : [
{
"envoy_grpc" : {
"cluster_name" : "sds-grpc"
}
}
]
}
}
}
}
} ,
"require_client_certificate" : true // Envoy将拒绝没有有效客户端证书的连接。
}
验证上游证书配置
Copy {
"name" : "envoy.transport_sockets.tls" ,
"typed_config" : {
"@type" : "type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext" , //验证上游,发出请求
"common_tls_context" : {
"alpn_protocols" : [
"istio-peer-exchange" ,
"istio" ,
"h2"
] ,
"tls_certificate_sds_secret_configs" : [
{
"name" : "default" ,
"sds_config" : {
"api_config_source" : {
"api_type" : "GRPC" ,
"grpc_services" : [
{
"envoy_grpc" : {
"cluster_name" : "sds-grpc"
}
}
]
}
}
}
] ,
"combined_validation_context" : { //组合验证规则
"default_validation_context" : {
"match_subject_alt_names" : [ SAN 匹配器
{
"exact" : "spiffe://cluster.local/ns/istio-system/sa/default"
}
]
} ,
"validation_context_sds_secret_config" : {
"name" : "ROOTCA" ,
"sds_config" : {
"api_config_source" : {
"api_type" : "GRPC" ,
"grpc_services" : [
{
"envoy_grpc" : {
"cluster_name" : "sds-grpc"
}
}
]
}
}
}
}
} ,
"sni" : "outbound_.14250_._.jaeger-collector-headless.istio-system.svc.cluster.local"
}
}
对于特殊情况,istio中请求某些基础服务是直接透传的,不会根据spiffeid验证
Copy {
"name" : "envoy.transport_sockets.tls" ,
"typed_config" : {
"@type" : "type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext" ,
"common_tls_context" : {
"validation_context" : {
"trusted_ca" : {
"filename" : "./var/run/secrets/istio/root-cert.pem"
} ,
"match_subject_alt_names" : [ //未经过envoy,域名如下
{
"exact" : "istiod.istio-system.svc"
}
]
} ,
"alpn_protocols" : [
"h2"
] ,
"tls_certificate_sds_secret_configs" : [
{
"name" : "default" ,
"sds_config" : {
"api_config_source" : {
"api_type" : "GRPC" ,
"grpc_services" : [
{
"envoy_grpc" : {
"cluster_name" : "sds-grpc"
}
}
]
}
}
}
]
}
}
}
pilot agent处理SDS流程
constructProxyConfig 构造proxy config getDNSDomain 根据registry生成域名
istio_agent.NewAgent 初始化agent
sa.Start(role.Type == model.SidecarProxy, podNamespaceVar.Get()) 开始启动SDS agent,默认为sidecar模式,网关需要启动为route模式
NewServer
创建SDSserver
对于sidecar模式,将执行initWorkloadSdsService进行grpc server初始化,
initWorkloadSdsService 初始化SDS service
通过s.workloadSds.register(s.grpcWorkloadServer),进行服务注册,需要实现以下接口
Copy type SecretDiscoveryServiceServer interface {
DeltaSecrets ( SecretDiscoveryService_DeltaSecretsServer ) error
// SDS API
StreamSecrets ( SecretDiscoveryService_StreamSecretsServer ) error
// 获取secret
FetchSecrets ( context . Context , * envoy_api_v2 . DiscoveryRequest ) ( * envoy_api_v2 . DiscoveryResponse , error )
}
FetchSecrets
FetchSecrets处理单次证书请求 通过s.st.GenerateSecret生成secret并返回,然后调用GenerateSecret,判断请求证书是否为rootca,若不是将调用generateSecret
如果开启了third-part的exchanger,则进行exchanger进行验证,现在支持Google auth 生成csr后通过sendRetriableRequest提交给pilot-discovery, sendRetriableRequest调用CSRSign方法进行证书签发,这里实际上会请求istiod(pilot-discovery)
Copy 发送请求到认证中心签发证书
func (c * citadelClient ) CSRSign
func (c * istioCertificateServiceClient ) CreateCertificate (ctx context . Context , in * IstioCertificateRequest , opts ... grpc . CallOption )
请求下面的接口进行证书签发
/ istio.v1.auth.IstioCertificateService / CreateCertificate "
StreamSecrets
FetchSecrets处理双向通信,具体操作和FetchSecrets类似
startXDS
创建xdsclient和xdsserver,用于处理envoy请求和请求pilot-discovery
ca server签发证书流程
s.maybeCreateCA
查看目录是否有对应的文件,否则生成自签名证书,作为根证书,后续将使用该证书签发证书
s.startCA
Copy caOpts := & CAOptions {
TrustDomain: s.environment. Mesh ().TrustDomain,
Namespace: args.Namespace,
}
实际上调用的 s.RunCA
s.RrunCA 调用detectAuthEnv,获取k8s token pay load,内容如下示例
Copy {"iss":"kubernetes/serviceaccount","kubernetes.io/serviceaccount/namespace":"istio-system","kubernetes.io/serviceaccount/secret.name":"istiod-service-account-token-h2mxh","kubernetes.io/serviceaccount/service-account.name":"istiod-service-account","kubernetes.io/serviceaccount/service-account.uid":"2f08fe65-6a69-4c2a-881b-8823b90dea60","sub":"system:serviceaccount:istio-system:istiod-service-account"}
caserver.NewWithGRPC
注册以下 Authenticator
对于VM,允许使用以前颁发的证书进行授权。对于VM,将返回具有从SAN提取的身份的调用方,应为SPIFFE身份。
1.解析bear token 2. 根据集群名称获取kubeclient 3. 调用tokenreview.ValidateK8sJwt函数对token进行验证 4. 调用k8s api server token review接口对token进行验证
然后对server进行初始化
caServer.Run()
注册下列 grpc api 用于处理证书请求 pb.RegisterIstioCertificateServiceServer(grpcServer, s)
_IstioCertificateService_CreateCertificate_Handler
srv.(IstioCertificateServiceServer).CreateCertificate(ctx, req.(*IstioCertificateRequest))
实际调用以下方法创建证书 func (s *Server) CreateCertificate
首先调用s.authenticate(ctx)用于认证客户端身份,该方法调用authn.Authenticate(ctx),也就是上面所注册的验证器进行客户端身份验证,返回caller
Copy &Caller{
AuthSource: AuthSourceIDToken,
Identities: []string{fmt.Sprintf(identityTemplate, a.trustDomain, callerNamespace, callerServiceAccount)},
}
返回的caller主要包含证书的身份用于后续签发时的Subject Alternative Name,格式如下
Copy spiffe://cluster.local/ns/foo/sa/httpbin
该字段也会用于服务授权
验证成功后
调用s.ca.GetCAKeyCertBundle().GetAll()获取证书链以及跟证书 s.ca.Sign根据csr,subjectIDs,requestedLifetime,对csr进行签发,requestedLifetime默认为24小时
最终调用util.GenCertFromCSR签发证书