1 package externalsecrets
2
3 import (
4 "errors"
5 "fmt"
6 "time"
7
8 goext "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
9 corev1 "k8s.io/api/core/v1"
10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11 "sigs.k8s.io/kustomize/kyaml/kio/kioutil"
12
13 "edge-infra.dev/pkg/edge/constants"
14 workloads "edge-infra.dev/pkg/edge/constants/api/workload"
15 )
16
17 const (
18 SecretName = "gcp-creds"
19 SecretNamespace = "external-secrets"
20 SecretKey = "key.json"
21
22 gcpProvider = "gcp-provider"
23 clusterSecretStore = "ClusterSecretStore"
24 DockerPullSecretType = "docker-registry"
25 )
26
27 var (
28 defaultInterval = time.Minute
29 ErrNoName = errors.New("external secret name must be set")
30 ErrNoNamespace = errors.New("external secret namespace or namespace selector must be set")
31 ErrNameSpaceConflict = errors.New("cannot set both namesapce and namesapce selector for an external secret")
32 ErrNoPath = errors.New("external secret path must be set")
33 ErrNoProjectID = errors.New("external secret projectID must be set")
34 )
35
36
37 type ExternalSecret struct {
38 name string
39 namespace string
40 secretStoreKind string
41 secretStoreName string
42 path string
43 k8sSecretName string
44 projectID string
45 template *goext.ExternalSecretTemplate
46 dataFieldMap map[string]map[string]string
47 dataMap map[string]string
48 refreshInterval time.Duration
49 creationPolicy goext.ExternalSecretCreationPolicy
50 labels map[string]string
51 }
52
53 func DefaultExternalSecret() *ExternalSecret {
54 return &ExternalSecret{
55 dataMap: map[string]string{},
56 dataFieldMap: map[string]map[string]string{},
57 secretStoreKind: clusterSecretStore,
58 secretStoreName: gcpProvider,
59 refreshInterval: defaultInterval,
60 creationPolicy: goext.CreatePolicyOwner,
61 }
62 }
63
64
65
66
67 func (p *ExternalSecret) DockerConfig(secretName, field string) *ExternalSecret {
68 templateString := fmt.Sprintf("{{ .%s }}", field)
69 p.template = &goext.ExternalSecretTemplate{
70 EngineVersion: goext.TemplateEngineV2,
71 Type: corev1.SecretTypeDockerConfigJson,
72 Data: map[string]string{".dockerconfigjson": templateString},
73 }
74
75 return p.MapSecretFieldToK8sSecretKey(secretName, field, field)
76 }
77
78 func (p *ExternalSecret) SetSecretType(secretType corev1.SecretType) *ExternalSecret {
79 p.template = &goext.ExternalSecretTemplate{
80 Type: secretType,
81 }
82 return p
83 }
84
85 func (p *ExternalSecret) Namespace(ns string) *ExternalSecret {
86 p.namespace = ns
87 return p
88 }
89
90 func (p *ExternalSecret) Name(name string) *ExternalSecret {
91 p.name = name
92 return p
93 }
94
95 func (p *ExternalSecret) Path(path string) *ExternalSecret {
96 p.path = path
97 return p
98 }
99
100 func (p *ExternalSecret) K8sSecretName(k8sSecretName string) *ExternalSecret {
101 p.k8sSecretName = k8sSecretName
102 return p
103 }
104
105 func (p *ExternalSecret) ProjectID(projectID string) *ExternalSecret {
106 p.projectID = projectID
107 return p
108 }
109
110 func (p *ExternalSecret) Labels(labels map[string]string) *ExternalSecret {
111 if labels == nil {
112 p.labels = map[string]string{}
113 return p
114 }
115 p.labels = labels
116 return p
117 }
118
119 func (p *ExternalSecret) MapSecretFieldToK8sSecretKey(secretManagerSecretName, secretManagerField, k8sSecretKey string) *ExternalSecret {
120 if secretManagerSecret, ok := p.dataFieldMap[secretManagerSecretName]; ok {
121 secretManagerSecret[secretManagerField] = k8sSecretKey
122 } else {
123 p.dataFieldMap[secretManagerSecretName] = map[string]string{secretManagerField: k8sSecretKey}
124 }
125 return p
126 }
127
128
129 func (p *ExternalSecret) MapSecretToK8sSecretKey(secretManagerSecretName, k8sSecretKey string) *ExternalSecret {
130 p.dataMap[secretManagerSecretName] = k8sSecretKey
131 return p
132 }
133
134 func (p *ExternalSecret) Validate() error {
135 if p.name == "" {
136 return ErrNoName
137 }
138 if p.k8sSecretName == "" {
139 p.k8sSecretName = p.name
140 }
141 if p.projectID == "" {
142 return ErrNoProjectID
143 }
144 return nil
145 }
146
147 func (p *ExternalSecret) BuildClusterExternalSecret() (*goext.ClusterExternalSecret, error) {
148 err := p.Validate()
149 if err != nil {
150 return nil, err
151 }
152 matchLabels := []string{"tenant"}
153 es := &goext.ClusterExternalSecret{
154 TypeMeta: metav1.TypeMeta{
155 APIVersion: goext.ExtSecretGroupVersionKind.GroupVersion().String(),
156 Kind: goext.ClusterExtSecretGroupVersionKind.Kind,
157 },
158 ObjectMeta: metav1.ObjectMeta{
159 Name: p.name,
160 Labels: mergeStringMaps(p.labels, map[string]string{
161 constants.Tenant: p.projectID,
162 }),
163 Annotations: map[string]string{
164
165 kioutil.PathAnnotation: p.path,
166 },
167 },
168 Spec: goext.ClusterExternalSecretSpec{
169 ExternalSecretName: p.k8sSecretName,
170 ExternalSecretSpec: goext.ExternalSecretSpec{
171 SecretStoreRef: goext.SecretStoreRef{
172 Name: p.secretStoreName,
173 Kind: p.secretStoreKind,
174 },
175 Target: goext.ExternalSecretTarget{
176 Name: p.k8sSecretName,
177 CreationPolicy: p.creationPolicy,
178 },
179 RefreshInterval: &metav1.Duration{
180 Duration: p.refreshInterval,
181 },
182 },
183 NamespaceSelectors: []*metav1.LabelSelector{
184 {
185 MatchExpressions: []metav1.LabelSelectorRequirement{
186 {Key: workloads.Label, Operator: metav1.LabelSelectorOpIn, Values: matchLabels},
187 },
188 },
189 },
190 },
191 }
192 var externalSecretData []goext.ExternalSecretData
193 for secretManagerSecretName, k8sSecretKey := range p.dataMap {
194 externalSecretData = append(externalSecretData, goext.ExternalSecretData{RemoteRef: goext.ExternalSecretDataRemoteRef{Key: secretManagerSecretName}, SecretKey: k8sSecretKey})
195 }
196 for secretManagerSecretName, secretManagerFieldToKeyMap := range p.dataFieldMap {
197 for secretManagerSecretField, k8sSecretKey := range secretManagerFieldToKeyMap {
198 externalSecretData = append(externalSecretData, goext.ExternalSecretData{RemoteRef: goext.ExternalSecretDataRemoteRef{Key: secretManagerSecretName, Property: secretManagerSecretField}, SecretKey: k8sSecretKey})
199 }
200 }
201 es.Spec.ExternalSecretSpec.Data = externalSecretData
202 es.Spec.ExternalSecretSpec.Target.Template = p.template
203 if p.namespace != "" {
204 es.ObjectMeta.Namespace = p.namespace
205 }
206
207 return es, nil
208 }
209
210 func (p *ExternalSecret) Build() (*goext.ExternalSecret, error) {
211 err := p.Validate()
212 if err != nil {
213 return nil, err
214 }
215 es := &goext.ExternalSecret{
216 TypeMeta: metav1.TypeMeta{
217 APIVersion: goext.ExtSecretGroupVersionKind.GroupVersion().String(),
218 Kind: goext.ExtSecretGroupVersionKind.Kind,
219 },
220 ObjectMeta: metav1.ObjectMeta{
221 Name: p.name,
222 Labels: mergeStringMaps(p.labels, map[string]string{
223 constants.Tenant: p.projectID,
224 }),
225 Annotations: map[string]string{
226
227 kioutil.PathAnnotation: p.path,
228 },
229 },
230 Spec: goext.ExternalSecretSpec{
231 SecretStoreRef: goext.SecretStoreRef{
232 Name: p.secretStoreName,
233 Kind: p.secretStoreKind,
234 },
235 Target: goext.ExternalSecretTarget{
236 Name: p.k8sSecretName,
237 CreationPolicy: p.creationPolicy,
238 },
239 RefreshInterval: &metav1.Duration{
240 Duration: p.refreshInterval,
241 },
242 },
243 }
244 var externalSecretData []goext.ExternalSecretData
245 for secretManagerSecretName, k8sSecretKey := range p.dataMap {
246 externalSecretData = append(externalSecretData, goext.ExternalSecretData{RemoteRef: goext.ExternalSecretDataRemoteRef{Key: secretManagerSecretName}, SecretKey: k8sSecretKey})
247 }
248 for secretManagerSecretName, secretManagerFieldToKeyMap := range p.dataFieldMap {
249 for secretManagerSecretField, k8sSecretKey := range secretManagerFieldToKeyMap {
250 externalSecretData = append(externalSecretData, goext.ExternalSecretData{RemoteRef: goext.ExternalSecretDataRemoteRef{Key: secretManagerSecretName, Property: secretManagerSecretField}, SecretKey: k8sSecretKey})
251 }
252 }
253 es.Spec.Data = externalSecretData
254 es.Spec.Target.Template = p.template
255 if p.namespace != "" {
256 es.ObjectMeta.Namespace = p.namespace
257 }
258 return es, nil
259 }
260
261
262 func mergeStringMaps(mapOne, mapTwo map[string]string) map[string]string {
263 for k, v := range mapOne {
264 mapTwo[k] = v
265 }
266 return mapTwo
267 }
268
View as plain text