mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
kubeadm: support certificate chain validation
Fixes an issue where some kubeadm phases fail if a certificate file contains a certificate chain with one or more intermediate CA certificates. The validation algorithm has been changed from requiring that a certificate was signed directly by the root CA to requiring that there is a valid certificate chain back to the root CA.
This commit is contained in:
parent
73118aecca
commit
de8821acd3
@ -263,7 +263,7 @@ func runCertPhase(cert *certsphase.KubeadmCert, caCert *certsphase.KubeadmCert)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if certData, _, err := pkiutil.TryLoadCertAndKeyFromDisk(data.CertificateDir(), cert.BaseName); err == nil {
|
if certData, intermediates, err := pkiutil.TryLoadCertChainFromDisk(data.CertificateDir(), cert.BaseName); err == nil {
|
||||||
certsphase.CheckCertificatePeriodValidity(cert.BaseName, certData)
|
certsphase.CheckCertificatePeriodValidity(cert.BaseName, certData)
|
||||||
|
|
||||||
caCertData, err := pkiutil.TryLoadCertFromDisk(data.CertificateDir(), caCert.BaseName)
|
caCertData, err := pkiutil.TryLoadCertFromDisk(data.CertificateDir(), caCert.BaseName)
|
||||||
@ -273,7 +273,7 @@ func runCertPhase(cert *certsphase.KubeadmCert, caCert *certsphase.KubeadmCert)
|
|||||||
|
|
||||||
certsphase.CheckCertificatePeriodValidity(caCert.BaseName, caCertData)
|
certsphase.CheckCertificatePeriodValidity(caCert.BaseName, caCertData)
|
||||||
|
|
||||||
if err := certData.CheckSignatureFrom(caCertData); err != nil {
|
if err := pkiutil.VerifyCertChain(certData, intermediates, caCertData); err != nil {
|
||||||
return errors.Wrapf(err, "[certs] certificate %s not signed by CA certificate %s", cert.BaseName, caCert.BaseName)
|
return errors.Wrapf(err, "[certs] certificate %s not signed by CA certificate %s", cert.BaseName, caCert.BaseName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,8 +229,14 @@ func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert
|
|||||||
|
|
||||||
// Checks if the signed certificate exists in the PKI directory
|
// Checks if the signed certificate exists in the PKI directory
|
||||||
if pkiutil.CertOrKeyExist(pkiDir, baseName) {
|
if pkiutil.CertOrKeyExist(pkiDir, baseName) {
|
||||||
// Try to load signed certificate .crt and .key from the PKI directory
|
// Try to load key from the PKI directory
|
||||||
signedCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, baseName)
|
_, err := pkiutil.TryLoadKeyFromDisk(pkiDir, baseName)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failure loading %s key", baseName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load certificate from the PKI directory
|
||||||
|
signedCert, intermediates, err := pkiutil.TryLoadCertChainFromDisk(pkiDir, baseName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failure loading %s certificate", baseName)
|
return errors.Wrapf(err, "failure loading %s certificate", baseName)
|
||||||
}
|
}
|
||||||
@ -238,7 +244,7 @@ func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert
|
|||||||
CheckCertificatePeriodValidity(baseName, signedCert)
|
CheckCertificatePeriodValidity(baseName, signedCert)
|
||||||
|
|
||||||
// Check if the existing cert is signed by the given CA
|
// Check if the existing cert is signed by the given CA
|
||||||
if err := signedCert.CheckSignatureFrom(signingCert); err != nil {
|
if err := pkiutil.VerifyCertChain(signedCert, intermediates, signingCert); err != nil {
|
||||||
return errors.Errorf("certificate %s is not signed by corresponding CA", baseName)
|
return errors.Errorf("certificate %s is not signed by corresponding CA", baseName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,10 +422,17 @@ func validateSignedCert(l certKeyLocation) error {
|
|||||||
return validateSignedCertWithCA(l, caCert)
|
return validateSignedCertWithCA(l, caCert)
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateSignedCertWithCA tries to load a certificate and validate it with the given caCert
|
// validateSignedCertWithCA tries to load a certificate and private key and
|
||||||
|
// validates that the cert is signed by the given caCert
|
||||||
func validateSignedCertWithCA(l certKeyLocation, caCert *x509.Certificate) error {
|
func validateSignedCertWithCA(l certKeyLocation, caCert *x509.Certificate) error {
|
||||||
// Try to load key and signed certificate
|
// Try to load key from the PKI directory
|
||||||
signedCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(l.pkiDir, l.baseName)
|
_, err := pkiutil.TryLoadKeyFromDisk(l.pkiDir, l.baseName)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failure loading key for %s", l.baseName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load certificate from the PKI directory
|
||||||
|
signedCert, intermediates, err := pkiutil.TryLoadCertChainFromDisk(l.pkiDir, l.baseName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
|
return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
|
||||||
}
|
}
|
||||||
@ -427,7 +440,7 @@ func validateSignedCertWithCA(l certKeyLocation, caCert *x509.Certificate) error
|
|||||||
CheckCertificatePeriodValidity(l.uxName, signedCert)
|
CheckCertificatePeriodValidity(l.uxName, signedCert)
|
||||||
|
|
||||||
// Check if the cert is signed by the CA
|
// Check if the cert is signed by the CA
|
||||||
if err := signedCert.CheckSignatureFrom(caCert); err != nil {
|
if err := pkiutil.VerifyCertChain(signedCert, intermediates, caCert); err != nil {
|
||||||
return errors.Wrapf(err, "certificate %s is not signed by corresponding CA", l.uxName)
|
return errors.Wrapf(err, "certificate %s is not signed by corresponding CA", l.uxName)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -256,6 +256,21 @@ func TryLoadCertFromDisk(pkiPath, name string) (*x509.Certificate, error) {
|
|||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TryLoadCertChainFromDisk tries to load the cert chain from the disk
|
||||||
|
func TryLoadCertChainFromDisk(pkiPath, name string) (*x509.Certificate, []*x509.Certificate, error) {
|
||||||
|
certificatePath := pathForCert(pkiPath, name)
|
||||||
|
|
||||||
|
certs, err := certutil.CertsFromFile(certificatePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrapf(err, "couldn't load the certificate file %s", certificatePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
cert := certs[0]
|
||||||
|
intermediates := certs[1:]
|
||||||
|
|
||||||
|
return cert, intermediates, nil
|
||||||
|
}
|
||||||
|
|
||||||
// TryLoadKeyFromDisk tries to load the key from the disk and validates that it is valid
|
// TryLoadKeyFromDisk tries to load the key from the disk and validates that it is valid
|
||||||
func TryLoadKeyFromDisk(pkiPath, name string) (crypto.Signer, error) {
|
func TryLoadKeyFromDisk(pkiPath, name string) (crypto.Signer, error) {
|
||||||
privateKeyPath := pathForKey(pkiPath, name)
|
privateKeyPath := pathForKey(pkiPath, name)
|
||||||
@ -624,3 +639,27 @@ func ValidateCertPeriod(cert *x509.Certificate, offset time.Duration) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyCertChain verifies that a certificate has a valid chain of
|
||||||
|
// intermediate CAs back to the root CA
|
||||||
|
func VerifyCertChain(cert *x509.Certificate, intermediates []*x509.Certificate, root *x509.Certificate) error {
|
||||||
|
rootPool := x509.NewCertPool()
|
||||||
|
rootPool.AddCert(root)
|
||||||
|
|
||||||
|
intermediatePool := x509.NewCertPool()
|
||||||
|
for _, c := range intermediates {
|
||||||
|
intermediatePool.AddCert(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyOptions := x509.VerifyOptions{
|
||||||
|
Roots: rootPool,
|
||||||
|
Intermediates: intermediatePool,
|
||||||
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := cert.Verify(verifyOptions); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user