Skip to content

Commit 969aa60

Browse files
Merge pull request openshift#486 from tmshort/OCPBUGS-1684m
OCPBUGS-1684: Optimize certificate generation
2 parents 18655e5 + cbd2325 commit 969aa60

File tree

4 files changed

+78
-52
lines changed

4 files changed

+78
-52
lines changed

cmd/collect-profiles/main.go

Lines changed: 74 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import (
3232
const (
3333
profileConfigMapLabelKey = "olm.openshift.io/pprof"
3434
pprofSecretName = "pprof-cert"
35+
validity = 24 * time.Hour
36+
minValidity = 15 * time.Minute
3537
)
3638

3739
var (
@@ -74,7 +76,7 @@ func newCmd() *cobra.Command {
7476
Short: "Retrieves the pprof data from a URL and stores it in a configMap.",
7577
Long: `The collect-profiles command makes https requests against pprof URLs
7678
provided as arguments and stores that information in immutable configMaps.
77-
79+
7880
# Example command with multiple arguments
7981
./collect-profiles -n - openshift-operator-lifecycle-manager \
8082
- --config-mount-path \
@@ -143,15 +145,23 @@ func newCmd() *cobra.Command {
143145
certPath := filepath.Join(certMountPath, corev1.TLSCertKey)
144146
keyPath := filepath.Join(certMountPath, corev1.TLSPrivateKeyKey)
145147

146-
if err := verifyCertAndKeyExist(certPath, keyPath); err != nil {
148+
var tlsCert *tls.Certificate
149+
if tlsCert, err = verifyCertAndKey(certPath, keyPath); err != nil {
147150
logrus.Infof("error verifying provided cert and key: %v", err)
148151
logrus.Info("generating a new cert and key")
149-
return populateServingCert(cmd.Context(), cfg.Client)
152+
if tlsCert, err = populateServingCert(cmd.Context(), cfg.Client); err != nil {
153+
return err
154+
}
155+
// Continue with new certificate/keypair
150156
}
151157

152-
httpClient, err := getHttpClient(certPath, keyPath)
153-
if err != nil {
154-
return err
158+
httpClient := &http.Client{
159+
Transport: &http.Transport{
160+
TLSClientConfig: &tls.Config{
161+
InsecureSkipVerify: true,
162+
Certificates: []tls.Certificate{*tlsCert},
163+
},
164+
},
155165
}
156166

157167
// Track successfully created configMaps by generateName for each endpoint being scrapped.
@@ -205,29 +215,49 @@ func newCmd() *cobra.Command {
205215
return fmt.Errorf("error deleting existing pprof configMaps: %v", errs)
206216
}
207217

208-
// Update serving cert after a successful run
209-
return populateServingCert(cmd.Context(), cfg.Client)
218+
return nil
210219
},
211220
}
212221
}
213222

214-
func verifyCertAndKeyExist(certPath, keyPath string) error {
223+
func verifyCertAndKey(certPath, keyPath string) (*tls.Certificate, error) {
215224
fi, err := os.Stat(certPath)
216225
if err != nil {
217-
return err
226+
return nil, err
218227
}
219228
if fi.Size() == 0 {
220-
return fmt.Errorf("cert file should not be empty")
229+
return nil, fmt.Errorf("cert file should not be empty")
221230
}
222231

223232
fi, err = os.Stat(keyPath)
224233
if err != nil {
225-
return err
234+
return nil, err
226235
}
227236
if fi.Size() == 0 {
228-
return fmt.Errorf("key file should not be empty")
237+
return nil, fmt.Errorf("key file should not be empty")
238+
}
239+
240+
tlsCert, err := tls.LoadX509KeyPair(certPath, keyPath)
241+
if err != nil {
242+
return nil, err
243+
}
244+
245+
x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
246+
if err != nil {
247+
return nil, err
248+
}
249+
250+
now := time.Now()
251+
if x509Cert.NotAfter.Before(now) {
252+
return nil, fmt.Errorf("certificate has expired")
253+
}
254+
// Since this cron runs every 15 minutes, we assume that the job takes less
255+
// than 15 minutes, so make sure there's still 15 minutes of validity left
256+
if x509Cert.NotAfter.Before(now.Add(minValidity)) {
257+
return nil, fmt.Errorf("certificate expires in less than 15 minutes")
229258
}
230-
return nil
259+
260+
return &tlsCert, nil
231261
}
232262

233263
func separateConfigMapsIntoNewestAndExpired(configMaps []corev1.ConfigMap) (newestCMs []corev1.ConfigMap, expiredCMs []corev1.ConfigMap) {
@@ -279,21 +309,6 @@ func newArgument(s string) (*argument, error) {
279309
return arg, nil
280310
}
281311

282-
func getHttpClient(certPath, keyPath string) (*http.Client, error) {
283-
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
284-
if err != nil {
285-
return nil, err
286-
}
287-
return &http.Client{
288-
Transport: &http.Transport{
289-
TLSClientConfig: &tls.Config{
290-
InsecureSkipVerify: true,
291-
Certificates: []tls.Certificate{cert},
292-
},
293-
},
294-
}, nil
295-
}
296-
297312
func requestURLBody(httpClient *http.Client, u *url.URL) ([]byte, error) {
298313
response, err := httpClient.Do(&http.Request{
299314
Method: http.MethodGet,
@@ -315,56 +330,67 @@ func requestURLBody(httpClient *http.Client, u *url.URL) ([]byte, error) {
315330
return b.Bytes(), nil
316331
}
317332

318-
func populateServingCert(ctx context.Context, client client.Client) error {
333+
func populateServingCert(ctx context.Context, client client.Client) (*tls.Certificate, error) {
319334
secret := &corev1.Secret{}
320335
err := client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: pprofSecretName}, secret)
321336
if err != nil {
322-
return err
337+
return nil, err
323338
}
324339

325-
cert, privateKey, err := getCertAndKey()
340+
certPEMBytes, privKeyPEMBytes, err := generateCertAndKey()
326341
if err != nil {
327-
return err
342+
return nil, err
328343
}
329344

330-
secret.Data[corev1.TLSCertKey] = cert
331-
secret.Data[corev1.TLSPrivateKeyKey] = privateKey
332-
return client.Update(ctx, secret)
345+
secret.Data[corev1.TLSCertKey] = certPEMBytes
346+
secret.Data[corev1.TLSPrivateKeyKey] = privKeyPEMBytes
347+
348+
if err = client.Update(ctx, secret); err != nil {
349+
return nil, err
350+
}
351+
// Create tlsCert for client use
352+
tlsCert, err := tls.X509KeyPair(certPEMBytes, privKeyPEMBytes)
353+
if err != nil {
354+
return nil, err
355+
}
356+
return &tlsCert, nil
333357
}
334358

335-
func getCertAndKey() ([]byte, []byte, error) {
359+
func generateCertAndKey() ([]byte, []byte, error) {
360+
now := time.Now()
336361
cert := &x509.Certificate{
337362
SerialNumber: big.NewInt(1658),
338363
Subject: pkix.Name{
339364
Organization: []string{"Red Hat, Inc."},
340365
},
341-
NotBefore: time.Now(),
342-
NotAfter: time.Now().Add(time.Hour),
366+
NotBefore: now,
367+
NotAfter: now.Add(validity),
343368
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
344369
KeyUsage: x509.KeyUsageDigitalSignature,
345370
}
346371

347-
caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
372+
keyPair, err := rsa.GenerateKey(rand.Reader, 4096)
348373
if err != nil {
349374
return nil, nil, err
350375
}
351376

352-
caBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, &caPrivKey.PublicKey, caPrivKey)
377+
// Generate a DER-encoded self-signed certificate
378+
certDER, err := x509.CreateCertificate(rand.Reader, cert, cert, &keyPair.PublicKey, keyPair)
353379
if err != nil {
354380
return nil, nil, err
355381
}
356382

357-
caPEM := new(bytes.Buffer)
358-
pem.Encode(caPEM, &pem.Block{
383+
certPEM := new(bytes.Buffer)
384+
pem.Encode(certPEM, &pem.Block{
359385
Type: "CERTIFICATE",
360-
Bytes: caBytes,
386+
Bytes: certDER,
361387
})
362388

363-
caPrivKeyPEM := new(bytes.Buffer)
364-
pem.Encode(caPrivKeyPEM, &pem.Block{
389+
privKeyPEM := new(bytes.Buffer)
390+
pem.Encode(privKeyPEM, &pem.Block{
365391
Type: "RSA PRIVATE KEY",
366-
Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey),
392+
Bytes: x509.MarshalPKCS1PrivateKey(keyPair),
367393
})
368394

369-
return caPEM.Bytes(), caPrivKeyPEM.Bytes(), nil
395+
return certPEM.Bytes(), privKeyPEM.Bytes(), nil
370396
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ require (
177177
github.com/opencontainers/go-digest v1.0.0 // indirect
178178
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
179179
github.com/openshift/client-go v0.0.0-20220525160904-9e1acff93e4a // indirect
180-
github.com/openshift/cluster-policy-controller v0.0.0-20230329210054-1a5f0ca08be7 // indirect
180+
github.com/openshift/cluster-policy-controller v0.0.0-20230424132259-62adf796a213 // indirect
181181
github.com/otiai10/copy v1.2.0 // indirect
182182
github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9 // indirect
183183
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -983,8 +983,8 @@ github.com/openshift/api v0.0.0-20210517065120-b325f58df679/go.mod h1:dZ4kytOo3s
983983
github.com/openshift/build-machinery-go v0.0.0-20210209125900-0da259a2c359/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE=
984984
github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0 h1:kMiuiZXH1GdfbiMwsuAQOqGaMxlo9NCUk0wT4XAdfNM=
985985
github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0/go.mod h1:uUQ4LClRO+fg5MF/P6QxjMCb1C9f7Oh4RKepftDnEJE=
986-
github.com/openshift/cluster-policy-controller v0.0.0-20230329210054-1a5f0ca08be7 h1:0rJWfuAuSChNKF8Dq1JjX1Yfzixj1PX6ocKYIhvyuZU=
987-
github.com/openshift/cluster-policy-controller v0.0.0-20230329210054-1a5f0ca08be7/go.mod h1:vlkRuwyRueLOQ/ZRRle+rCrh+YNoh+pzJm9WaN9e6mU=
986+
github.com/openshift/cluster-policy-controller v0.0.0-20230424132259-62adf796a213 h1:Fpyt5GHMm1JqRz1xYeBjnzT5VxII+s5d7N9HmyH7iUk=
987+
github.com/openshift/cluster-policy-controller v0.0.0-20230424132259-62adf796a213/go.mod h1:vlkRuwyRueLOQ/ZRRle+rCrh+YNoh+pzJm9WaN9e6mU=
988988
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
989989
github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k=
990990
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=

vendor/modules.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ github.com/openshift/client-go/config/informers/externalversions/config
632632
github.com/openshift/client-go/config/informers/externalversions/config/v1
633633
github.com/openshift/client-go/config/informers/externalversions/internalinterfaces
634634
github.com/openshift/client-go/config/listers/config/v1
635-
# github.com/openshift/cluster-policy-controller v0.0.0-20230329210054-1a5f0ca08be7
635+
# github.com/openshift/cluster-policy-controller v0.0.0-20230424132259-62adf796a213
636636
## explicit; go 1.19
637637
github.com/openshift/cluster-policy-controller/pkg/psalabelsyncer/nsexemptions
638638
# github.com/operator-framework/api v0.17.3 => ./staging/api

0 commit comments

Comments
 (0)