kube-apiserver启动的时候若是加了以下的参数:git
--admission_control=ServiceAccount
会自动生成一个apiserver.crt和apiserver.key文件,所在目录是/var/run/kubernetes/
,而且程序启动后会发现,有一个默认的serviceaccount,这种模式下咱们建立的resource都会有一个默认的serviceaccount。github
kube-controller-manager启动时有这么两个参数:golang
--root-ca-file="": If set, this root certificate authority will be included in service account's token secret. This must be a valid PEM-encoded CA bundle. --service-account-private-key-file="": Filename containing a PEM-encoded private RSA key used to sign service account tokens.
这两个参数指定了要用哪些文件作token和根证书。若咱们将这两个参数分别设定值为apiserver.crt和apiserver.key,那么启动后,执行:segmentfault
kubectl get secrets
命令,并详细地查看该secret能够看到,该secret中有了两个data:ca.crt和token,他们分别是apiserver.crt和apiserver.key进行再次加密后的数据。api
这样,咱们建立一个heapster,heapster所属的serviceaccount的secret中的两个data,会被copy到建立出来的容器中,咱们能够进入该容器找到两个数据。app
咱们看到kubernetes的源码中,apiserver的模块有这么一个函数,这个函数在启动apiserver的时候会被调用:less
func GenerateSelfSignedCert(host, certPath, keyPath string, alternateIPs []net.IP, alternateDNS []string) error { priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return err } template := x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()), }, NotBefore: time.Now(), NotAfter: time.Now().Add(time.Hour * 24 * 365), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } ... }
这个函数的功能是建立crt和key,调用这个函数的地方是kubernetes\cmd\kube-apiserver\app\server.go
:函数
if s.TLSCertFile == "" && s.TLSPrivateKeyFile == "" { s.TLSCertFile = path.Join(s.CertDirectory, "apiserver.crt") s.TLSPrivateKeyFile = path.Join(s.CertDirectory, "apiserver.key") // TODO (cjcullen): Is PublicAddress the right address to sign a cert with? alternateIPs := []net.IP{config.ServiceReadWriteIP} alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"} // It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless // alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME") if err := util.GenerateSelfSignedCert(config.PublicAddress.String(), s.TLSCertFile, s.TLSPrivateKeyFile, alternateIPs, alternateDNS); err != nil { glog.Errorf("Unable to generate self signed cert: %v", err) } else { glog.Infof("Using self-signed cert (%s, %s)", s.TLSCertFile, s.TLSPrivateKeyFile) } }
经过上一篇能够知heapster启动后是要向apiserver作https请求的,因此crt和token必不可少。那为何咱们不直接拿这边的crt和key去用呢?this
这篇文章详细地讲了证书生成的相关知识,其中的“添加了SAN的证书生成的过程”和上文源码中调用生成证书的地方是类似的,可是生成证书的过程当中,hostname部分引用了了一个host@time.Now()做为/CN。见源代码中这句:加密
Subject: pkix.Name{ CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()), },
这句将生成crt的时候的hostname设置成了host@time,好比vm-56-65@23542343562 这样的形式,并且每次重启了apiserver,hostname都会变,容器内部可不知道这个hostname,因此根本无法访问。
heapster内部会记录apiserver的几个common name,即kubernetes源码中的:
[]string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"}
我认为这确定是要与kubernetes自生成的crt公用而设计的。 至于为何不行,等有时间再研究。