func shouldIssueNewCertificate()

in pkg/controller/elasticsearch/certificates/transport/pod_secret.go [107:195]


func shouldIssueNewCertificate(
	ctx context.Context,
	es esv1.Elasticsearch,
	secret corev1.Secret,
	pod corev1.Pod,
	privateKey crypto.Signer,
	ca *certificates.CA,
	certReconcileBefore time.Duration,
) bool {
	log := ulog.FromContext(ctx)
	certCommonName := buildCertificateCommonName(pod, es)

	generalNames, err := buildGeneralNames(es, pod)
	if err != nil {
		log.Error(err, "Cannot create GeneralNames for the TLS certificate",
			"namespace", pod.Namespace, "pod_name", pod.Name)
		return true
	}

	cert := extractTransportCert(ctx, secret, pod, certCommonName)
	if cert == nil {
		return true
	}

	if !certificates.PrivateMatchesPublicKey(ctx, cert.PublicKey, privateKey) {
		log.Info(
			"Certificate belongs do a different public key, should issue new",
			"namespace", pod.Namespace,
			"subject", cert.Subject,
			"issuer", cert.Issuer,
			"current_ca_subject", ca.Cert.Subject,
			"pod_name", pod.Name,
		)
		return true
	}

	pool := x509.NewCertPool()
	pool.AddCert(ca.Cert)
	verifyOpts := x509.VerifyOptions{
		DNSName:       certCommonName,
		Roots:         pool,
		Intermediates: pool,
	}
	if _, err := cert.Verify(verifyOpts); err != nil {
		log.Info(
			fmt.Sprintf("Certificate was not valid, should issue new: %s", err),
			"namespace", pod.Namespace,
			"subject", cert.Subject,
			"issuer", cert.Issuer,
			"current_ca_subject", ca.Cert.Subject,
			"pod", pod.Name,
		)
		return true
	}

	if time.Now().After(cert.NotAfter.Add(-certReconcileBefore)) {
		log.Info("Certificate soon to expire, should issue new",
			"namespace", pod.Namespace, "pod", pod.Name)
		return true
	}

	// compare actual vs. expected SANs
	expected, err := certificates.MarshalToSubjectAlternativeNamesData(generalNames)
	if err != nil {
		log.Error(err, "Cannot marshal subject alternative names, will issue new certificate",
			"namespace", pod.Namespace, "pod_name", pod.Name)
		return true
	}
	extraExtensionFound := false
	for _, ext := range cert.Extensions {
		if !ext.Id.Equal(certificates.SubjectAlternativeNamesObjectIdentifier) {
			continue
		}
		extraExtensionFound = true
		if !reflect.DeepEqual(ext.Value, expected) {
			log.Info("Certificate SANs do not match expected one, should issue new",
				"namespace", pod.Namespace, "pod_name", pod.Name)
			return true
		}
	}
	if !extraExtensionFound {
		log.Error(errors.New("no SAN extra extension"),
			"SAN extra extension not found, should issue new certificate",
			"namespace", pod.Namespace, "pod_name", pod.Name)
		return true
	}

	return false
}