Skip to content

Commit d154940

Browse files
authored
Merge pull request #353 from slauger/fix/cert-renewal-double-race
fix: reuse existing key during certificate renewal
2 parents 4e40c5e + 533e641 commit d154940

1 file changed

Lines changed: 10 additions & 23 deletions

File tree

internal/controller/certificate_signing.go

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -515,8 +515,9 @@ func buildCSR(certname string, dnsAltNames []string, extensions *openvoxv1alpha1
515515
}
516516

517517
// renewCertificate performs certificate renewal via the Puppet CA HTTP API.
518-
// It generates a new key+CSR, authenticates with the existing cert via mTLS,
519-
// and POSTs the CSR to the certificate_renewal endpoint.
518+
// It reuses the existing private key, builds a CSR, authenticates with the
519+
// existing cert via mTLS, and POSTs the CSR to the certificate_renewal endpoint.
520+
// The CA returns a new certificate for the same public key.
520521
func (r *CertificateReconciler) renewCertificate(ctx context.Context, cert *openvoxv1alpha1.Certificate, ca *openvoxv1alpha1.CertificateAuthority, caBaseURL, namespace string) error {
521522
logger := log.FromContext(ctx)
522523

@@ -526,7 +527,6 @@ func (r *CertificateReconciler) renewCertificate(ctx context.Context, cert *open
526527
}
527528

528529
tlsSecretName := fmt.Sprintf("%s-tls", cert.Name)
529-
pendingSecretName := fmt.Sprintf("%s-tls-pending", cert.Name)
530530

531531
// Read existing cert+key from TLS Secret for mTLS authentication
532532
existingSecret := &corev1.Secret{}
@@ -539,20 +539,15 @@ func (r *CertificateReconciler) renewCertificate(ctx context.Context, cert *open
539539
return fmt.Errorf("TLS Secret %s missing cert.pem or key.pem", tlsSecretName)
540540
}
541541

542-
// Ensure a pending key exists (reuse from previous attempt or generate new)
543-
newKeyPEM, err := r.ensurePendingKey(ctx, cert, pendingSecretName, namespace)
544-
if err != nil {
545-
return err
546-
}
547-
548-
// Parse new private key to build CSR
549-
block, _ := pem.Decode(newKeyPEM)
542+
// Reuse the existing private key for renewal -- the CA renews the
543+
// certificate for the same public key, so the key must not change.
544+
block, _ := pem.Decode(existingKeyPEM)
550545
if block == nil {
551-
return fmt.Errorf("invalid PEM in pending key")
546+
return fmt.Errorf("invalid PEM in existing key")
552547
}
553548
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
554549
if err != nil {
555-
return fmt.Errorf("parsing pending key: %w", err)
550+
return fmt.Errorf("parsing existing key: %w", err)
556551
}
557552

558553
csrPEM, err := buildCSR(certname, cert.Spec.DNSAltNames, cert.Spec.CSRExtensions, privateKey)
@@ -635,19 +630,11 @@ func (r *CertificateReconciler) renewCertificate(ctx context.Context, cert *open
635630
return fmt.Errorf("updating Certificate status to Signed: %w", err)
636631
}
637632

638-
// Update TLS Secret with new cert and key
639-
if err := r.createOrUpdateTLSSecret(ctx, cert, ca, tlsSecretName, body, newKeyPEM); err != nil {
633+
// Update TLS Secret with renewed cert and existing key
634+
if err := r.createOrUpdateTLSSecret(ctx, cert, ca, tlsSecretName, body, existingKeyPEM); err != nil {
640635
return fmt.Errorf("updating TLS Secret with renewed cert: %w", err)
641636
}
642637

643-
// Clean up pending Secret
644-
pendingSecret := &corev1.Secret{}
645-
if err := r.Get(ctx, types.NamespacedName{Name: pendingSecretName, Namespace: namespace}, pendingSecret); err == nil {
646-
if err := r.Delete(ctx, pendingSecret); err != nil && !errors.IsNotFound(err) {
647-
logger.Info("failed to delete pending Secret", "error", err)
648-
}
649-
}
650-
651638
logger.Info("certificate renewed via CA API", "certname", certname)
652639
return nil
653640
}

0 commit comments

Comments
 (0)