Skip to content

Commit a57f023

Browse files
AlexanderYastrebovThilina Madumal
authored andcommitted
certs/fake: refactor CertificateProvider (#746)
Refactor fake certificate provider to enable creation of multiple certificates with the same CA and to allow manual mocking of GetCertificates result. Follow up on #615 and #587 Signed-off-by: Alexander Yastrebov <[email protected]>
1 parent 81a0757 commit a57f023

File tree

2 files changed

+93
-76
lines changed

2 files changed

+93
-76
lines changed

certs/fake/certificate.go

Lines changed: 82 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -8,100 +8,97 @@ import (
88
"crypto/x509/pkix"
99
"fmt"
1010
"math/big"
11-
"sync"
1211
"time"
1312

1413
"github.com/zalando-incubator/kube-ingress-aws-controller/certs"
1514
)
1615

17-
type caSingleton struct {
18-
once sync.Once
19-
err error
16+
type CA struct {
2017
chainKey *rsa.PrivateKey
2118
roots *x509.CertPool
2219
chainCert *x509.Certificate
2320
}
2421

25-
type CertificateProvider struct {
26-
ca caSingleton
27-
}
22+
func NewCA() (*CA, error) {
23+
const tenYears = time.Hour * 24 * 365 * 10
2824

29-
func (m *CertificateProvider) GetCertificates(ctx context.Context) ([]*certs.CertificateSummary, error) {
30-
tenYears := time.Hour * 24 * 365 * 10
31-
altNames := []string{"foo.bar.org"}
32-
arn := "DUMMY"
33-
notBefore := time.Now()
34-
notAfter := time.Now().Add(time.Hour * 24)
25+
caKey, err := rsa.GenerateKey(rand.Reader, 2048)
26+
if err != nil {
27+
return nil, fmt.Errorf("unable to generate CA key: %w", err)
28+
}
3529

36-
m.ca.once.Do(func() {
37-
caKey, err := rsa.GenerateKey(rand.Reader, 2048)
38-
if err != nil {
39-
m.ca.err = fmt.Errorf("unable to generate CA key: %w", err)
40-
return
41-
}
30+
caCert := x509.Certificate{
31+
SerialNumber: big.NewInt(1),
32+
Subject: pkix.Name{
33+
Organization: []string{"Testing CA"},
34+
},
35+
NotBefore: time.Time{},
36+
NotAfter: time.Now().Add(tenYears),
4237

43-
caCert := x509.Certificate{
44-
SerialNumber: big.NewInt(1),
45-
Subject: pkix.Name{
46-
Organization: []string{"Testing CA"},
47-
},
48-
NotBefore: time.Time{},
49-
NotAfter: time.Now().Add(tenYears),
38+
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
39+
BasicConstraintsValid: true,
5040

51-
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
52-
BasicConstraintsValid: true,
41+
IsCA: true,
42+
}
5343

54-
IsCA: true,
55-
}
56-
caBody, err := x509.CreateCertificate(rand.Reader, &caCert, &caCert, caKey.Public(), caKey)
57-
if err != nil {
58-
m.ca.err = fmt.Errorf("unable to generate CA certificate: %w", err)
59-
return
60-
}
61-
caReparsed, err := x509.ParseCertificate(caBody)
62-
if err != nil {
63-
m.ca.err = fmt.Errorf("unable to parse CA certificate: %w", err)
64-
return
65-
}
66-
m.ca.roots = x509.NewCertPool()
67-
m.ca.roots.AddCert(caReparsed)
44+
caBody, err := x509.CreateCertificate(rand.Reader, &caCert, &caCert, caKey.Public(), caKey)
45+
if err != nil {
46+
return nil, fmt.Errorf("unable to generate CA certificate: %w", err)
47+
}
6848

69-
chainKey, err := rsa.GenerateKey(rand.Reader, 2048)
70-
if err != nil {
71-
m.ca.err = fmt.Errorf("unable to generate sub-CA key: %w", err)
72-
return
73-
}
74-
chainCert := x509.Certificate{
75-
SerialNumber: big.NewInt(2),
76-
Subject: pkix.Name{
77-
Organization: []string{"Testing Sub-CA"},
78-
},
79-
NotBefore: time.Time{},
80-
NotAfter: time.Now().Add(tenYears),
81-
82-
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
83-
BasicConstraintsValid: true,
84-
85-
IsCA: true,
86-
}
87-
chainBody, err := x509.CreateCertificate(rand.Reader, &chainCert, caReparsed, chainKey.Public(), caKey)
88-
if err != nil {
89-
m.ca.err = fmt.Errorf("unable to generate sub-CA certificate: %w", err)
90-
}
91-
chainReparsed, err := x509.ParseCertificate(chainBody)
92-
if err != nil {
93-
m.ca.err = fmt.Errorf("unable to parse sub-CA certificate: %w", err)
94-
return
95-
}
49+
caReparsed, err := x509.ParseCertificate(caBody)
50+
if err != nil {
51+
return nil, fmt.Errorf("unable to parse CA certificate: %w", err)
52+
}
53+
54+
chainKey, err := rsa.GenerateKey(rand.Reader, 2048)
55+
if err != nil {
56+
return nil, fmt.Errorf("unable to generate sub-CA key: %w", err)
57+
}
58+
chainCert := x509.Certificate{
59+
SerialNumber: big.NewInt(2),
60+
Subject: pkix.Name{
61+
Organization: []string{"Testing Sub-CA"},
62+
},
63+
NotBefore: time.Time{},
64+
NotAfter: time.Now().Add(tenYears),
65+
66+
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
67+
BasicConstraintsValid: true,
68+
69+
IsCA: true,
70+
}
71+
72+
chainBody, err := x509.CreateCertificate(rand.Reader, &chainCert, caReparsed, chainKey.Public(), caKey)
73+
if err != nil {
74+
return nil, fmt.Errorf("unable to generate sub-CA certificate: %w", err)
75+
}
76+
77+
chainReparsed, err := x509.ParseCertificate(chainBody)
78+
if err != nil {
79+
return nil, fmt.Errorf("unable to parse sub-CA certificate: %w", err)
80+
}
81+
82+
ca := new(CA)
83+
ca.roots = x509.NewCertPool()
84+
ca.roots.AddCert(caReparsed)
85+
ca.chainKey = chainKey
86+
ca.chainCert = chainReparsed
87+
88+
return ca, nil
89+
}
9690

97-
m.ca.chainKey = chainKey
98-
m.ca.chainCert = chainReparsed
99-
})
91+
func (ca *CA) NewCertificateSummary() (*certs.CertificateSummary, error) {
92+
altNames := []string{"foo.bar.org"}
93+
arn := "DUMMY"
94+
notBefore := time.Now()
95+
notAfter := time.Now().Add(time.Hour * 24)
10096

10197
certKey, err := rsa.GenerateKey(rand.Reader, 2048)
10298
if err != nil {
10399
return nil, fmt.Errorf("unable to generate certificate key: %w", err)
104100
}
101+
105102
cert := x509.Certificate{
106103
SerialNumber: big.NewInt(3),
107104
DNSNames: altNames,
@@ -113,17 +110,27 @@ func (m *CertificateProvider) GetCertificates(ctx context.Context) ([]*certs.Cer
113110
BasicConstraintsValid: true,
114111
}
115112

116-
body, err := x509.CreateCertificate(rand.Reader, &cert, m.ca.chainCert, certKey.Public(), m.ca.chainKey)
113+
body, err := x509.CreateCertificate(rand.Reader, &cert, ca.chainCert, certKey.Public(), ca.chainKey)
117114
if err != nil {
118115
return nil, err
119116
}
117+
120118
reparsed, err := x509.ParseCertificate(body)
121119
if err != nil {
122120
return nil, err
123121
}
124122

125-
c := certs.NewCertificate(arn, reparsed, []*x509.Certificate{m.ca.chainCert})
126-
return []*certs.CertificateSummary{c.WithRoots(m.ca.roots)}, nil
123+
c := certs.NewCertificate(arn, reparsed, []*x509.Certificate{ca.chainCert})
124+
return c.WithRoots(ca.roots), nil
125+
}
126+
127+
type CertificateProvider struct {
128+
Summaries []*certs.CertificateSummary
129+
Error error
130+
}
131+
132+
func (m *CertificateProvider) GetCertificates(_ context.Context) ([]*certs.CertificateSummary, error) {
133+
return m.Summaries, m.Error
127134
}
128135

129136
// certmock implements CertificatesFinder for testing, without validating

worker_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ func TestResourceConversionOneToOne(tt *testing.T) {
3939
// See https://github.com/aws/aws-sdk-go-v2/blob/main/service/ec2/types/types.go, type InstanceState
4040
running := int32(16)
4141

42+
ca, err := certsfake.NewCA()
43+
require.NoError(tt, err)
44+
45+
certSummary, err := ca.NewCertificateSummary()
46+
require.NoError(tt, err)
47+
48+
var certsProvider certs.CertificatesProvider = &certsfake.CertificateProvider{
49+
Summaries: []*certs.CertificateSummary{certSummary},
50+
}
51+
4252
for _, scenario := range []struct {
4353
name string
4454
responsesEC2 fake.EC2Outputs
@@ -514,7 +524,7 @@ func TestResourceConversionOneToOne(tt *testing.T) {
514524
}
515525

516526
log.SetLevel(log.DebugLevel)
517-
problems := doWork(ctx, &certsfake.CertificateProvider{}, 10, time.Hour, a, k, "")
527+
problems := doWork(ctx, certsProvider, 10, time.Hour, a, k, "")
518528
if len(problems.Errors()) > 0 {
519529
t.Error(problems.Errors())
520530
}

0 commit comments

Comments
 (0)