/
store.go
138 lines (117 loc) · 3.33 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package secret
import (
"context"
"io/ioutil"
"os"
"path/filepath"
"github.com/loft-sh/jspolicy/pkg/util/certhelper"
"github.com/loft-sh/jspolicy/pkg/util/clienthelper"
"github.com/pkg/errors"
"k8s.io/klog"
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
// WebhookCertSecretName is the name of the js policy webhook certificate
WebhookCertSecretName = "jspolicy-webhook-cert"
)
func EnsureCertSecrets(ctx context.Context, client client.Client) error {
// get current namespace
namespace, err := clienthelper.CurrentNamespace()
if err != nil {
return err
}
// make sure the namespace exists
err = client.Create(ctx, &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
})
if err != nil && kerrors.IsAlreadyExists(err) == false {
return err
}
// ensure webhook secret
err = ensureSecret(ctx, client, namespace, WebhookCertSecretName, certhelper.WebhookCertFolder, certhelper.GenerateWebhookCertificate)
if err != nil {
return errors.Wrap(err, "ensure webhook cert")
}
return nil
}
func ensureSecret(ctx context.Context, client client.Client, namespace string, certSecretName string, certFolder string, createCert func() error) error {
secret := &corev1.Secret{}
err := client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: certSecretName}, secret)
if err != nil {
if kerrors.IsNotFound(err) == false {
return err
}
// Fallthrough
} else if isSecretValid(secret) {
return getDataFromSecret(secret, certFolder)
} else {
err = client.Delete(ctx, secret)
if err != nil {
return err
}
}
// create a new secret
err = createCert()
if err != nil {
return err
}
// read the data
data := map[string][]byte{}
for _, file := range []string{"ca.crt", "tls.crt", "tls.key"} {
out, err := ioutil.ReadFile(filepath.Join(certFolder, file))
if err != nil {
return err
}
data[file] = out
}
// create secret
secret = &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: certSecretName,
Namespace: namespace,
},
Data: data,
Type: corev1.SecretTypeTLS,
}
err = client.Create(ctx, secret)
if err != nil {
// someone was faster here, this can happen if we run with leader election on
// and another instance created the secret faster than we did, in this case
// we just retrieve the secret again and continue
if kerrors.IsAlreadyExists(err) {
klog.Infof("secret %s/%s already exists, will retry to get the data from it", namespace, certSecretName)
return ensureSecret(ctx, client, namespace, certSecretName, certFolder, createCert)
}
return err
}
return nil
}
func getDataFromSecret(secret *corev1.Secret, certFolder string) error {
err := os.MkdirAll(certFolder, 0755)
if err != nil {
return err
}
for _, file := range []string{"ca.crt", "tls.crt", "tls.key"} {
err := ioutil.WriteFile(filepath.Join(certFolder, file), secret.Data[file], 0666)
if err != nil {
return err
}
}
return nil
}
func isSecretValid(secret *corev1.Secret) bool {
if secret.Data == nil {
return false
} else if secret.Type != corev1.SecretTypeTLS {
return false
} else if secret.Data["ca.crt"] == nil || secret.Data["tls.crt"] == nil || secret.Data["tls.key"] == nil {
return false
}
return true
}