This repository was archived by the owner on Jan 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkubernetes.go
152 lines (123 loc) · 3.55 KB
/
kubernetes.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package secrets
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"regexp"
"strings"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
var _ SecretStorage = &KubernetesSecretProvider{}
type KubernetesSecretProvider struct {
KubernetesConfig
client *kubernetes.Clientset
}
type KubernetesConfig struct {
Namespace string
}
func NewKubernetesConfig() KubernetesConfig {
return KubernetesConfig{
Namespace: getDefaultNamespace(),
}
}
func NewKubernetesSecretProviderFromConfig(cfg KubernetesConfig) (*KubernetesSecretProvider, error) {
k8sConfig, err := rest.InClusterConfig()
if err != nil {
return nil, fmt.Errorf("getting in-cluster config: %w", err)
}
clientset, err := kubernetes.NewForConfig(k8sConfig)
if err != nil {
return nil, fmt.Errorf("creating k8s config: %w", err)
}
return &KubernetesSecretProvider{
KubernetesConfig: cfg,
client: clientset,
}, nil
}
func NewKubernetesSecretProvider(client *kubernetes.Clientset, namespace string) *KubernetesSecretProvider {
return &KubernetesSecretProvider{
KubernetesConfig: KubernetesConfig{
Namespace: namespace,
},
client: client,
}
}
var kubernetesInvalidKeyCharacters = regexp.MustCompile(`[^-._a-zA-Z0-9/]`)
// Use secrets when you don't want to store the underlying data, eg secret tokens
func (k *KubernetesSecretProvider) SetSecret(name string, secret []byte) error {
name = kubernetesInvalidKeyCharacters.ReplaceAllLiteralString(name, "_")
secretParts := strings.Split(name, "/")
if len(secretParts) != 2 {
return fmt.Errorf("invalid Kubernetes secret path specified, expected exactly 2 parts but was %d", len(secretParts))
}
objName := secretParts[0]
// key must match [-._a-zA-Z0-9]+
key := secretParts[1]
data := map[string][]byte{}
data[key] = secret
patch := v1.Secret{
Data: data,
}
d, err := json.Marshal(patch)
if err != nil {
return err
}
_, err = k.client.CoreV1().Secrets(k.Namespace).Patch(
context.TODO(),
objName,
types.StrategicMergePatchType,
d,
metav1.PatchOptions{},
)
if err != nil && strings.Contains(err.Error(), "not found") {
_, err = k.client.CoreV1().Secrets(k.Namespace).Create(context.TODO(), &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: objName,
},
Data: data,
}, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("k8s: creating secret: %w", err)
}
} else if err != nil {
return fmt.Errorf("k8s: patching secret: %w", err)
}
return nil
}
func (k *KubernetesSecretProvider) GetSecret(name string) (secret []byte, err error) {
name = kubernetesInvalidKeyCharacters.ReplaceAllLiteralString(name, "_")
secretParts := strings.Split(name, "/")
if len(secretParts) != 2 {
return nil, fmt.Errorf("invalid Kubernetes secret path specified, expected exactly 2 parts but was %d", len(secretParts))
}
objName := secretParts[0]
key := secretParts[1]
retrieved, err := k.client.CoreV1().Secrets(k.Namespace).Get(context.TODO(), objName, metav1.GetOptions{})
if err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, ErrNotFound
}
return nil, err
}
secretVal, ok := retrieved.Data[key]
if !ok {
return nil, ErrNotFound
}
return secretVal, nil
}
var defaultInstallNamespace = "default"
func getDefaultNamespace() string {
contents, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if err != nil {
return defaultInstallNamespace
}
if len(contents) > 0 {
return string(contents)
}
return defaultInstallNamespace
}