Skip to content

Commit e5235b1

Browse files
committed
pkg/tlsutil: implement the case ca and key are in cache
1 parent 92a82a7 commit e5235b1

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed

pkg/tlsutil/tls.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@
1515
package tlsutil
1616

1717
import (
18+
"crypto/rsa"
19+
"crypto/x509"
20+
"errors"
21+
"strings"
22+
"sync"
23+
1824
"k8s.io/api/core/v1"
25+
"k8s.io/apimachinery/pkg/api/meta"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1927
"k8s.io/apimachinery/pkg/runtime"
2028
)
2129

@@ -111,3 +119,135 @@ type CertGenerator interface {
111119
// ca.key: ..
112120
GenerateCert(cr runtime.Object, service *v1.Service, config *CertConfig) (*v1.Secret, *v1.ConfigMap, *v1.Secret, error)
113121
}
122+
123+
const (
124+
// TLSPrivateCAKeyKey is the key for the private CA key field.
125+
TLSPrivateCAKeyKey = "ca.key"
126+
// TLSCertKey is the key for tls CA certificates.
127+
TLSCACertKey = "ca.crt"
128+
)
129+
130+
type SDKCertGenerator struct {
131+
// appKeyAndCertMap holds the application key and cert for a given cr + config.CertName.
132+
appKeyAndCertMap sync.Map
133+
// caKeyAndCertMap holds the CA key and cert for a given cr.
134+
caKeyAndCertMap sync.Map
135+
}
136+
137+
type keyAndCert struct {
138+
key *rsa.PrivateKey
139+
cert *x509.Certificate
140+
}
141+
142+
func (scg *SDKCertGenerator) GenerateCert(cr runtime.Object, service *v1.Service, config *CertConfig) (*v1.Secret, *v1.ConfigMap, *v1.Secret, error) {
143+
if err := verifyConfig(config); err != nil {
144+
return nil, nil, nil, err
145+
}
146+
147+
n, k, ns, err := toKindNameNamespace(cr)
148+
if err != nil {
149+
return nil, nil, nil, err
150+
}
151+
152+
asn := toAppSecretName(k, n, config.CertName)
153+
cascn := toCASecretAndConfigMapName(k, n)
154+
appkcv, hasAppKeyAndCert := scg.appKeyAndCertMap.Load(asn + "-" + ns)
155+
cakcv, hasCAKeyAndCert := scg.caKeyAndCertMap.Load(cascn + "-" + ns)
156+
// TODO: handle passed in CA
157+
if hasAppKeyAndCert && hasCAKeyAndCert {
158+
s := toTLSSecret(appkcv.(*keyAndCert), asn, ns)
159+
cacm, cas := toCASecretAndConfigmap(cakcv.(*keyAndCert), cascn, ns)
160+
return s, cacm, cas, nil
161+
} else if hasAppKeyAndCert && !hasCAKeyAndCert {
162+
// TODO
163+
} else if !hasAppKeyAndCert && hasCAKeyAndCert {
164+
// TODO
165+
} else {
166+
// TODO
167+
}
168+
return nil, nil, nil, nil
169+
}
170+
171+
func verifyConfig(config *CertConfig) error {
172+
if config == nil {
173+
return errors.New("nil CertConfig not allowed")
174+
}
175+
if config.CertName == "" {
176+
return errors.New("empty CertConfig.CertName not allowed")
177+
}
178+
return nil
179+
}
180+
181+
func toAppSecretName(kind, name, certName string) string {
182+
return strings.ToLower(kind) + "-" + name + "-" + certName
183+
}
184+
185+
func toCASecretAndConfigMapName(kind, name string) string {
186+
return strings.ToLower(kind) + "-" + name + "-ca"
187+
}
188+
189+
func toKindNameNamespace(cr runtime.Object) (string, string, string, error) {
190+
a := meta.NewAccessor()
191+
k, err := a.Kind(cr)
192+
if err != nil {
193+
return "", "", "", err
194+
}
195+
n, err := a.Name(cr)
196+
if err != nil {
197+
return "", "", "", err
198+
}
199+
ns, err := a.Namespace(cr)
200+
if err != nil {
201+
return "", "", "", err
202+
}
203+
return k, n, ns, nil
204+
}
205+
206+
// toTLSSecret returns a client/server "kubernetes.io/tls" secret.
207+
// TODO: add owner ref.
208+
func toTLSSecret(kc *keyAndCert, name, namespace string) *v1.Secret {
209+
return &v1.Secret{
210+
TypeMeta: metav1.TypeMeta{
211+
Kind: "Secret",
212+
APIVersion: "v1",
213+
},
214+
ObjectMeta: metav1.ObjectMeta{
215+
Name: name,
216+
Namespace: namespace,
217+
},
218+
Data: map[string][]byte{
219+
v1.TLSPrivateKeyKey: encodePrivateKeyPEM(kc.key),
220+
v1.TLSCertKey: encodeCertificatePEM(kc.cert),
221+
},
222+
Type: v1.SecretTypeTLS,
223+
}
224+
}
225+
226+
// TODO: add owner ref.
227+
func toCASecretAndConfigmap(cakc *keyAndCert, name, namespace string) (*v1.ConfigMap, *v1.Secret) {
228+
return &v1.ConfigMap{
229+
TypeMeta: metav1.TypeMeta{
230+
Kind: "ConfigMap",
231+
APIVersion: "v1",
232+
},
233+
ObjectMeta: metav1.ObjectMeta{
234+
Name: name,
235+
Namespace: namespace,
236+
},
237+
Data: map[string]string{
238+
TLSCACertKey: string(encodeCertificatePEM(cakc.cert)),
239+
},
240+
}, &v1.Secret{
241+
TypeMeta: metav1.TypeMeta{
242+
Kind: "Secret",
243+
APIVersion: "v1",
244+
},
245+
ObjectMeta: metav1.ObjectMeta{
246+
Name: name,
247+
Namespace: namespace,
248+
},
249+
Data: map[string][]byte{
250+
TLSPrivateCAKeyKey: encodePrivateKeyPEM(cakc.key),
251+
},
252+
}
253+
}

0 commit comments

Comments
 (0)