Skip to content

Commit 07026c9

Browse files
author
Ziqi Zhang
committed
Add CRL support to Prometheus
This commit adds support for certificate revocation status by Certificate Revocation List (CRL) in Prometheus. New fields 'CRL' and 'CRLFile' have been added to the Prometheus config ('tls_config' section). These enable certificate revocation validation with the provided CRL. The Prometheus loads the Certificate Revocation List (CRL) to validate the revocation status of the peer's certificate chain by invoking the 'verifyPeerCertificate' (https://pkg.go.dev/crypto/tls) function during a TLS handshake. Signed-off-by: Ziqi Zhang <[email protected]>
1 parent 94bf982 commit 07026c9

22 files changed

+1365
-307
lines changed

config/generate.go

+159-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func GenerateCertificateAuthority(commonName string, parentCert *x509.Certificat
9292
},
9393
NotBefore: now,
9494
NotAfter: now.Add(validityPeriod),
95-
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
95+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
9696
IsCA: true,
9797
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
9898
BasicConstraintsValid: true,
@@ -186,6 +186,51 @@ func writeCertificateAndKey(path string, cert *x509.Certificate, key *rsa.Privat
186186
return nil
187187
}
188188

189+
func GenerateCRL(cert *x509.Certificate, privateKey *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, isExpired bool) ([]byte, error) {
190+
now := time.Now()
191+
192+
next := now.Add(30 * 24 * time.Hour)
193+
if isExpired {
194+
next = now
195+
}
196+
197+
crl := &x509.RevocationList{
198+
SignatureAlgorithm: x509.SHA256WithRSA,
199+
ThisUpdate: now,
200+
NextUpdate: next,
201+
RevokedCertificates: revokedCerts,
202+
Number: big.NewInt(1),
203+
Issuer: cert.Subject,
204+
}
205+
206+
crlBytes, err := x509.CreateRevocationList(rand.Reader, crl, cert, privateKey)
207+
if err != nil {
208+
return nil, fmt.Errorf("cannot create revocation list: %v", err)
209+
}
210+
211+
return crlBytes, nil
212+
}
213+
214+
func writeCRLs(filename string, crlData [][]byte) error {
215+
crlPemBytes := new(bytes.Buffer)
216+
for _, data := range crlData {
217+
crlPem := &pem.Block{
218+
Type: "X509 CRL",
219+
Bytes: data,
220+
}
221+
err := pem.Encode(crlPemBytes, crlPem)
222+
if err != nil {
223+
return err
224+
}
225+
}
226+
227+
if crlPemBytes == nil {
228+
return fmt.Errorf("empty CRL to write")
229+
}
230+
231+
return os.WriteFile(filename, crlPemBytes.Bytes(), 0644)
232+
}
233+
189234
func main() {
190235
log.Println("Generating root CA")
191236
rootCert, rootKey, err := GenerateCertificateAuthority("Prometheus Root CA", nil, nil)
@@ -199,6 +244,12 @@ func main() {
199244
log.Fatal(err)
200245
}
201246

247+
log.Println("Generating Irrelevant CA")
248+
irlvtCert, irlvtKey, err := GenerateCertificateAuthority("Prometheus TLS Irrelevant CA", nil, nil)
249+
if err != nil {
250+
log.Fatal(err)
251+
}
252+
202253
log.Println("Generating server certificate")
203254
cert, key, err := GenerateCertificate(caCert, caKey, true, "localhost", net.IPv4(127, 0, 0, 1), net.IPv4(127, 0, 0, 0))
204255
if err != nil {
@@ -209,6 +260,16 @@ func main() {
209260
log.Fatal(err)
210261
}
211262

263+
log.Println("Generating revoked server certificate")
264+
revokedCert, revokedKey, err := GenerateCertificate(caCert, caKey, true, "localhost", net.IPv4(127, 0, 0, 1), net.IPv4(127, 0, 0, 0))
265+
if err != nil {
266+
log.Fatal(err)
267+
}
268+
269+
if err := writeCertificateAndKey("testdata/server_revoked", revokedCert, revokedKey); err != nil {
270+
log.Fatal(err)
271+
}
272+
212273
log.Println("Generating client certificate")
213274
cert, key, err = GenerateCertificate(caCert, caKey, false, "localhost")
214275
if err != nil {
@@ -235,11 +296,108 @@ func main() {
235296
log.Fatal(err)
236297
}
237298

299+
if err := os.WriteFile("testdata/tls-ca-no-root.pem", b.Bytes(), 0644); err != nil {
300+
log.Fatal(err)
301+
}
302+
238303
if err := EncodeCertificate(&b, rootCert); err != nil {
239304
log.Fatal(err)
240305
}
241306

242307
if err := os.WriteFile("testdata/tls-ca-chain.pem", b.Bytes(), 0644); err != nil {
243308
log.Fatal(err)
244309
}
310+
311+
if err := EncodeCertificate(&b, irlvtCert); err != nil {
312+
log.Fatal(err)
313+
}
314+
315+
if err := os.WriteFile("testdata/tls-ca-chain-add-irlvt-ca.pem", b.Bytes(), 0644); err != nil {
316+
log.Fatal(err)
317+
}
318+
319+
log.Println("Generating CRLs")
320+
crlProp_revokedCert := []pkix.RevokedCertificate{
321+
{
322+
SerialNumber: revokedCert.SerialNumber,
323+
RevocationTime: time.Now(),
324+
},
325+
}
326+
327+
crl_RevokedCert, err := GenerateCRL(caCert, caKey, crlProp_revokedCert, false)
328+
if err != nil {
329+
log.Fatal(err)
330+
}
331+
332+
if err := writeCRLs("testdata/crl_cert_revoked.pem", [][]byte{crl_RevokedCert}); err != nil {
333+
log.Fatal(err)
334+
}
335+
336+
crl_RevokedCert_expired, err := GenerateCRL(caCert, caKey, crlProp_revokedCert, true)
337+
if err != nil {
338+
log.Fatal(err)
339+
}
340+
341+
if err := writeCRLs("testdata/crl_cert_revoked_expired.pem", [][]byte{crl_RevokedCert_expired}); err != nil {
342+
log.Fatal(err)
343+
}
344+
345+
crl_irlvtRevokedCert, err := GenerateCRL(irlvtCert, irlvtKey, crlProp_revokedCert, false)
346+
if err != nil {
347+
log.Fatal(err)
348+
}
349+
350+
crlProp_empty := []pkix.RevokedCertificate{
351+
{
352+
SerialNumber: big.NewInt(1),
353+
RevocationTime: time.Now(),
354+
},
355+
}
356+
357+
crl_InterCA_Empty, err := GenerateCRL(caCert, caKey, crlProp_empty, false)
358+
if err != nil {
359+
log.Fatal(err)
360+
}
361+
362+
if err := writeCRLs("testdata/crl_inter_empty.pem", [][]byte{crl_InterCA_Empty}); err != nil {
363+
log.Fatal(err)
364+
}
365+
366+
crlProp_RevokedInterCA := []pkix.RevokedCertificate{
367+
{
368+
SerialNumber: caCert.SerialNumber,
369+
RevocationTime: time.Now(),
370+
},
371+
}
372+
373+
crl_revokedInterCA, err := GenerateCRL(rootCert, rootKey, crlProp_RevokedInterCA, false)
374+
if err != nil {
375+
log.Fatal(err)
376+
}
377+
378+
crl_Root_Empty, err := GenerateCRL(rootCert, rootKey, crlProp_empty, false)
379+
if err != nil {
380+
log.Fatal(err)
381+
}
382+
383+
if err := writeCRLs("testdata/crl_root_empty.pem", [][]byte{crl_Root_Empty}); err != nil {
384+
log.Fatal(err)
385+
}
386+
387+
if err := writeCRLs("testdata/crl_chain_all_empty.pem", [][]byte{crl_InterCA_Empty, crl_Root_Empty}); err != nil {
388+
log.Fatal(err)
389+
}
390+
391+
if err := writeCRLs("testdata/crl_chain_cert_revoked.pem", [][]byte{crl_Root_Empty, crl_RevokedCert}); err != nil {
392+
log.Fatal(err)
393+
}
394+
395+
if err := writeCRLs("testdata/crl_chain_inter_ca_cert_revoked.pem", [][]byte{crl_revokedInterCA, crl_InterCA_Empty}); err != nil {
396+
log.Fatal(err)
397+
}
398+
399+
if err := writeCRLs("testdata/crl_chain_irlvt_cert_revoked.pem", [][]byte{crl_InterCA_Empty, crl_irlvtRevokedCert}); err != nil {
400+
log.Fatal(err)
401+
}
402+
245403
}

0 commit comments

Comments
 (0)