@@ -2,12 +2,14 @@ package certrotation
2
2
3
3
import (
4
4
"context"
5
+ "crypto/x509"
5
6
"crypto/x509/pkix"
6
- clocktesting "k8s.io/utils/clock/testing"
7
7
"strings"
8
8
"testing"
9
9
"time"
10
10
11
+ clocktesting "k8s.io/utils/clock/testing"
12
+
11
13
"github.com/davecgh/go-spew/spew"
12
14
13
15
"github.com/openshift/api/annotations"
@@ -504,3 +506,201 @@ func TestEnsureTargetSignerCertKeyPair(t *testing.T) {
504
506
})
505
507
}
506
508
}
509
+
510
+ func TestNeedNewTargetCertKeyPair (t * testing.T ) {
511
+ now := time .Now ()
512
+ nowFn := func () time.Time { return now }
513
+
514
+ // Create a test CA certificate
515
+ testCA , err := newTestCACertificate (pkix.Name {CommonName : "test-ca" }, int64 (1 ), metav1.Duration {Duration : time .Hour * 24 * 60 }, nowFn )
516
+ if err != nil {
517
+ t .Fatal (err )
518
+ }
519
+
520
+ // Create another CA certificate with different name
521
+ otherCA , err := newTestCACertificate (pkix.Name {CommonName : "other-ca" }, int64 (2 ), metav1.Duration {Duration : time .Hour * 24 * 60 }, nowFn )
522
+ if err != nil {
523
+ t .Fatal (err )
524
+ }
525
+
526
+ tests := []struct {
527
+ name string
528
+ secret * corev1.Secret
529
+ signer * crypto.CA
530
+ caBundleCerts []* x509.Certificate
531
+ refresh time.Duration
532
+ refreshOnlyWhenExpired bool
533
+ creationRequired bool
534
+ expected string
535
+ }{
536
+ {
537
+ name : "secret doesn't exist" ,
538
+ creationRequired : true ,
539
+ signer : testCA ,
540
+ caBundleCerts : testCA .Config .Certs ,
541
+ refresh : time .Hour ,
542
+ expected : "secret doesn't exist" ,
543
+ },
544
+ {
545
+ name : "valid secret" ,
546
+ creationRequired : false ,
547
+ secret : & corev1.Secret {
548
+ ObjectMeta : metav1.ObjectMeta {
549
+ Annotations : map [string ]string {
550
+ CertificateNotAfterAnnotation : now .Add (1 * time .Hour ).Format (time .RFC3339 ),
551
+ CertificateNotBeforeAnnotation : now .Add (- 1 * time .Hour ).Format (time .RFC3339 ),
552
+ CertificateIssuer : "test-ca" ,
553
+ },
554
+ },
555
+ },
556
+ signer : testCA ,
557
+ caBundleCerts : testCA .Config .Certs ,
558
+ refresh : time .Hour ,
559
+ expected : "" ,
560
+ },
561
+ {
562
+ name : "expired secret" ,
563
+ creationRequired : false ,
564
+ secret : & corev1.Secret {
565
+ ObjectMeta : metav1.ObjectMeta {
566
+ Annotations : map [string ]string {
567
+ CertificateNotAfterAnnotation : now .Add (- 1 * time .Minute ).Format (time .RFC3339 ),
568
+ CertificateNotBeforeAnnotation : now .Add (2 * time .Hour ).Format (time .RFC3339 ),
569
+ CertificateIssuer : "test-ca" ,
570
+ },
571
+ },
572
+ },
573
+ signer : testCA ,
574
+ caBundleCerts : testCA .Config .Certs ,
575
+ refresh : time .Hour ,
576
+ expected : "already expired" ,
577
+ },
578
+ {
579
+ name : "refreshOnlyWhenExpired=true, valid secret" ,
580
+ creationRequired : false ,
581
+ secret : & corev1.Secret {
582
+ ObjectMeta : metav1.ObjectMeta {
583
+ Annotations : map [string ]string {
584
+ CertificateNotAfterAnnotation : now .Add (1 * time .Hour ).Format (time .RFC3339 ), // not expired
585
+ CertificateNotBeforeAnnotation : now .Add (- 1 * time .Hour ).Format (time .RFC3339 ),
586
+ CertificateIssuer : "test-ca" ,
587
+ },
588
+ },
589
+ },
590
+ signer : testCA ,
591
+ caBundleCerts : testCA .Config .Certs ,
592
+ refresh : 30 * time .Minute ,
593
+ refreshOnlyWhenExpired : true ,
594
+ expected : "" , // should not refresh
595
+ },
596
+ {
597
+ name : "refreshOnlyWhenExpired=true, expired secret" ,
598
+ creationRequired : false ,
599
+ secret : & corev1.Secret {
600
+ ObjectMeta : metav1.ObjectMeta {
601
+ Annotations : map [string ]string {
602
+ CertificateNotAfterAnnotation : now .Add (- 1 * time .Hour ).Format (time .RFC3339 ), // expired
603
+ CertificateNotBeforeAnnotation : now .Add (1 * time .Hour ).Format (time .RFC3339 ),
604
+ CertificateIssuer : "test-ca" ,
605
+ },
606
+ },
607
+ },
608
+ signer : testCA ,
609
+ caBundleCerts : testCA .Config .Certs ,
610
+ refresh : 30 * time .Minute ,
611
+ refreshOnlyWhenExpired : true ,
612
+ expected : "already expired" , // needs refresh
613
+ },
614
+ {
615
+ name : "missing issuer name" ,
616
+ creationRequired : false ,
617
+ secret : & corev1.Secret {
618
+ ObjectMeta : metav1.ObjectMeta {
619
+ Annotations : map [string ]string {
620
+ CertificateNotAfterAnnotation : now .Add (2 * time .Hour ).Format (time .RFC3339 ),
621
+ CertificateNotBeforeAnnotation : now .Add (- 1 * time .Hour ).Format (time .RFC3339 ),
622
+ // CertificateIssuer unset
623
+ },
624
+ },
625
+ },
626
+ signer : testCA ,
627
+ caBundleCerts : testCA .Config .Certs ,
628
+ refresh : time .Hour ,
629
+ expected : "missing issuer name" ,
630
+ },
631
+ {
632
+ name : "issuer in ca bundle - valid cert" ,
633
+ creationRequired : false ,
634
+ secret : & corev1.Secret {
635
+ ObjectMeta : metav1.ObjectMeta {
636
+ Annotations : map [string ]string {
637
+ CertificateNotAfterAnnotation : now .Add (2 * time .Hour ).Format (time .RFC3339 ),
638
+ CertificateNotBeforeAnnotation : now .Add (- 1 * time .Hour ).Format (time .RFC3339 ),
639
+ CertificateIssuer : "test-ca" ,
640
+ },
641
+ },
642
+ },
643
+ signer : testCA ,
644
+ caBundleCerts : testCA .Config .Certs , // test-ca is in the bundle
645
+ refresh : time .Hour ,
646
+ expected : "" , // no refresh needed
647
+ },
648
+ {
649
+ name : "issuer not in ca bundle - expired cert" ,
650
+ creationRequired : false ,
651
+ secret : & corev1.Secret {
652
+ ObjectMeta : metav1.ObjectMeta {
653
+ Annotations : map [string ]string {
654
+ CertificateNotAfterAnnotation : now .Add (2 * time .Hour ).Format (time .RFC3339 ),
655
+ CertificateNotBeforeAnnotation : now .Add (- 1 * time .Hour ).Format (time .RFC3339 ),
656
+ CertificateIssuer : "old-ca-name" , // not in bundle
657
+ },
658
+ },
659
+ },
660
+ signer : testCA ,
661
+ caBundleCerts : testCA .Config .Certs , // only contains test-ca
662
+ refresh : time .Hour ,
663
+ expected : `issuer "old-ca-name", not in ca bundle:` ,
664
+ },
665
+ {
666
+ name : "issuer in ca bundle with multiple certs" ,
667
+ creationRequired : false ,
668
+ secret : & corev1.Secret {
669
+ ObjectMeta : metav1.ObjectMeta {
670
+ Annotations : map [string ]string {
671
+ CertificateNotAfterAnnotation : now .Add (2 * time .Hour ).Format (time .RFC3339 ),
672
+ CertificateNotBeforeAnnotation : now .Add (- 1 * time .Hour ).Format (time .RFC3339 ),
673
+ CertificateIssuer : "other-ca" ,
674
+ },
675
+ },
676
+ },
677
+ signer : testCA ,
678
+ caBundleCerts : append (testCA .Config .Certs , otherCA .Config .Certs ... ), // both test-ca and other-ca
679
+ refresh : time .Hour ,
680
+ expected : "" , // other-ca is in the bundle
681
+ },
682
+ }
683
+
684
+ for _ , test := range tests {
685
+ t .Run (test .name , func (t * testing.T ) {
686
+ actual := needNewTargetCertKeyPair (
687
+ test .secret ,
688
+ test .signer ,
689
+ test .caBundleCerts ,
690
+ test .refresh ,
691
+ test .refreshOnlyWhenExpired ,
692
+ test .creationRequired ,
693
+ )
694
+
695
+ if test .expected == "" {
696
+ if actual != "" {
697
+ t .Errorf ("expected no refresh needed, got: %v" , actual )
698
+ }
699
+ } else {
700
+ if ! strings .Contains (actual , test .expected ) {
701
+ t .Errorf ("expected result to contain %q, got: %v" , test .expected , actual )
702
+ }
703
+ }
704
+ })
705
+ }
706
+ }
0 commit comments