mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
Add support for cross-signing new certs during ca rotation
We need to send the full chain in order for cross-signing to work properly during switchover to a new root. Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
This commit is contained in:
parent
68fcb48a35
commit
977a85559e
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/k3s-io/k3s/pkg/daemons/config"
|
"github.com/k3s-io/k3s/pkg/daemons/config"
|
||||||
"github.com/k3s-io/k3s/pkg/passwd"
|
"github.com/k3s-io/k3s/pkg/passwd"
|
||||||
"github.com/k3s-io/k3s/pkg/token"
|
"github.com/k3s-io/k3s/pkg/token"
|
||||||
|
"github.com/k3s-io/k3s/pkg/util"
|
||||||
"github.com/k3s-io/k3s/pkg/version"
|
"github.com/k3s-io/k3s/pkg/version"
|
||||||
certutil "github.com/rancher/dynamiclistener/cert"
|
certutil "github.com/rancher/dynamiclistener/cert"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -592,7 +593,7 @@ func createClientCertKey(regen bool, commonName string, organization []string, a
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
caCert, err := certutil.CertsFromFile(caCertFile)
|
caCerts, err := certutil.CertsFromFile(caCertFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -615,12 +616,12 @@ func createClientCertKey(regen bool, commonName string, organization []string, a
|
|||||||
if altNames != nil {
|
if altNames != nil {
|
||||||
cfg.AltNames = *altNames
|
cfg.AltNames = *altNames
|
||||||
}
|
}
|
||||||
cert, err := certutil.NewSignedCert(cfg, key.(crypto.Signer), caCert[0], caKey.(crypto.Signer))
|
cert, err := certutil.NewSignedCert(cfg, key.(crypto.Signer), caCerts[0], caKey.(crypto.Signer))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, certutil.WriteCert(certFile, append(certutil.EncodeCertPEM(cert), certutil.EncodeCertPEM(caCert[0])...))
|
return true, certutil.WriteCert(certFile, util.EncodeCertsPEM(cert, caCerts))
|
||||||
}
|
}
|
||||||
|
|
||||||
func exists(files ...string) bool {
|
func exists(files ...string) bool {
|
||||||
|
@ -143,10 +143,6 @@ func validateCA(oldCAPath, newCAPath string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(oldCerts) == 1 {
|
|
||||||
return errors.New("old CA is self-signed")
|
|
||||||
}
|
|
||||||
|
|
||||||
newCerts, err := certutil.CertsFromFile(newCAPath)
|
newCerts, err := certutil.CertsFromFile(newCAPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -158,16 +154,26 @@ func validateCA(oldCAPath, newCAPath string) error {
|
|||||||
|
|
||||||
roots := x509.NewCertPool()
|
roots := x509.NewCertPool()
|
||||||
intermediates := x509.NewCertPool()
|
intermediates := x509.NewCertPool()
|
||||||
for i, cert := range oldCerts {
|
|
||||||
|
// Load all certs from the old bundle
|
||||||
|
for _, cert := range oldCerts {
|
||||||
|
if len(cert.AuthorityKeyId) == 0 || bytes.Equal(cert.AuthorityKeyId, cert.SubjectKeyId) {
|
||||||
|
roots.AddCert(cert)
|
||||||
|
} else {
|
||||||
|
intermediates.AddCert(cert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include any intermediates from the new bundle, in case they're cross-signed by a cert in the old bundle
|
||||||
|
for i, cert := range newCerts {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
if len(cert.AuthorityKeyId) == 0 || bytes.Equal(cert.AuthorityKeyId, cert.SubjectKeyId) {
|
if len(cert.AuthorityKeyId) > 0 {
|
||||||
roots.AddCert(cert)
|
|
||||||
} else {
|
|
||||||
intermediates.AddCert(cert)
|
intermediates.AddCert(cert)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify the first cert in the bundle, using the combined roots and intermediates
|
||||||
_, err = newCerts[0].Verify(x509.VerifyOptions{Roots: roots, Intermediates: intermediates})
|
_, err = newCerts[0].Verify(x509.VerifyOptions{Roots: roots, Intermediates: intermediates})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "new CA cert cannot be verified using old CA chain")
|
err = errors.Wrap(err, "new CA cert cannot be verified using old CA chain")
|
||||||
|
@ -219,7 +219,7 @@ func servingKubeletCert(server *config.Control, keyFile string, auth nodePassBoo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
caCert, caKey, key, err := getCACertAndKeys(server.Runtime.ServerCA, server.Runtime.ServerCAKey, server.Runtime.ServingKubeletKey)
|
caCerts, caKey, key, err := getCACertAndKeys(server.Runtime.ServerCA, server.Runtime.ServerCAKey, server.Runtime.ServingKubeletKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendError(err, resp)
|
sendError(err, resp)
|
||||||
return
|
return
|
||||||
@ -245,7 +245,7 @@ func servingKubeletCert(server *config.Control, keyFile string, auth nodePassBoo
|
|||||||
DNSNames: []string{nodeName, "localhost"},
|
DNSNames: []string{nodeName, "localhost"},
|
||||||
IPs: ips,
|
IPs: ips,
|
||||||
},
|
},
|
||||||
}, key, caCert[0], caKey)
|
}, key, caCerts[0], caKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendError(err, resp)
|
sendError(err, resp)
|
||||||
return
|
return
|
||||||
@ -257,7 +257,7 @@ func servingKubeletCert(server *config.Control, keyFile string, auth nodePassBoo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Write(append(certutil.EncodeCertPEM(cert), certutil.EncodeCertPEM(caCert[0])...))
|
resp.Write(util.EncodeCertsPEM(cert, caCerts))
|
||||||
resp.Write(keyBytes)
|
resp.Write(keyBytes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -275,7 +275,7 @@ func clientKubeletCert(server *config.Control, keyFile string, auth nodePassBoot
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
caCert, caKey, key, err := getCACertAndKeys(server.Runtime.ClientCA, server.Runtime.ClientCAKey, server.Runtime.ClientKubeletKey)
|
caCerts, caKey, key, err := getCACertAndKeys(server.Runtime.ClientCA, server.Runtime.ClientCAKey, server.Runtime.ClientKubeletKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendError(err, resp)
|
sendError(err, resp)
|
||||||
return
|
return
|
||||||
@ -285,7 +285,7 @@ func clientKubeletCert(server *config.Control, keyFile string, auth nodePassBoot
|
|||||||
CommonName: "system:node:" + nodeName,
|
CommonName: "system:node:" + nodeName,
|
||||||
Organization: []string{user.NodesGroup},
|
Organization: []string{user.NodesGroup},
|
||||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||||
}, key, caCert[0], caKey)
|
}, key, caCerts[0], caKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendError(err, resp)
|
sendError(err, resp)
|
||||||
return
|
return
|
||||||
@ -297,7 +297,7 @@ func clientKubeletCert(server *config.Control, keyFile string, auth nodePassBoot
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Write(append(certutil.EncodeCertPEM(cert), certutil.EncodeCertPEM(caCert[0])...))
|
resp.Write(util.EncodeCertsPEM(cert, caCerts))
|
||||||
resp.Write(keyBytes)
|
resp.Write(keyBytes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
17
pkg/util/cert.go
Normal file
17
pkg/util/cert.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
|
||||||
|
certutil "github.com/rancher/dynamiclistener/cert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EncodeCertsPEM is a wrapper around the EncodeCertPEM function to return the
|
||||||
|
// PEM encoding of a cert and chain, instead of just a single cert.
|
||||||
|
func EncodeCertsPEM(cert *x509.Certificate, caCerts []*x509.Certificate) []byte {
|
||||||
|
pemBytes := certutil.EncodeCertPEM(cert)
|
||||||
|
for _, caCert := range caCerts {
|
||||||
|
pemBytes = append(pemBytes, certutil.EncodeCertPEM(caCert)...)
|
||||||
|
}
|
||||||
|
return pemBytes
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user