go / expert
Snippet
Zero-Downtime TLS-Zertifikat Live-Reloading mit Generischen Atomen Pointern
Durch die Kombination des dynamischen GetCertificate-Callbacks von tls.Config mit atomic.Pointer[tls.Certificate] (eingeführt in Go 1.19) können Server-TLS-Zertifikate zur Laufzeit im Speicher ausgetauscht werden, ohne Mutex-Sperren zu erwerben oder bestehende Verbindungs-Handshakes zu unterbrechen.
snippet.go
go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package mainimport ("crypto/tls""errors""fmt""sync/atomic")type CertificateReloader struct {certPointer atomic.Pointer[tls.Certificate]}func NewCertificateReloader(initialCert tls.Certificate) *CertificateReloader {r := &CertificateReloader{}r.certPointer.Store(&initialCert)return r}func (r *CertificateReloader) SwapCertificate(newCert tls.Certificate) {r.certPointer.Store(&newCert)}func (r *CertificateReloader) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {cert := r.certPointer.Load()if cert == nil {return nil, errors.New("no valid tls certificate loaded")}return cert, nil}func main() {initial := tls.Certificate{}reloader := NewCertificateReloader(initial)config := &tls.Config{GetCertificate: reloader.GetCertificate,}reloader.SwapCertificate(tls.Certificate{})fmt.Printf("TLS GetCertificate hook dynamic reload verified: %v\n", config.GetCertificate != nil)}
Erklärung
1
certPointer atomic.Pointer[tls.Certificate]
Typsicherer atomarer Zeiger, der eine threadsichere Referenz auf die aktuelle TLS-Zertifikat-Struktur hält.
2
GetCertificate: reloader.GetCertificate,
Konfiguriert tls.Config so, dass bei jedem eingehenden Client-Handshake die atomare Abruffunktion aufgerufen wird.