Skip to content

Commit 517670e

Browse files
committed
improve tls generator
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
1 parent 905697b commit 517670e

2 files changed

Lines changed: 93 additions & 11 deletions

File tree

common-hooks/tls-certificate/internal_tls.go

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package tlscertificate
1919
import (
2020
"context"
2121
"crypto/x509"
22-
"encoding/json"
2322
"errors"
2423
"fmt"
2524
"slices"
@@ -101,11 +100,18 @@ type GenSelfSignedTLSHookConf struct {
101100
// CommonCAValuesPath
102101
// Example: CommonCAValuesPath = 'commonCaPath'
103102
// Values to store:
104-
// commonCaPath.key
105-
// commonCaPath.crt
103+
// commonCaPath.<CommonCACertField> (default: commonCaPath.crt)
104+
// commonCaPath.<CommonCAKeyField> (default: commonCaPath.key)
106105
// Data in values store as plain text
107106
// In helm templates you need use `b64enc` function to encode
108107
CommonCAValuesPath string
108+
// CommonCACertField - field name for the cert within CommonCAValuesPath object.
109+
// Defaults to "crt" if empty.
110+
// Example: set to "cert" if the CA is stored as commonCaPath.cert instead of commonCaPath.crt
111+
CommonCACertField string
112+
// CommonCAKeyField - field name for the key within CommonCAValuesPath object.
113+
// Defaults to "key" if empty.
114+
CommonCAKeyField string
109115
// Canonical name (CN) of common CA certificate.
110116
// If not specified (empty), then (if no CA cert already generated) using CN property of this struct
111117
CommonCACanonicalName string
@@ -134,6 +140,20 @@ func (gss GenSelfSignedTLSHookConf) CommonCAPath() string {
134140
return strings.TrimSuffix(gss.CommonCAValuesPath, ".")
135141
}
136142

143+
func (gss GenSelfSignedTLSHookConf) CACertField() string {
144+
if gss.CommonCACertField == "" {
145+
return "crt"
146+
}
147+
return gss.CommonCACertField
148+
}
149+
150+
func (gss GenSelfSignedTLSHookConf) CAKeyField() string {
151+
if gss.CommonCAKeyField == "" {
152+
return "key"
153+
}
154+
return gss.CommonCAKeyField
155+
}
156+
137157
// SANsGenerator function for generating sans
138158
type SANsGenerator func(input *pkg.HookInput) []string
139159

@@ -281,7 +301,7 @@ func GenSelfSignedTLS(conf GenSelfSignedTLSHookConf) func(ctx context.Context, i
281301
// 2.2) save new common ca in values
282302
// 2.3) mark certificates to regenerate
283303
if useCommonCA {
284-
auth, err = getCommonCA(input, conf.CommonCAPath(), caExpiryDuration, caOutdatedDuration)
304+
auth, err = getCommonCA(input, conf.CommonCAPath(), conf.CACertField(), conf.CAKeyField(), caExpiryDuration, caOutdatedDuration)
285305
if err != nil {
286306
commonCACanonicalName := conf.CommonCACanonicalName
287307

@@ -298,7 +318,8 @@ func GenSelfSignedTLS(conf GenSelfSignedTLSHookConf) func(ctx context.Context, i
298318
return fmt.Errorf("generate ca: %w", err)
299319
}
300320

301-
input.Values.Set(conf.CommonCAPath(), auth)
321+
input.Values.Set(conf.CommonCAPath()+"."+conf.CACertField(), string(auth.Cert))
322+
input.Values.Set(conf.CommonCAPath()+"."+conf.CAKeyField(), string(auth.Key))
302323

303324
mustGenerate = true
304325
}
@@ -384,17 +405,20 @@ func convCertToValues(cert *certificate.Certificate) CertValues {
384405
var ErrCertificateIsNotFound = errors.New("certificate is not found")
385406
var ErrCAIsInvalidOrOutdated = errors.New("ca is invalid or outdated")
386407

387-
func getCommonCA(input *pkg.HookInput, valKey string, caExpiryDuration, caOutdatedDuration time.Duration) (*certificate.Authority, error) {
388-
auth := new(certificate.Authority)
408+
func getCommonCA(input *pkg.HookInput, valKey, certField, keyField string, caExpiryDuration, caOutdatedDuration time.Duration) (*certificate.Authority, error) {
409+
certVal, ok := input.Values.GetOk(valKey + "." + certField)
410+
if !ok {
411+
return nil, ErrCertificateIsNotFound
412+
}
389413

390-
ca, ok := input.Values.GetOk(valKey)
414+
keyVal, ok := input.Values.GetOk(valKey + "." + keyField)
391415
if !ok {
392416
return nil, ErrCertificateIsNotFound
393417
}
394418

395-
err := json.Unmarshal([]byte(ca.String()), auth)
396-
if err != nil {
397-
return nil, err
419+
auth := &certificate.Authority{
420+
Cert: []byte(certVal.String()),
421+
Key: []byte(keyVal.String()),
398422
}
399423

400424
outdated, err := isOutdatedCA(auth.Cert, caExpiryDuration, caOutdatedDuration)

common-hooks/tls-certificate/internal_tls_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,64 @@ func Test_GenSelfSignedTLS(t *testing.T) {
548548
assert.NoError(t, err)
549549
})
550550

551+
t.Run("common ca with custom cert field name", func(t *testing.T) {
552+
dc := mock.NewDependencyContainerMock(t)
553+
554+
snapshots := mock.NewSnapshotsMock(t)
555+
snapshots.GetMock.When(tlscertificate.InternalTLSSnapshotKey).Then([]pkg.Snapshot{})
556+
557+
ca, err := certificate.GenerateCA(
558+
"cert-name",
559+
certificate.WithKeyAlgo("ecdsa"),
560+
certificate.WithKeySize(256),
561+
certificate.WithCAExpiry(tenYears))
562+
assert.NoError(t, err)
563+
564+
values := mock.NewOutputPatchableValuesCollectorMock(t)
565+
566+
values.GetMock.When("global.discovery.clusterDomain").Then(gjson.Result{Type: gjson.String, Str: "cluster.local"})
567+
values.GetMock.When("global.modules.publicDomainTemplate").Then(gjson.Result{Type: gjson.String, Str: "%s.127.0.0.1.sslip.io"})
568+
569+
// CA is stored at custom field name "cert" instead of default "crt"
570+
values.GetOkMock.When("global.internal.modules.kubeRBACProxyCA.cert").Then(gjson.Result{Type: gjson.String, Str: string(ca.Cert)}, true)
571+
values.GetOkMock.When("global.internal.modules.kubeRBACProxyCA.key").Then(gjson.Result{Type: gjson.String, Str: string(ca.Key)}, true)
572+
573+
values.SetMock.Set(func(path string, v any) {
574+
assert.Equal(t, "d8-example-module.internal.kubeRBACProxyCert", path)
575+
576+
vals, ok := v.(tlscertificate.CertValues)
577+
assert.True(t, ok)
578+
579+
assert.NotEmpty(t, vals.CA)
580+
assert.NotEmpty(t, vals.Crt)
581+
assert.NotEmpty(t, vals.Key)
582+
583+
parsedCert, err := certificate.ParseCertificate([]byte(vals.Crt))
584+
assert.NoError(t, err)
585+
assert.Equal(t, parsedCert.Issuer.CommonName, "cert-name")
586+
})
587+
588+
var input = &pkg.HookInput{
589+
Snapshots: snapshots,
590+
Values: values,
591+
DC: dc,
592+
Logger: log.NewNop(),
593+
}
594+
595+
config := tlscertificate.GenSelfSignedTLSHookConf{
596+
CN: "cert-name",
597+
TLSSecretName: "secret-kube-rbac-proxy-cert",
598+
Namespace: "some-namespace",
599+
SANs: tlscertificate.DefaultSANs([]string{"example-svc"}),
600+
FullValuesPathPrefix: "d8-example-module.internal.kubeRBACProxyCert",
601+
CommonCAValuesPath: "global.internal.modules.kubeRBACProxyCA",
602+
CommonCACertField: "cert",
603+
}
604+
605+
err = tlscertificate.GenSelfSignedTLS(config)(context.Background(), input)
606+
assert.NoError(t, err)
607+
})
608+
551609
t.Run("wrong certificate expiry duration in snapshot", func(t *testing.T) {
552610
dc := mock.NewDependencyContainerMock(t)
553611

0 commit comments

Comments
 (0)