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公用而設計的。 至於爲何不行,等有時間再研究。