Skip to content
This repository was archived by the owner on Mar 16, 2024. It is now read-only.

Commit 10cdaa9

Browse files
authored
Merge pull request #924 from iwilltry42/iwilltry42/certs-cleanup-2
Avoid unnecessary TLS certificate requests
2 parents 55504a6 + 9db466f commit 10cdaa9

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

pkg/controller/tls/certs.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package tls
22

33
import (
44
"context"
5+
"crypto/x509"
6+
"encoding/pem"
57
"fmt"
68
"strings"
79

@@ -14,6 +16,8 @@ import (
1416
"github.com/sirupsen/logrus"
1517
corev1 "k8s.io/api/core/v1"
1618
apierrors "k8s.io/apimachinery/pkg/api/errors"
19+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20+
klabels "k8s.io/apimachinery/pkg/labels"
1721
"k8s.io/apimachinery/pkg/util/validation"
1822
"k8s.io/apimachinery/pkg/util/validation/field"
1923
kclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -145,6 +149,56 @@ func ProvisionCerts(req router.Request, resp router.Response) error {
145149
return nil
146150
}
147151

152+
// certFromSecret converts TLS secret data to a TLS certificate
153+
func certFromSecret(secret corev1.Secret) (*x509.Certificate, error) {
154+
tlsPEM, ok := secret.Data["tls.crt"]
155+
if !ok {
156+
return nil, fmt.Errorf("key tls.crt not found in secret %s/%s", secret.Namespace, secret.Name)
157+
}
158+
159+
tlsCertBytes, _ := pem.Decode(tlsPEM)
160+
if tlsCertBytes == nil {
161+
return nil, fmt.Errorf("failed to parse Cert PEM stored in secret %s/%s", secret.Namespace, secret.Name)
162+
}
163+
164+
return x509.ParseCertificate(tlsCertBytes.Bytes)
165+
}
166+
167+
// findExistingCert returns the first TLS secret that matches the given domain
168+
func findExistingCertSecret(ctx context.Context, client kclient.Client, target string) (*corev1.Secret, error) {
169+
// Find existing certificate if exists
170+
existingTLSSecrets := &corev1.SecretList{}
171+
if err := client.List(ctx, existingTLSSecrets, &kclient.ListOptions{LabelSelector: klabels.SelectorFromSet(map[string]string{
172+
labels.AcornManaged: "true",
173+
})}); err != nil {
174+
logrus.Errorf("Error listing existing TLS secrets: %v", err)
175+
}
176+
177+
for _, sec := range existingTLSSecrets.Items {
178+
logrus.Debugf("Found existing TLS secret: %s/%s", sec.Namespace, sec.Name)
179+
if sec.Type != corev1.SecretTypeTLS {
180+
continue
181+
}
182+
domain, ok := sec.Annotations[labels.AcornDomain]
183+
if !ok {
184+
continue
185+
}
186+
187+
if domain == target {
188+
cert, err := certFromSecret(sec)
189+
if err != nil {
190+
logrus.Errorf("Error parsing cert from secret: %v", err)
191+
continue
192+
}
193+
if err := cert.VerifyHostname(target); err == nil {
194+
return &sec, nil
195+
}
196+
}
197+
198+
}
199+
return nil, nil
200+
}
201+
148202
func (u *LEUser) provisionCertIfNotExists(ctx context.Context, client kclient.Client, domain string, namespace string, secretName string) error {
149203
// Find existing secret if exists
150204
existingSecret := &corev1.Secret{}
@@ -158,6 +212,45 @@ func (u *LEUser) provisionCertIfNotExists(ctx context.Context, client kclient.Cl
158212
return findSecretErr
159213
}
160214

215+
// Let's see if we have some existing certificate that matches the domain
216+
existingSecret, err := findExistingCertSecret(ctx, client, domain)
217+
if err != nil {
218+
return err
219+
}
220+
if existingSecret != nil {
221+
// We found an existing certificate
222+
// 1. It's in the same namespace, so it will be picked up automatically
223+
if existingSecret.Namespace == namespace {
224+
logrus.Debugf("Found existing TLS secret %s/%s for domain %s", existingSecret.Namespace, existingSecret.Name, domain)
225+
// Skip: TLS secret already exists, nothing to do here, renewal will be handled elsewhere
226+
return nil
227+
}
228+
229+
logrus.Debugf("Found existing TLS secret %s/%s for domain %s, copying to %s/%s", existingSecret.Namespace, existingSecret.Name, domain, namespace, secretName)
230+
231+
// 2. Copy secret to new namespace
232+
copiedSecret := &corev1.Secret{
233+
ObjectMeta: metav1.ObjectMeta{
234+
Name: secretName,
235+
Namespace: namespace,
236+
Labels: map[string]string{
237+
labels.AcornManaged: "true",
238+
},
239+
Annotations: map[string]string{
240+
labels.AcornDomain: domain,
241+
},
242+
},
243+
Data: existingSecret.Data,
244+
Type: existingSecret.Type,
245+
}
246+
247+
if err := client.Create(ctx, copiedSecret); err != nil {
248+
logrus.Errorf("Error creating TLS secret %s/%s: %v", copiedSecret.Namespace, copiedSecret.Name, err)
249+
return err
250+
}
251+
return nil
252+
}
253+
161254
go func() {
162255
// Do not start a new challenge if we already have one in progress
163256
if !lockDomain(domain) {

pkg/controller/tls/letsencrypt.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ func (u *LEUser) httpChallenge(ctx context.Context, domain string) (*certificate
502502
{
503503
Path: "/.well-known/acme-challenge/",
504504
PathType: func() *networkingv1.PathType {
505-
pt := networkingv1.PathTypeImplementationSpecific
505+
pt := networkingv1.PathTypePrefix
506506
return &pt
507507
}(),
508508
Backend: networkingv1.IngressBackend{

0 commit comments

Comments
 (0)