1 package kclient
2
3 import (
4 "bytes"
5 "context"
6 "crypto/rand"
7 "crypto/rsa"
8 "crypto/x509"
9 "crypto/x509/pkix"
10 "encoding/pem"
11 "fmt"
12 "math/big"
13 "strings"
14 "time"
15
16 "k8s.io/apimachinery/pkg/fields"
17 "k8s.io/klog"
18
19 corev1 "k8s.io/api/core/v1"
20 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21 )
22
23
24 const ComponentPortAnnotationName = "component-port"
25
26 var SecretGVK = corev1.SchemeGroupVersion.WithKind("Secret")
27
28
29
30
31 func (c *Client) CreateTLSSecret(tlsCertificate []byte, tlsPrivKey []byte, objectMeta metav1.ObjectMeta) (*corev1.Secret, error) {
32 if objectMeta.Name == "" {
33 return nil, fmt.Errorf("tlsSecret name is empty")
34 }
35 data := make(map[string][]byte)
36 data["tls.crt"] = tlsCertificate
37 data["tls.key"] = tlsPrivKey
38 secretTemplate := corev1.Secret{
39 ObjectMeta: objectMeta,
40 Type: corev1.SecretTypeTLS,
41 Data: data,
42 }
43
44 secret, err := c.KubeClient.CoreV1().Secrets(c.Namespace).Create(context.TODO(), &secretTemplate, metav1.CreateOptions{FieldManager: FieldManager})
45 if err != nil {
46 return nil, fmt.Errorf("unable to create secret %s: %w", objectMeta.Name, err)
47 }
48 return secret, nil
49 }
50
51
52
53
54 type SelfSignedCertificate struct {
55 CertPem []byte
56 KeyPem []byte
57 }
58
59
60 func GenerateSelfSignedCertificate(host string) (SelfSignedCertificate, error) {
61
62 privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
63 if err != nil {
64 return SelfSignedCertificate{}, fmt.Errorf("unable to generate rsa key: %w", err)
65 }
66 template := x509.Certificate{
67 SerialNumber: big.NewInt(time.Now().Unix()),
68 Subject: pkix.Name{
69 CommonName: "Odo self-signed certificate",
70 Organization: []string{"Odo"},
71 },
72 NotBefore: time.Now(),
73 NotAfter: time.Now().Add(time.Hour * 24 * 365 * 10),
74 KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
75 BasicConstraintsValid: true,
76 DNSNames: []string{"*." + host},
77 }
78
79 certificateDerEncoding, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
80 if err != nil {
81 return SelfSignedCertificate{}, fmt.Errorf("unable to create certificate: %w", err)
82 }
83 out := &bytes.Buffer{}
84 err = pem.Encode(out, &pem.Block{Type: "CERTIFICATE", Bytes: certificateDerEncoding})
85 if err != nil {
86 return SelfSignedCertificate{}, fmt.Errorf("unable to encode certificate: %w", err)
87 }
88 certPemEncode := out.String()
89 certPemByteArr := []byte(certPemEncode)
90
91 tlsPrivKeyEncoding := x509.MarshalPKCS1PrivateKey(privateKey)
92 err = pem.Encode(out, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: tlsPrivKeyEncoding})
93 if err != nil {
94 return SelfSignedCertificate{}, fmt.Errorf("unable to encode rsa private key: %w", err)
95 }
96 keyPemEncode := out.String()
97 keyPemByteArr := []byte(keyPemEncode)
98
99 return SelfSignedCertificate{CertPem: certPemByteArr, KeyPem: keyPemByteArr}, nil
100 }
101
102
103 func (c *Client) GetSecret(name, namespace string) (*corev1.Secret, error) {
104 secret, err := c.KubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{})
105 if err != nil {
106 return nil, fmt.Errorf("unable to get the secret %s: %w", secret, err)
107 }
108 return secret, nil
109 }
110
111
112 func (c *Client) UpdateSecret(secret *corev1.Secret, namespace string) (*corev1.Secret, error) {
113 secret, err := c.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
114 if err != nil {
115 return nil, fmt.Errorf("unable to update the secret %s: %w", secret, err)
116 }
117 return secret, nil
118 }
119
120
121 func (c *Client) DeleteSecret(secretName, namespace string) error {
122 err := c.KubeClient.CoreV1().Secrets(namespace).Delete(context.TODO(), secretName, metav1.DeleteOptions{})
123 if err != nil {
124 return fmt.Errorf("unable to delete the secret %s: %w", secretName, err)
125 }
126 return nil
127 }
128
129
130
131 func (c *Client) CreateSecret(objectMeta metav1.ObjectMeta, data map[string]string, ownerReference metav1.OwnerReference) error {
132
133 secret := corev1.Secret{
134 ObjectMeta: objectMeta,
135 Type: corev1.SecretTypeOpaque,
136 StringData: data,
137 }
138 secret.SetOwnerReferences(append(secret.GetOwnerReferences(), ownerReference))
139 _, err := c.KubeClient.CoreV1().Secrets(c.Namespace).Create(context.TODO(), &secret, metav1.CreateOptions{FieldManager: FieldManager})
140 if err != nil {
141 return fmt.Errorf("unable to create secret for %s: %w", objectMeta.Name, err)
142 }
143 return nil
144 }
145
146
147
148
149 func (c *Client) CreateSecrets(componentName string, commonObjectMeta metav1.ObjectMeta, svc *corev1.Service, ownerReference metav1.OwnerReference) error {
150 originalName := commonObjectMeta.Name
151 for _, svcPort := range svc.Spec.Ports {
152 portAsString := fmt.Sprintf("%v", svcPort.Port)
153
154
155
156 commonObjectMeta.Name = fmt.Sprintf("%v-%v", originalName, portAsString)
157
158
159
160
161 commonObjectMeta.Annotations[ComponentPortAnnotationName] = portAsString
162
163 err := c.CreateSecret(
164 commonObjectMeta,
165 map[string]string{
166 secretKeyName(componentName, "host"): svc.Name,
167 secretKeyName(componentName, "port"): portAsString,
168 },
169 ownerReference)
170
171 if err != nil {
172 return fmt.Errorf("unable to create Secret for %s: %w", commonObjectMeta.Name, err)
173 }
174 }
175
176
177 commonObjectMeta.Name = originalName
178 delete(commonObjectMeta.Annotations, ComponentPortAnnotationName)
179
180 return nil
181 }
182
183
184 func (c *Client) ListSecrets(labelSelector string) ([]corev1.Secret, error) {
185 listOptions := metav1.ListOptions{}
186 if len(labelSelector) > 0 {
187 listOptions = metav1.ListOptions{
188 LabelSelector: labelSelector,
189 }
190 }
191
192 secretList, err := c.KubeClient.CoreV1().Secrets(c.Namespace).List(context.TODO(), listOptions)
193 if err != nil {
194 return nil, fmt.Errorf("unable to get secret list: %w", err)
195 }
196
197 return secretList.Items, nil
198 }
199
200
201 func (c *Client) WaitAndGetSecret(name string, namespace string) (*corev1.Secret, error) {
202 klog.V(3).Infof("Waiting for secret %s to become available", name)
203
204 w, err := c.KubeClient.CoreV1().Secrets(namespace).Watch(context.TODO(), metav1.ListOptions{
205 FieldSelector: fields.Set{"metadata.name": name}.AsSelector().String(),
206 })
207 if err != nil {
208 return nil, fmt.Errorf("unable to watch secret: %w", err)
209 }
210 defer w.Stop()
211 for {
212 val, ok := <-w.ResultChan()
213 if !ok {
214 break
215 }
216 if e, ok := val.Object.(*corev1.Secret); ok {
217 klog.V(3).Infof("Secret %s now exists", e.Name)
218 return e, nil
219 }
220 }
221 return nil, fmt.Errorf("unknown error while waiting for secret '%s'", name)
222 }
223
224 func secretKeyName(componentName, baseKeyName string) string {
225 return fmt.Sprintf("COMPONENT_%v_%v", strings.Replace(strings.ToUpper(componentName), "-", "_", -1), strings.ToUpper(baseKeyName))
226 }
227
View as plain text