本系列链接:
- Istio源码系列1:pilot-agent 源码分析
- Istio源码系列2:citadel 源码分析
- Istio源码系列3:pilot-discovery 源码分析
- Istio源码系列4:mixer 源码分析
安全整体架构
From: Istio 安全
源码位于 security,编译后名称为 citadel。
命令行介绍
Dockerfile istio.io/istio/security/docker/Dockerfile.citadel
1 | FROM scratch |
查看版本:
1 | # kubectl exec -ti istio-citadel-55cdfdd57c-bh7dk -n istio-system -- /usr/local/bin/istio_ca version |
命令行帮助:
1 | # kubectl exec -ti istio-citadel-55cdfdd57c-bh7dk -n istio-system -- /usr/local/bin/istio_ca --help |
容器内部启动添加的命令行如下:
1 | - --append-dns-names=true |
可以在其运行的 node 节点上通过命令查看
1 | $ /usr/local/bin/istio_ca --self-signed-ca --append-dns-names=true --grpc-port=8060 --grpc-hostname=citadel --citadel-storage-namespace=istio-system --custom-dns-names=istio-pilot-service-account.istio-system:istio-pilot.istio-system,istio-ingressgateway-service-account.istio-system:istio-ingressgateway.istio-system --self-signed-ca=true |
istio-citadel 启动的 yaml 文件
1 | # kubectl get pod istio-citadel-55cdfdd57c-bh7dk -n istio-system -o yaml |
代码流程分析
整体架构
istio.io/istio/security/cmd/istio_ca/main.go
1 | // /usr/local/bin/istio_ca |
runCA 的主函数流程如下:
1 | func runCA() { |
NewSecretController
SecretController 内部会创建两个 Controller:
- ServiceAccount 的监听,如果设置了 listened-namespace,则监听该 namespace 下,否则是全部;
- Secret 的监听,namespace 同上,但是 Controller 只会监听自己创建的类型,即:type:”istio.io/key-and-cert”
实现的主要功能是为 ServiceAccount 创建对应的 Secret,Secret 中设置了相关的证书,在对应的 Pod 启动的时候进行加载;
1 | // NewSecretController returns a pointer to a newly constructed SecretController instance. |
gRPC Server 启动
如果设置了 gRPC 相关的参数,则会启动相关的服务,同上也会启动两个 Controller 和 一个 gRPC Server,Controller 监听的 namespace 由 listened-namespace 设置,同上:
NewServiceController:用于监听添加了注解
alpha.istio.io/kubernetes-serviceaccounts
和alpha.istio.io/canonical-serviceaccounts
的 Service 对象;从注解中解出来对应的用户名对应的 Reg 注册表的映射关系中,当前 key 和 value 都是相同c.reg.AddMapping(svcAcct, svcAcct)
;istio.io/istio/security/pkg/registry/kube/service.go
1
2
3
4
5
6
7// KubeServiceAccountsOnVMAnnotation is to specify the K8s service accounts that are allowed to run
// this service on the VMs
KubeServiceAccountsOnVMAnnotation = "alpha.istio.io/kubernetes-serviceaccounts"
// CanonicalServiceAccountsAnnotation is to specify the non-Kubernetes service accounts that
// are allowed to run this service.
CanonicalServiceAccountsAnnotation = "alpha.istio.io/canonical-serviceaccounts"结构体定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14// ServiceController monitors the service definition changes in a namespace. If a
// new service is added with "alpha.istio.io/kubernetes-serviceaccounts" or
// "alpha.istio.io/canonical-serviceaccounts" annotations enabled,
// the corresponding service account will be added to the identity registry
// for whitelisting.
type ServiceController struct {
core corev1.CoreV1Interface
// identity registry object
reg registry.Registry
// controller for service objects
controller cache.Controller
}
NewServiceAccountController: 监听 ServiceAccount 对象;对于获取到 sa 信息,生成相对应的
SpiffeID
保存到 Reg 注册表的映射关系中,当前 key 和 value 都是相同c.reg.DeleteMapping(id, id)
;结构体定义如下:
istio.io/istio/security/pkg/registry/kube/serviceaccount.go
1
2
3
4
5
6
7
8
9
10
11
12// ServiceAccountController monitors service account definition changes in a namespace.
// For each service account object, its SpiffeID is added to identity registry for
// whitelisting purpose.
type ServiceAccountController struct {
core corev1.CoreV1Interface
// identity registry object
reg registry.Registry
// controller for service objects
controller cache.Controller
}IstioCAServiceServer:主要提供证书的生成和验证功能;
istio.io/istio/security/pkg/server/ca/server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49// CreateCertificate handles an incoming certificate signing request (CSR). It does
// authentication and authorization. Upon validated, signs a certificate that:
// the SAN is the identity of the caller in authentication result.
// the subject public key is the public key in the CSR.
// the validity duration is the ValidityDuration in request, or default value if the given duration is invalid.
// it is signed by the CA signing key.
func (s *Server) CreateCertificate(ctx context.Context, request *pb.IstioCertificateRequest) (
*pb.IstioCertificateResponse, error) {
// 根据请求生成对应的证书
_, _, certChainBytes, rootCertBytes := s.ca.GetCAKeyCertBundle().GetAll()
cert, signErr := s.ca.Sign(
[]byte(request.Csr), caller.Identities, time.Duration(request.ValidityDuration)*time.Second, false)
respCertChain := []string{string(cert)}
respCertChain = append(respCertChain, string(rootCertBytes))
response := &pb.IstioCertificateResponse{
CertChain: respCertChain,
}
log.Debug("CSR successfully signed.")
return response, nil
}
// HandleCSR handles an incoming certificate signing request (CSR). It does
// proper validation (e.g. authentication) and upon validated, signs the CSR
// and returns the resulting certificate. If not approved, reason for refusal
// to sign is returned as part of the response object.
// [TODO](myidpt): Deprecate this function.
func (s *Server) HandleCSR(ctx context.Context, request *pb.CsrRequest) (*pb.CsrResponse, error) {
csr, err := util.ParsePemEncodedCSR(request.CsrPem)
_, err = util.ExtractIDs(csr.Extensions)
// TODO: Call authorizer.
_, _, certChainBytes, _ := s.ca.GetCAKeyCertBundle().GetAll()
cert, signErr := s.ca.Sign(request.CsrPem, []string{}, time.Duration(request.RequestedTtlMinutes)*time.Minute, s.forCA)
response := &pb.CsrResponse{
IsApproved: true,
SignedCert: cert,
CertChain: certChainBytes,
}
log.Debug("CSR successfully signed.")
return response, nil
}
Monitor
Monitor 服务主要用于对外输出检查,为 HttpServer, 主要提供 /metrics
和 /version
,如果启用了 enableProfiling
还会启用 /debug/pprof/
相关的路径;当 Monitor 启动以后, Citadel 则任务已经启动成功,打印以下信息:log.Info("Citadel has started")
;
CA client
如果指定了 upstream CA Server,还会启动一个 CA Client, 创建一个 rotator go routine,定期用于证书的轮转替换;
istio.io/istio/security/pkg/caclient/keycertbundlerotator.go
1 | // Start periodically rotates the KeyCertBundle by interacting with the upstream CA. |
TODO: istio-security-post-install 和 istio-cleanup-secrets Job 作用
除特别声明本站文章均属原创(翻译内容除外),如需要转载请事先联系,转载需要注明作者原文链接地址。