Skip to content

Commit

Permalink
Reduce load of parsing the certificate on every request to check cert…
Browse files Browse the repository at this point in the history
… expiration date
  • Loading branch information
bonzofenix committed Dec 19, 2024
1 parent bf9e05e commit f5b31e8
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 19 deletions.
50 changes: 36 additions & 14 deletions src/autoscaler/helpers/httpclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,27 @@ import (
)

type TLSReloadTransport struct {
Base http.RoundTripper
logger lager.Logger
tlsCerts *models.TLSCerts
Base http.RoundTripper
logger lager.Logger
tlsCerts *models.TLSCerts
certExpiration *time.Time
}

func NewTLSReloadTransport(base http.RoundTripper, logger lager.Logger, tlsCerts *models.TLSCerts) *TLSReloadTransport {
return &TLSReloadTransport{
Base: base,
logger: logger,
tlsCerts: tlsCerts,
}
}

func (t *TLSReloadTransport) GetCertExpiration() *time.Time {
if t.certExpiration == nil {
x509Cert, _ := x509.ParseCertificate(t.tlsClientConfig().Certificates[0].Certificate[0])
t.certExpiration = &x509Cert.NotAfter
}

return t.certExpiration
}

func (t *TLSReloadTransport) tlsClientConfig() *tls.Config {
Expand All @@ -30,21 +48,24 @@ func (t *TLSReloadTransport) setTLSClientConfig(tlsConfig *tls.Config) {
t.Base.(*retryablehttp.RoundTripper).Client.HTTPClient.Transport.(*http.Transport).TLSClientConfig = tlsConfig
}

func (t *TLSReloadTransport) certificateExpiringWithin(dur time.Duration) bool {
x509Cert, err := x509.ParseCertificate(t.tlsClientConfig().Certificates[0].Certificate[0])
if err != nil {
return false
}
func (t *TLSReloadTransport) reloadCert() {
tlsConfig, _ := t.tlsCerts.CreateClientConfig()
t.setTLSClientConfig(tlsConfig)
x509Cert, _ := x509.ParseCertificate(t.tlsClientConfig().Certificates[0].Certificate[0])
t.certExpiration = &x509Cert.NotAfter
}

return x509Cert.NotAfter.Sub(time.Now()) < dur
func (t *TLSReloadTransport) certificateExpiringWithin(dur time.Duration) bool {
return t.GetCertExpiration().Sub(time.Now()) < dur
}

func (t *TLSReloadTransport) RoundTrip(req *http.Request) (*http.Response, error) {
if t.certificateExpiringWithin(time.Hour) {
t.logger.Info("reloading-cert", lager.Data{"request": req})
tlsConfig, _ := t.tlsCerts.CreateClientConfig()
t.setTLSClientConfig(tlsConfig)
// Checks for cert validity within 5m timeframe. See https://docs.cloudfoundry.org/devguide/deploy-apps/instance-identity.html
if t.certificateExpiringWithin(5 * time.Minute) {
t.logger.Debug("reloading-cert", lager.Data{"request": req})
t.reloadCert()
} else {
t.logger.Info("cert-not-expiring", lager.Data{"request": req})
t.logger.Debug("cert-not-expiring", lager.Data{"request": req})
}

return t.Base.RoundTrip(req)
Expand Down Expand Up @@ -76,6 +97,7 @@ func CreateHTTPSClient(tlsCerts *models.TLSCerts, config cf.ClientConfig, logger
Base: retryClient.Transport,
logger: logger,
tlsCerts: tlsCerts,
// TODO: try sending reference to tls config of the client
}

return retryClient, nil
Expand Down
19 changes: 14 additions & 5 deletions src/autoscaler/helpers/httpclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"net/http"
"os"
Expand Down Expand Up @@ -78,9 +79,9 @@ var _ = Describe("HTTPClient", func() {
os.Remove(cfInstanceKeyFile)
})

When("Cert cert is not within 1 hour of expiration", func() {
When("Cert cert is not within 5m of expiration", func() {
BeforeEach(func() {
notAfter = time.Now().Add(63 * time.Minute)
notAfter = time.Now().Add(7 * time.Minute)
})

It("should reload the cert", func() {
Expand All @@ -90,11 +91,11 @@ var _ = Describe("HTTPClient", func() {
})
})

When("Cert cert is within 1 hour of expiration", func() {
When("Cert cert is within 5m of expiration", func() {
var cfInstanceCertFileToRotateContent []byte

BeforeEach(func() {
notAfter = time.Now().Add(59 * time.Minute)
notAfter = time.Now().Add(3 * time.Minute)
})

It("should reload the cert", func() {
Expand All @@ -105,16 +106,24 @@ var _ = Describe("HTTPClient", func() {
_, err = configutil.MaterializeContentInFile(certTmpDir, "eventgenerator.crt", string(cfInstanceCertFileToRotateContent))
Expect(err).NotTo(HaveOccurred())

oldCertExpiration := getCertExpirationFromClient(client)
fmt.Println(oldCertExpiration)
Expect(getCertFromClient(client)).To(Equal(string(cfInstanceCertContent)))
client.Get(fakeServer.URL())
Expect(logger).To(gbytes.Say("reloading-cert"))

newCertExpiration := getCertExpirationFromClient(client)
Expect(newCertExpiration).To(BeTemporally(">", oldCertExpiration))
Expect(getCertFromClient(client)).To(Equal(string(cfInstanceCertFileToRotateContent)))
})
})
})
})

func getCertExpirationFromClient(client *http.Client) time.Time {
GinkgoHelper()
return *client.Transport.(*helpers.TLSReloadTransport).GetCertExpiration()
}

func getCertFromClient(client *http.Client) string {
GinkgoHelper()
cert := client.Transport.(*helpers.TLSReloadTransport).Base.(*retryablehttp.RoundTripper).Client.HTTPClient.Transport.(*http.Transport).TLSClientConfig.Certificates[0]
Expand Down

0 comments on commit f5b31e8

Please sign in to comment.