mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
Download cert/key to agent with single HTTP request
Since generated cert/keys are stored locally, each server has a different copy. In a HA setup we need to ensure we download the cert and key from the same server so we combined HTTP requests to do that.
This commit is contained in:
parent
fe4b9cafd6
commit
ff34c5c5cf
@ -6,6 +6,7 @@ import (
|
|||||||
cryptorand "crypto/rand"
|
cryptorand "crypto/rand"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
sysnet "net"
|
sysnet "net"
|
||||||
@ -141,14 +142,13 @@ func getServingCert(nodeName, servingCertFile, servingKeyFile, nodePasswordFile
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
servingCert, servingKey := splitCertKeyPEM(servingCert)
|
||||||
|
|
||||||
if err := ioutil.WriteFile(servingCertFile, servingCert, 0600); err != nil {
|
if err := ioutil.WriteFile(servingCertFile, servingCert, 0600); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to write node cert")
|
return nil, errors.Wrapf(err, "failed to write node cert")
|
||||||
}
|
}
|
||||||
|
|
||||||
servingKey, err := clientaccess.Get("/v1-k3s/serving-kubelet.key", info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := ioutil.WriteFile(servingKeyFile, servingKey, 0600); err != nil {
|
if err := ioutil.WriteFile(servingKeyFile, servingKey, 0600); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to write node key")
|
return nil, errors.Wrapf(err, "failed to write node key")
|
||||||
}
|
}
|
||||||
@ -160,27 +160,60 @@ func getServingCert(nodeName, servingCertFile, servingKeyFile, nodePasswordFile
|
|||||||
return &cert, nil
|
return &cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHostFile(filename string, info *clientaccess.Info) error {
|
func getHostFile(filename, keyFile string, info *clientaccess.Info) error {
|
||||||
basename := filepath.Base(filename)
|
basename := filepath.Base(filename)
|
||||||
fileBytes, err := clientaccess.Get("/v1-k3s/"+basename, info)
|
fileBytes, err := clientaccess.Get("/v1-k3s/"+basename, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(filename, fileBytes, 0600); err != nil {
|
if keyFile == "" {
|
||||||
return errors.Wrapf(err, "failed to write cert %s", filename)
|
if err := ioutil.WriteFile(filename, fileBytes, 0600); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to write cert %s", filename)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileBytes, keyBytes := splitCertKeyPEM(fileBytes)
|
||||||
|
if err := ioutil.WriteFile(filename, fileBytes, 0600); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to write cert %s", filename)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(keyFile, keyBytes, 0600); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to write key %s", filename)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNodeNamedHostFile(filename, nodeName, nodePasswordFile string, info *clientaccess.Info) error {
|
func splitCertKeyPEM(bytes []byte) (certPem []byte, keyPem []byte) {
|
||||||
|
for {
|
||||||
|
b, rest := pem.Decode(bytes)
|
||||||
|
if b == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
bytes = rest
|
||||||
|
|
||||||
|
if strings.Contains(b.Type, "PRIVATE KEY") {
|
||||||
|
keyPem = append(keyPem, pem.EncodeToMemory(b)...)
|
||||||
|
} else {
|
||||||
|
certPem = append(certPem, pem.EncodeToMemory(b)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNodeNamedHostFile(filename, keyFile, nodeName, nodePasswordFile string, info *clientaccess.Info) error {
|
||||||
basename := filepath.Base(filename)
|
basename := filepath.Base(filename)
|
||||||
fileBytes, err := Request("/v1-k3s/"+basename, info, getNodeNamedCrt(nodeName, nodePasswordFile))
|
fileBytes, err := Request("/v1-k3s/"+basename, info, getNodeNamedCrt(nodeName, nodePasswordFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
fileBytes, keyBytes := splitCertKeyPEM(fileBytes)
|
||||||
|
|
||||||
if err := ioutil.WriteFile(filename, fileBytes, 0600); err != nil {
|
if err := ioutil.WriteFile(filename, fileBytes, 0600); err != nil {
|
||||||
return errors.Wrapf(err, "failed to write cert %s", filename)
|
return errors.Wrapf(err, "failed to write cert %s", filename)
|
||||||
}
|
}
|
||||||
|
if err := ioutil.WriteFile(keyFile, keyBytes, 0600); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to write key %s", filename)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,12 +320,12 @@ func get(envInfo *cmds.Agent) (*config.Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientCAFile := filepath.Join(envInfo.DataDir, "client-ca.crt")
|
clientCAFile := filepath.Join(envInfo.DataDir, "client-ca.crt")
|
||||||
if err := getHostFile(clientCAFile, info); err != nil {
|
if err := getHostFile(clientCAFile, "", info); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
serverCAFile := filepath.Join(envInfo.DataDir, "server-ca.crt")
|
serverCAFile := filepath.Join(envInfo.DataDir, "server-ca.crt")
|
||||||
if err := getHostFile(serverCAFile, info); err != nil {
|
if err := getHostFile(serverCAFile, "", info); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,12 +364,8 @@ func get(envInfo *cmds.Agent) (*config.Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientKubeletCert := filepath.Join(envInfo.DataDir, "client-kubelet.crt")
|
clientKubeletCert := filepath.Join(envInfo.DataDir, "client-kubelet.crt")
|
||||||
if err := getNodeNamedHostFile(clientKubeletCert, nodeName, newNodePasswordFile, info); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
clientKubeletKey := filepath.Join(envInfo.DataDir, "client-kubelet.key")
|
clientKubeletKey := filepath.Join(envInfo.DataDir, "client-kubelet.key")
|
||||||
if err := getHostFile(clientKubeletKey, info); err != nil {
|
if err := getNodeNamedHostFile(clientKubeletCert, clientKubeletKey, nodeName, newNodePasswordFile, info); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,12 +375,8 @@ func get(envInfo *cmds.Agent) (*config.Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientKubeProxyCert := filepath.Join(envInfo.DataDir, "client-kube-proxy.crt")
|
clientKubeProxyCert := filepath.Join(envInfo.DataDir, "client-kube-proxy.crt")
|
||||||
if err := getHostFile(clientKubeProxyCert, info); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
clientKubeProxyKey := filepath.Join(envInfo.DataDir, "client-kube-proxy.key")
|
clientKubeProxyKey := filepath.Join(envInfo.DataDir, "client-kube-proxy.key")
|
||||||
if err := getHostFile(clientKubeProxyKey, info); err != nil {
|
if err := getHostFile(clientKubeProxyCert, clientKubeProxyKey, info); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,12 +386,8 @@ func get(envInfo *cmds.Agent) (*config.Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientK3sControllerCert := filepath.Join(envInfo.DataDir, "client-k3s-controller.crt")
|
clientK3sControllerCert := filepath.Join(envInfo.DataDir, "client-k3s-controller.crt")
|
||||||
if err := getHostFile(clientK3sControllerCert, info); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
clientK3sControllerKey := filepath.Join(envInfo.DataDir, "client-k3s-controller.key")
|
clientK3sControllerKey := filepath.Join(envInfo.DataDir, "client-k3s-controller.key")
|
||||||
if err := getHostFile(clientK3sControllerKey, info); err != nil {
|
if err := getHostFile(clientK3sControllerCert, clientK3sControllerKey, info); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,14 +29,10 @@ func router(serverConfig *config.Control, tunnel http.Handler, ca []byte) http.H
|
|||||||
authed := mux.NewRouter()
|
authed := mux.NewRouter()
|
||||||
authed.Use(authMiddleware(serverConfig, "k3s:agent"))
|
authed.Use(authMiddleware(serverConfig, "k3s:agent"))
|
||||||
authed.NotFoundHandler = serverConfig.Runtime.Handler
|
authed.NotFoundHandler = serverConfig.Runtime.Handler
|
||||||
authed.Path("/v1-k3s/serving-kubelet.crt").Handler(servingKubeletCert(serverConfig))
|
authed.Path("/v1-k3s/serving-kubelet.crt").Handler(servingKubeletCert(serverConfig, serverConfig.Runtime.ServingKubeletKey))
|
||||||
authed.Path("/v1-k3s/serving-kubelet.key").Handler(fileHandler(serverConfig.Runtime.ServingKubeletKey))
|
authed.Path("/v1-k3s/client-kubelet.crt").Handler(clientKubeletCert(serverConfig, serverConfig.Runtime.ClientKubeletKey))
|
||||||
authed.Path("/v1-k3s/client-kubelet.crt").Handler(clientKubeletCert(serverConfig))
|
authed.Path("/v1-k3s/client-kube-proxy.crt").Handler(fileHandler(serverConfig.Runtime.ClientKubeProxyCert, serverConfig.Runtime.ClientKubeProxyKey))
|
||||||
authed.Path("/v1-k3s/client-kubelet.key").Handler(fileHandler(serverConfig.Runtime.ClientKubeletKey))
|
authed.Path("/v1-k3s/client-k3s-controller.crt").Handler(fileHandler(serverConfig.Runtime.ClientK3sControllerCert, serverConfig.Runtime.ClientK3sControllerKey))
|
||||||
authed.Path("/v1-k3s/client-kube-proxy.crt").Handler(fileHandler(serverConfig.Runtime.ClientKubeProxyCert))
|
|
||||||
authed.Path("/v1-k3s/client-kube-proxy.key").Handler(fileHandler(serverConfig.Runtime.ClientKubeProxyKey))
|
|
||||||
authed.Path("/v1-k3s/client-k3s-controller.crt").Handler(fileHandler(serverConfig.Runtime.ClientK3sControllerCert))
|
|
||||||
authed.Path("/v1-k3s/client-k3s-controller.key").Handler(fileHandler(serverConfig.Runtime.ClientK3sControllerKey))
|
|
||||||
authed.Path("/v1-k3s/client-ca.crt").Handler(fileHandler(serverConfig.Runtime.ClientCA))
|
authed.Path("/v1-k3s/client-ca.crt").Handler(fileHandler(serverConfig.Runtime.ClientCA))
|
||||||
authed.Path("/v1-k3s/server-ca.crt").Handler(fileHandler(serverConfig.Runtime.ServerCA))
|
authed.Path("/v1-k3s/server-ca.crt").Handler(fileHandler(serverConfig.Runtime.ServerCA))
|
||||||
authed.Path("/v1-k3s/config").Handler(configHandler(serverConfig))
|
authed.Path("/v1-k3s/config").Handler(configHandler(serverConfig))
|
||||||
@ -119,7 +115,7 @@ func getCACertAndKeys(caCertFile, caKeyFile, signingKeyFile string) ([]*x509.Cer
|
|||||||
return caCert, caKey.(crypto.Signer), key.(crypto.Signer), nil
|
return caCert, caKey.(crypto.Signer), key.(crypto.Signer), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func servingKubeletCert(server *config.Control) http.Handler {
|
func servingKubeletCert(server *config.Control, keyFile string) http.Handler {
|
||||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||||
if req.TLS == nil {
|
if req.TLS == nil {
|
||||||
resp.WriteHeader(http.StatusNotFound)
|
resp.WriteHeader(http.StatusNotFound)
|
||||||
@ -156,11 +152,18 @@ func servingKubeletCert(server *config.Control) http.Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyBytes, err := ioutil.ReadFile(keyFile)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(resp, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
resp.Write(append(certutil.EncodeCertPEM(cert), certutil.EncodeCertPEM(caCert[0])...))
|
resp.Write(append(certutil.EncodeCertPEM(cert), certutil.EncodeCertPEM(caCert[0])...))
|
||||||
|
resp.Write(keyBytes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func clientKubeletCert(server *config.Control) http.Handler {
|
func clientKubeletCert(server *config.Control, keyFile string) http.Handler {
|
||||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||||
if req.TLS == nil {
|
if req.TLS == nil {
|
||||||
resp.WriteHeader(http.StatusNotFound)
|
resp.WriteHeader(http.StatusNotFound)
|
||||||
@ -194,17 +197,39 @@ func clientKubeletCert(server *config.Control) http.Handler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyBytes, err := ioutil.ReadFile(keyFile)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(resp, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
resp.Write(append(certutil.EncodeCertPEM(cert), certutil.EncodeCertPEM(caCert[0])...))
|
resp.Write(append(certutil.EncodeCertPEM(cert), certutil.EncodeCertPEM(caCert[0])...))
|
||||||
|
resp.Write(keyBytes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func fileHandler(fileName string) http.Handler {
|
func fileHandler(fileName ...string) http.Handler {
|
||||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||||
if req.TLS == nil {
|
if req.TLS == nil {
|
||||||
resp.WriteHeader(http.StatusNotFound)
|
resp.WriteHeader(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.ServeFile(resp, req, fileName)
|
resp.Header().Set("Content-Type", "text/plain")
|
||||||
|
|
||||||
|
if len(fileName) == 1 {
|
||||||
|
http.ServeFile(resp, req, fileName[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range fileName {
|
||||||
|
bytes, err := ioutil.ReadFile(f)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to read %s: %v", f, err)
|
||||||
|
resp.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp.Write(bytes)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user