Skip to content

Commit 575b4ba

Browse files
authored
Merge pull request #49 from irbekrm/fix_renewal
Fix default renewal time calculation
2 parents 8ebb8cd + 2acbb8a commit 575b4ba

File tree

3 files changed

+69
-8
lines changed

3 files changed

+69
-8
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/container-storage-interface/spec v1.7.0
88
github.com/go-logr/logr v1.2.3
99
github.com/kubernetes-csi/csi-lib-utils v0.13.0
10+
github.com/stretchr/testify v1.8.1
1011
golang.org/x/net v0.7.0
1112
google.golang.org/grpc v1.53.0
1213
k8s.io/apimachinery v0.26.1
@@ -44,6 +45,7 @@ require (
4445
github.com/modern-go/reflect2 v1.0.2 // indirect
4546
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
4647
github.com/pkg/errors v0.9.1 // indirect
48+
github.com/pmezard/go-difflib v1.0.0 // indirect
4749
github.com/prometheus/client_golang v1.14.0 // indirect
4850
github.com/prometheus/client_model v0.3.0 // indirect
4951
github.com/prometheus/common v0.39.0 // indirect

manager/manager.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ type Options struct {
9595
// resume managing them if any already exist.
9696
func NewManager(opts Options) (*Manager, error) {
9797
if opts.Client == nil {
98-
return nil, errors.New("Client must be set")
98+
return nil, errors.New("client must be set")
9999
}
100100
if opts.ClientForMetadata == nil {
101101
opts.ClientForMetadata = func(_ metadata.Metadata) (cmclient.Interface, error) {
@@ -122,7 +122,7 @@ func NewManager(opts Options) (*Manager, error) {
122122
}
123123
}
124124
if opts.Log == nil {
125-
return nil, errors.New("Log must be set")
125+
return nil, errors.New("log must be set")
126126
}
127127
if opts.MetadataReader == nil {
128128
return nil, errors.New("MetadataReader must be set")
@@ -413,16 +413,13 @@ func (m *Manager) issue(ctx context.Context, volumeID string) error {
413413
return fmt.Errorf("waiting for request: %w", err)
414414
}
415415

416-
// Default the renewal time to be 2/3rds through the certificate's duration.
416+
// Calculate the default next issuance time.
417417
// The implementation's writeKeypair function may override this value before
418418
// writing to the storage layer.
419-
block, _ := pem.Decode(req.Status.Certificate)
420-
crt, err := x509.ParseCertificate(block.Bytes)
419+
renewalPoint, err := calculateNextIssuanceTime(req.Status.Certificate)
421420
if err != nil {
422-
return fmt.Errorf("parsing issued certificate: %w", err)
421+
return fmt.Errorf("calculating next issuance time: %w", err)
423422
}
424-
duration := crt.NotAfter.Sub(crt.NotBefore)
425-
renewalPoint := crt.NotBefore.Add(duration * (2 / 3))
426423
meta.NextIssuanceTime = &renewalPoint
427424

428425
if err := m.writeKeypair(meta, key, req.Status.Certificate, req.Status.CA); err != nil {
@@ -722,3 +719,20 @@ func (m *Manager) Stop() {
722719
delete(m.managedVolumes, k)
723720
}
724721
}
722+
723+
// calculateNextIssuanceTime will return the default time at which the certificate
724+
// should be renewed by the driver- 2/3rds through its lifetime (NotAfter -
725+
// NotBefore).
726+
func calculateNextIssuanceTime(chain []byte) (time.Time, error) {
727+
block, _ := pem.Decode(chain)
728+
crt, err := x509.ParseCertificate(block.Bytes)
729+
if err != nil {
730+
return time.Time{}, fmt.Errorf("parsing issued certificate: %w", err)
731+
}
732+
733+
actualDuration := crt.NotAfter.Sub(crt.NotBefore)
734+
735+
renewBeforeNotAfter := actualDuration / 3
736+
737+
return crt.NotAfter.Add(-renewBeforeNotAfter), nil
738+
}

manager/manager_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@ package manager
22

33
import (
44
"context"
5+
"crypto/rand"
6+
"crypto/rsa"
7+
"crypto/x509"
8+
"encoding/pem"
59
"fmt"
10+
"math/big"
611
"testing"
712
"time"
813

914
cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
1015
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
1116
"github.com/go-logr/logr/testr"
17+
"github.com/stretchr/testify/assert"
18+
"github.com/stretchr/testify/require"
1219
apierrors "k8s.io/apimachinery/pkg/api/errors"
1320
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1421
"k8s.io/apimachinery/pkg/util/wait"
@@ -383,6 +390,44 @@ func TestManager_cleanupStaleRequests(t *testing.T) {
383390
}
384391
}
385392

393+
func Test_calculateNextIssuanceTime(t *testing.T) {
394+
notBefore := time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)
395+
notAfter := time.Date(1970, time.January, 4, 0, 0, 0, 0, time.UTC)
396+
pk, err := rsa.GenerateKey(rand.Reader, 2048)
397+
if err != nil {
398+
t.Fatal(err)
399+
}
400+
401+
template := x509.Certificate{
402+
SerialNumber: new(big.Int).Lsh(big.NewInt(1), 128),
403+
NotBefore: notBefore,
404+
NotAfter: notAfter,
405+
BasicConstraintsValid: true,
406+
}
407+
408+
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &pk.PublicKey, pk)
409+
require.NoError(t, err)
410+
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
411+
412+
tests := map[string]struct {
413+
expTime time.Time
414+
expErr bool
415+
}{
416+
"if no attributes given, return 2/3rd certificate lifetime": {
417+
expTime: notBefore.AddDate(0, 0, 2),
418+
expErr: false,
419+
},
420+
}
421+
422+
for name, test := range tests {
423+
t.Run(name, func(t *testing.T) {
424+
renewTime, err := calculateNextIssuanceTime(certPEM)
425+
assert.Equal(t, test.expErr, err != nil)
426+
assert.Equal(t, test.expTime, renewTime)
427+
})
428+
}
429+
}
430+
386431
func cr(crName, crNamespace, nodeID, volumeID string) *cmapi.CertificateRequest {
387432
return &cmapi.CertificateRequest{
388433
ObjectMeta: metav1.ObjectMeta{

0 commit comments

Comments
 (0)