Skip to content

Commit 8b85f01

Browse files
committed
add ceritficate bundle abstraction
1 parent d8772d3 commit 8b85f01

File tree

3 files changed

+78
-33
lines changed

3 files changed

+78
-33
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package graph
2+
3+
import (
4+
"crypto/tls"
5+
"crypto/x509"
6+
"encoding/base64"
7+
"encoding/pem"
8+
"fmt"
9+
10+
"k8s.io/apimachinery/pkg/types"
11+
v1 "sigs.k8s.io/gateway-api/apis/v1"
12+
)
13+
14+
const CAKey = "ca.crt"
15+
16+
type CertificateBundle struct {
17+
Name types.NamespacedName
18+
Kind v1.Kind
19+
20+
// Required ...
21+
TLSCert []byte
22+
TLSPrivateKey []byte
23+
24+
// Optional
25+
CACert []byte
26+
}
27+
28+
func (cb *CertificateBundle) validate() error {
29+
_, err := tls.X509KeyPair(cb.TLSCert, cb.TLSPrivateKey)
30+
if err != nil {
31+
return fmt.Errorf("TLS secret is invalid: %w", err)
32+
}
33+
34+
if err = validateCA(cb.CACert); len(cb.CACert) >= 1 && err != nil {
35+
return fmt.Errorf("Certificate in secret is invalid: %w", err)
36+
}
37+
38+
return nil
39+
}
40+
41+
// validateCA validates the ca.crt entry in the ConfigMap. If it is valid, the function returns nil.
42+
func validateCA(caData []byte) error {
43+
data := make([]byte, base64.StdEncoding.DecodedLen(len(caData)))
44+
_, err := base64.StdEncoding.Decode(data, caData)
45+
if err != nil {
46+
data = caData
47+
}
48+
block, _ := pem.Decode(data)
49+
if block == nil {
50+
return fmt.Errorf("the data field %s must hold a valid CERTIFICATE PEM block", CAKey)
51+
}
52+
if block.Type != "CERTIFICATE" {
53+
return fmt.Errorf("the data field %s must hold a valid CERTIFICATE PEM block, but got '%s'", CAKey, block.Type)
54+
}
55+
56+
_, err = x509.ParseCertificate(block.Bytes)
57+
if err != nil {
58+
return fmt.Errorf("failed to validate certificate: %w", err)
59+
}
60+
61+
return nil
62+
}

internal/mode/static/state/graph/configmaps.go

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
package graph
22

33
import (
4-
"crypto/x509"
5-
"encoding/base64"
6-
"encoding/pem"
74
"errors"
85
"fmt"
96

107
apiv1 "k8s.io/api/core/v1"
118
"k8s.io/apimachinery/pkg/types"
129
)
1310

14-
const CAKey = "ca.crt"
15-
1611
// CaCertConfigMap represents a ConfigMap resource that holds CA Cert data.
1712
type CaCertConfigMap struct {
1813
// Source holds the actual ConfigMap resource. Can be nil if the ConfigMap does not exist.
@@ -97,26 +92,3 @@ func (r *configMapResolver) getResolvedConfigMaps() map[types.NamespacedName]*Ca
9792

9893
return resolved
9994
}
100-
101-
// validateCA validates the ca.crt entry in the ConfigMap. If it is valid, the function returns nil.
102-
func validateCA(caData []byte) error {
103-
data := make([]byte, base64.StdEncoding.DecodedLen(len(caData)))
104-
_, err := base64.StdEncoding.Decode(data, caData)
105-
if err != nil {
106-
data = caData
107-
}
108-
block, _ := pem.Decode(data)
109-
if block == nil {
110-
return fmt.Errorf("the data field %s must hold a valid CERTIFICATE PEM block", CAKey)
111-
}
112-
if block.Type != "CERTIFICATE" {
113-
return fmt.Errorf("the data field %s must hold a valid CERTIFICATE PEM block, but got '%s'", CAKey, block.Type)
114-
}
115-
116-
_, err = x509.ParseCertificate(block.Bytes)
117-
if err != nil {
118-
return fmt.Errorf("failed to validate certificate: %w", err)
119-
}
120-
121-
return nil
122-
}

internal/mode/static/state/graph/secret.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package graph
22

33
import (
4-
"crypto/tls"
54
"errors"
65
"fmt"
76

@@ -13,6 +12,9 @@ import (
1312
type Secret struct {
1413
// Source holds the actual Secret resource. Can be nil if the Secret does not exist.
1514
Source *apiv1.Secret
15+
16+
// CertBundle holds actual certificate data.
17+
CertBundle *CertificateBundle
1618
}
1719

1820
type secretEntry struct {
@@ -43,6 +45,7 @@ func (r *secretResolver) resolve(nsname types.NamespacedName) error {
4345
secret, exist := r.clusterSecrets[nsname]
4446

4547
var validationErr error
48+
var certBundle *CertificateBundle
4649

4750
switch {
4851
case !exist:
@@ -53,15 +56,23 @@ func (r *secretResolver) resolve(nsname types.NamespacedName) error {
5356

5457
default:
5558
// A TLS Secret is guaranteed to have these data fields.
56-
_, err := tls.X509KeyPair(secret.Data[apiv1.TLSCertKey], secret.Data[apiv1.TLSPrivateKeyKey])
57-
if err != nil {
58-
validationErr = fmt.Errorf("TLS secret is invalid: %w", err)
59+
certBundle = &CertificateBundle{
60+
TLSCert: secret.Data[apiv1.TLSCertKey],
61+
TLSPrivateKey: secret.Data[apiv1.TLSPrivateKeyKey],
62+
}
63+
64+
// Not always guaranteed to have a ca certificate in the secret.
65+
if _, exists := secret.Data[CAKey]; exists {
66+
certBundle.CACert = secret.Data[CAKey]
5967
}
68+
69+
validationErr = certBundle.validate()
6070
}
6171

6272
r.resolvedSecrets[nsname] = &secretEntry{
6373
Secret: Secret{
64-
Source: secret,
74+
Source: secret,
75+
CertBundle: certBundle,
6576
},
6677
err: validationErr,
6778
}

0 commit comments

Comments
 (0)