mirror of
https://github.com/outbackdingo/kamaji.git
synced 2026-01-27 10:19:29 +00:00
fix(cert): checking api server certificate SAN entries (#641)
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
This commit is contained in:
committed by
GitHub
parent
7904b4d04a
commit
11e1e6c25b
@@ -13,9 +13,11 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
mathrand "math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// CheckPublicAndPrivateKeyValidity checks if the given bytes for the private and public keys are valid.
|
||||
@@ -37,6 +39,39 @@ func CheckPublicAndPrivateKeyValidity(publicKey []byte, privateKey []byte) (bool
|
||||
return checkPublicKeys(privKey.PublicKey, *pubKey), nil
|
||||
}
|
||||
|
||||
// CheckCertificateSAN checks if the Kubernetes API Server certificate matches the SAN stored in the kubeadm:
|
||||
// it must check both IPs and DNS names, and returns a false if the required entry isn't available.
|
||||
// In case of removal of entries, this function returns true nevertheless to avoid reloading a Control Plane uselessly.
|
||||
func CheckCertificateSAN(certificateBytes []byte, certSANs []string) (bool, error) {
|
||||
crt, err := ParseCertificateBytes(certificateBytes)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
ips := sets.New[string]()
|
||||
for _, ip := range crt.IPAddresses {
|
||||
ips.Insert(ip.String())
|
||||
}
|
||||
|
||||
dns := sets.New[string](crt.DNSNames...)
|
||||
|
||||
for _, e := range certSANs {
|
||||
if ip := net.ParseIP(e); ip != nil {
|
||||
if !ips.Has(ip.String()) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if !dns.Has(e) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// CheckCertificateAndPrivateKeyPairValidity checks if the certificate and private key pair are valid.
|
||||
func CheckCertificateAndPrivateKeyPairValidity(certificate []byte, privateKey []byte) (bool, error) {
|
||||
switch {
|
||||
|
||||
@@ -84,6 +84,14 @@ func (r *APIServerCertificate) UpdateTenantControlPlaneStatus(_ context.Context,
|
||||
func (r *APIServerCertificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) controllerutil.MutateFn {
|
||||
return func() error {
|
||||
logger := log.FromContext(ctx, "resource", r.GetName())
|
||||
// The Kubeadm configuration must be retrieved in advance:
|
||||
// this is required to check also the certificate SAN
|
||||
config, kadmErr := getStoredKubeadmConfiguration(ctx, r.Client, r.TmpDirectory, tenantControlPlane)
|
||||
if kadmErr != nil {
|
||||
logger.Error(kadmErr, "cannot retrieve stored kubeadm configuration", "err", kadmErr.Error())
|
||||
|
||||
return fmt.Errorf("failed to generate certificate and private key: %w", kadmErr)
|
||||
}
|
||||
// Retrieving the TenantControlPlane CA:
|
||||
// this is required to trigger a new generation in case of Certificate Authority rotation.
|
||||
namespacedName := k8stypes.NamespacedName{Namespace: tenantControlPlane.GetNamespace(), Name: tenantControlPlane.Status.Certificates.CA.SecretName}
|
||||
@@ -121,18 +129,16 @@ func (r *APIServerCertificate) mutate(ctx context.Context, tenantControlPlane *k
|
||||
logger.Info(fmt.Sprintf("%s certificate-private_key pair is not valid: %s", kubeadmconstants.APIServerCertAndKeyBaseName, err.Error()))
|
||||
}
|
||||
|
||||
if isCAValid && isCertValid {
|
||||
dnsNamesMatches, dnsErr := crypto.CheckCertificateSAN(r.resource.Data[kubeadmconstants.APIServerCertName], config.InitConfiguration.APIServer.CertSANs)
|
||||
if dnsErr != nil {
|
||||
logger.Info(fmt.Sprintf("%s SAN check returned an error: %s", kubeadmconstants.APIServerCertAndKeyBaseName, err.Error()))
|
||||
}
|
||||
|
||||
if isCAValid && isCertValid && dnsNamesMatches {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
config, err := getStoredKubeadmConfiguration(ctx, r.Client, r.TmpDirectory, tenantControlPlane)
|
||||
if err != nil {
|
||||
logger.Error(err, "cannot generate certificate and private key in api server certificate", "details", err.Error())
|
||||
|
||||
return fmt.Errorf("failed to generate certificate and private key: %w", err)
|
||||
}
|
||||
|
||||
ca := kubeadm.CertificatePrivateKeyPair{
|
||||
Name: kubeadmconstants.CACertAndKeyBaseName,
|
||||
Certificate: secretCA.Data[kubeadmconstants.CACertName],
|
||||
|
||||
Reference in New Issue
Block a user