1
16
17 package providerctl
18
19 import (
20 "bytes"
21 "context"
22 "fmt"
23 "os"
24 "path/filepath"
25 "reflect"
26 "sort"
27 "strconv"
28 "strings"
29 "time"
30
31 "github.com/fluxcd/pkg/ssa"
32 "github.com/go-logr/logr"
33 "k8s.io/apimachinery/pkg/api/meta"
34 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
36 "k8s.io/apimachinery/pkg/runtime"
37
38 "sigs.k8s.io/cli-utils/pkg/kstatus/polling"
39 ctrl "sigs.k8s.io/controller-runtime"
40 "sigs.k8s.io/controller-runtime/pkg/client"
41 logger "sigs.k8s.io/controller-runtime/pkg/log"
42
43 "sigs.k8s.io/kustomize/api/hasher"
44 kp "sigs.k8s.io/kustomize/api/provider"
45 "sigs.k8s.io/kustomize/api/resmap"
46 "sigs.k8s.io/kustomize/api/resource"
47 "sigs.k8s.io/kustomize/kyaml/resid"
48
49 apiv1 "k8s.io/api/core/v1"
50
51 "edge-infra.dev/pkg/edge/info"
52 edgeConditions "edge-infra.dev/pkg/k8s/runtime/conditions"
53 "edge-infra.dev/pkg/k8s/runtime/controller/metrics"
54
55 api "edge-infra.dev/pkg/edge/iam/api/v1alpha1"
56 "edge-infra.dev/pkg/edge/iam/config"
57 ff "edge-infra.dev/pkg/lib/featureflag"
58 )
59
60 const (
61 SecretExistCheckFailure = "SecretExistCheckFailure"
62 SecretCreationFailure = "SecretCreationFailure"
63 MissingSecretData = "MissingSecretData"
64 ExternalProvider = "external-provider"
65 ProviderContainer = "edge-iam-provider"
66 DaemonSet = "DaemonSet"
67 Deployment = "Deployment"
68 ClientCRDName = "Client"
69 ClientCRDVersion = "v1alpha1"
70 ClientCRDGroup = "iam.edge-infra.dev"
71 TouchpointProvider = "touchpoint-provider"
72 StoreProvider = "store-provider"
73 TestClient = "test-client"
74 TestClientCRName = "verify"
75 TestClientSecretName = "verify-creds"
76 EncryptionRotationSucceeded = "EncryptionRotationSucceeded"
77 EdgeIAM = "edge-iam"
78 EncryptionKeySecretPrefix = "id-encryption-key-"
79 )
80
81 var envsToSync = [...]string{
82 "IAM_PROFILE_LIFESPAN",
83 "IAM_BARCODE_LIFESPAN",
84 "FF_BARCODE_ENFORCE_ROLES",
85 "FF_ENFORCE_PERMISSIONS",
86 "IAM_PIN_RETRY_THRESHOLD",
87 "IAM_PIN_HISTORY_LENGTH",
88 "IAM_PIN_LIFESPAN",
89 }
90
91
92 type ProviderReconciler struct {
93 client.Client
94 Scheme *runtime.Scheme
95
96
97
98 Name string
99
100
101 Manifests []*unstructured.Unstructured
102
103
104
105 ResourceManager *ssa.ResourceManager
106
107
108 Metrics metrics.Metrics
109
110
111 Resmaps map[string]resmap.ResMap
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 func (r *ProviderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
141 var (
142 reconcileStart = time.Now()
143 log = logger.FromContext(ctx)
144 provider = api.Provider{}
145 )
146
147 log.V(2).Info("reconcile provider")
148
149 defer func() {
150 r.Metrics.RecordReadiness(ctx, &provider)
151 r.Metrics.RecordReconciling(ctx, &provider)
152 r.Metrics.RecordStalled(ctx, &provider)
153 r.Metrics.RecordDuration(ctx, &provider, reconcileStart)
154 }()
155
156
157 r.setResourceManager()
158
159
160
161 err := r.Get(ctx, req.NamespacedName, &provider)
162 if err != nil {
163 return ctrl.Result{}, err
164 }
165
166
167
168 reconciled, reconcileErr := r.reconcile(ctx, req, *provider.DeepCopy())
169
170
171 if err := r.updateStatus(ctx, req, reconciled.Status); err != nil {
172 log.Error(err, "unable to update status")
173 return ctrl.Result{Requeue: true}, nil
174 }
175
176
177
178
179 if reconcileErr != nil {
180 log.Error(reconcileErr, "error reconciling provider resource")
181 return ctrl.Result{Requeue: true}, nil
182 }
183
184
185
186
187 return ctrl.Result{RequeueAfter: 5 * time.Minute}, nil
188 }
189
190
191 func (r *ProviderReconciler) SetupWithManager(mgr ctrl.Manager) error {
192 return ctrl.NewControllerManagedBy(mgr).
193
194 For(&api.Provider{}).
195 Complete(r)
196 }
197
198 func (r *ProviderReconciler) setResourceManager() {
199 if r.ResourceManager == nil {
200 mgr := ssa.NewResourceManager(
201 r.Client,
202
203
204 polling.NewStatusPoller(r.Client, r.Client.RESTMapper(), polling.Options{}), ssa.Owner{Field: r.Name, Group: config.Domain()},
205 )
206 r.ResourceManager = mgr
207 }
208 }
209
210 func (r *ProviderReconciler) reconcile(ctx context.Context, req ctrl.Request, provider api.Provider) (api.Provider, error) {
211 var err error
212
213
214
215
216
217 provider, err = r.reconcileSecrets(ctx, req, provider)
218 if err != nil {
219 return provider, err
220 }
221
222 provider, err = r.reconcileEncryptionKeyRotation(ctx, provider)
223 if err != nil {
224 return provider, err
225 }
226
227 provider, err = r.reconcileTarget(ctx, provider)
228 if err != nil {
229 return provider, err
230 }
231
232
233 if !meta.IsStatusConditionFalse(provider.Status.Conditions, api.ReadyCondition) {
234 return api.Ready(provider, "InstallationSucceeded", "successfully installed the provider"), nil
235 }
236
237 return api.Provider{}, nil
238 }
239
240 func (r *ProviderReconciler) reconcileSecrets(ctx context.Context, req ctrl.Request, provider api.Provider) (api.Provider, error) {
241 var pkSecret, challengeSecret *apiv1.Secret
242 var err error
243
244 log := logger.FromContext(ctx)
245 provider, pkSecret, err = r.reconcilePrivateKeysSecret(ctx, req, provider)
246 if err != nil {
247 return provider, err
248 }
249
250
251 provider, err = r.validatePrivateKeysSecret(provider, pkSecret)
252 if err != nil {
253 log.Error(err, fmt.Sprintf("secret %s/%s is invalid", pkSecret.Name, pkSecret.Namespace))
254 return provider, err
255 }
256
257 provider, challengeSecret, err = r.reconcileChallengeSecret(ctx, req, provider)
258 if err != nil {
259 return provider, err
260 }
261
262
263 provider, err = r.validateChallengeSecret(provider, challengeSecret)
264 if err != nil {
265 log.Error(err, fmt.Sprintf("secret %s/%s is invalid", challengeSecret.Name, challengeSecret.Namespace))
266 return provider, err
267 }
268
269 return provider, nil
270 }
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296 func (r *ProviderReconciler) deleteResource(ctx context.Context, resourceName string, gvk resid.Gvk, resMap resmap.ResMap, provider api.Provider) error {
297 resourceID := resid.ResId{
298 Gvk: gvk,
299 Name: resourceName,
300 Namespace: provider.Namespace,
301 }
302
303 objectToBeDeleted, err := resMap.GetById(resourceID)
304 if err != nil {
305 return err
306 }
307
308 resource, err := objectToBeDeleted.AsYAML()
309 if err != nil {
310 return err
311 }
312
313 manifests, err := ssa.ReadObjects(bytes.NewReader(resource))
314 if err != nil {
315 return err
316 }
317
318 sort.Sort(ssa.SortableUnstructureds(manifests))
319
320 for i := range manifests {
321 manifests[i].SetOwnerReferences(r.ownerRef(&provider))
322 }
323
324 _, err = r.ResourceManager.DeleteAll(ctx, manifests, ssa.DefaultDeleteOptions())
325 if err != nil {
326 return err
327 }
328
329 err = resMap.Remove(resourceID)
330 return err
331 }
332
333 func (r *ProviderReconciler) reconcileTarget(ctx context.Context, provider api.Provider) (api.Provider, error) {
334 log := logger.FromContext(ctx)
335
336 target := provider.Spec.Target
337 if target == "d-edge-lab" {
338 target = ""
339 }
340
341
342 if target == "" {
343 clusterType := ""
344 if einfo, _ := info.FromClient(ctx, r.Client); einfo != nil {
345 clusterType = einfo.ClusterType
346 }
347 switch clusterType {
348 case "dsds":
349 target = "d-edge"
350 case "sds":
351 target = "edge"
352 default:
353 target = "generic"
354 }
355 }
356
357 log.V(2).Info("reconcile target", "target", target)
358
359 if !config.TestClientEnabled() {
360
361
362 _, ok := r.Resmaps[target+"-without-test-client"]
363
364
365 if !ok {
366 orgResMap, ok := r.Resmaps[target]
367 if !ok {
368 return api.NotReady(provider, "ResMapFailed", fmt.Sprintf("no resources found for target %s", target)), fmt.Errorf("no resources found for target %s", target)
369 }
370
371
372 noTestClientResMap := orgResMap.DeepCopy()
373
374 err := r.deleteResource(ctx, TestClient, resid.Gvk{Version: "v1", Kind: "ServiceAccount"}, noTestClientResMap, provider)
375 if err != nil {
376 log.Error(err, "delete test client resource: no resources found for ServiceAccount test-client")
377 }
378
379 err = r.deleteResource(ctx, TestClient, resid.Gvk{Version: "v1", Kind: "Service"}, noTestClientResMap, provider)
380 if err != nil {
381 log.Error(err, "delete test client resource: no resources found for Service test-client")
382 }
383
384 err = r.deleteResource(ctx, TestClient, resid.Gvk{Version: "v1", Kind: Deployment, Group: "apps"}, noTestClientResMap, provider)
385 if err != nil {
386 log.Error(err, "delete test client resource: no resources found for Deployment test-client")
387 }
388
389 err = r.deleteResource(ctx, TestClientCRName, resid.Gvk{Version: ClientCRDVersion, Kind: ClientCRDName, Group: ClientCRDGroup}, noTestClientResMap, provider)
390 if err != nil {
391 log.Error(err, "delete test client resource: no resources found for Client CR of test-client")
392 }
393
394 err = r.deleteResource(ctx, TestClientSecretName, resid.Gvk{Version: "v1", Kind: "Secret"}, noTestClientResMap, provider)
395 if err != nil {
396 log.Error(err, "delete test client resource: no resources found for secret of test-client")
397 }
398 r.Resmaps[target+"-without-test-client"] = noTestClientResMap
399 }
400
401 target = target + "-without-test-client"
402 } else {
403 delete(r.Resmaps, target+"-without-test-client")
404 }
405
406 resMap, ok := r.Resmaps[target]
407 if !ok {
408 return api.NotReady(provider, "ResMapFailed", fmt.Sprintf("no resources found for target %s", target)), fmt.Errorf("no resources found for target %s", target)
409 }
410
411 syncDeploymentErr := updateEnvVarsForResource("deployment", provider, resMap, log)
412 if syncDeploymentErr != nil {
413 log.Info("failed to sync deployment environment variables with provider", "error", syncDeploymentErr)
414 }
415
416 syncDaemonsetErr := updateEnvVarsForResource("daemonset", provider, resMap, log)
417 if syncDaemonsetErr != nil {
418 log.Info("failed to sync deamonset environment variables with provider", "error", syncDaemonsetErr)
419 }
420
421 resources, err := resMap.AsYaml()
422 if err != nil {
423 return api.NotReady(provider, "KustomizeToYamlFailed", err.Error()), err
424 }
425
426 r.Manifests, err = ssa.ReadObjects(bytes.NewReader(resources))
427 if err != nil {
428 return api.NotReady(provider, "SSAReadObjectsFailed", err.Error()), err
429 }
430 sort.Sort(ssa.SortableUnstructureds(r.Manifests))
431
432 for i := range r.Manifests {
433 r.Manifests[i].SetOwnerReferences(r.ownerRef(&provider))
434 }
435
436 if provider.Spec.Okta.CredsSecretName != "" {
437
438 oktaAddSecret(r.Manifests, log)
439
440 oktaReplaceSecretName(r.Manifests, provider)
441 } else {
442
443 r.Manifests = oktaRemoveExternalSecret(r.Manifests)
444 }
445
446
447 version := encryptionGetDatabaseVersion(provider.Status)
448 if version != "" {
449
450 r.Manifests = encryptionAddSecretVersion(version, r.Manifests, log)
451 } else {
452
453 r.Manifests = encryptionRemoveSecretEnv(r.Manifests, log)
454 }
455
456
457
458 changed, err := r.ResourceManager.ApplyAllStaged(ctx, r.Manifests, ssa.ApplyOptions{
459 Force: true, WaitTimeout: 60 * time.Second,
460 })
461 if err != nil {
462 return api.NotReady(provider, "ResourceManagerApplyFailed", err.Error()), err
463 }
464
465 log.V(2).Info("applied target manifests", "resources", changed.Entries)
466
467
468
469 if !config.IsTest() {
470 err = r.ResourceManager.WaitForSet(changed.ToObjMetadataSet(), ssa.WaitOptions{
471 Interval: 2 * time.Second,
472 Timeout: 60 * time.Second,
473 })
474 if err != nil {
475 return api.NotReady(provider, "ResourceManagerTimedOutWaitingForSet", err.Error()), err
476 }
477 }
478
479 log.Info("target manifests successfully reconciled")
480
481 return provider, nil
482 }
483
484 func oktaAddSecret(manifest []*unstructured.Unstructured, log logr.Logger) {
485 for i := range manifest {
486 if ((manifest[i].GetName() == StoreProvider) || (manifest[i].GetName() == ExternalProvider) || (manifest[i].GetName() == TouchpointProvider)) &&
487 (manifest[i].GetKind() == Deployment || manifest[i].GetKind() == DaemonSet) && manifest[i].GetNamespace() == EdgeIAM {
488 containers := manifest[i].Object["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["containers"].([]interface{})
489 for _, container := range containers {
490 if container.(map[string]interface{})["name"] != ProviderContainer {
491 continue
492 }
493
494
495 envFrom := container.(map[string]interface{})["envFrom"].([]interface{})
496
497 oktaSecretRef := map[string]interface{}{"secretRef": map[string]interface{}{"name": "okta-secret"}}
498 envFrom = append(envFrom, oktaSecretRef)
499 container.(map[string]interface{})["envFrom"] = envFrom
500 log.Info("Added okta secretRef")
501 }
502 }
503 }
504 }
505
506 func oktaReplaceSecretName(manifest []*unstructured.Unstructured, provider api.Provider) {
507 for i := range manifest {
508 if (manifest[i].GetName() == "okta-secret") && (manifest[i].GetKind() == "ExternalSecret") {
509 datafrom := manifest[i].Object["spec"].(map[string]interface{})["dataFrom"].([]interface{})
510 for _, key := range datafrom {
511 if key.(map[string]interface{})["extract"].(map[string]interface{})["key"].(string) == "okta-creds-0" {
512 key.(map[string]interface{})["extract"].(map[string]interface{})["key"] = provider.Spec.Okta.CredsSecretName
513 break
514 }
515 }
516 }
517 }
518 }
519
520 func oktaRemoveExternalSecret(manifests []*unstructured.Unstructured) []*unstructured.Unstructured {
521 for i := range manifests {
522 if (manifests[i].GetName() == "okta-secret") && (manifests[i].GetKind() == "ExternalSecret") {
523 manifests = append(manifests[:i], manifests[i+1:]...)
524 break
525 }
526 }
527 return manifests
528 }
529
530 func getProviderValueFor(provider api.Provider, envName string) string {
531 switch envName {
532 case "IAM_PIN_RETRY_THRESHOLD":
533 if provider.Spec.PIN.Attempts != 0 {
534 return strconv.Itoa(int(provider.Spec.PIN.Attempts))
535 }
536 return ""
537 case "IAM_PIN_HISTORY_LENGTH":
538 if provider.Spec.PIN.History != 0 {
539 return strconv.Itoa(int(provider.Spec.PIN.History))
540 }
541 return ""
542 case "IAM_PIN_LIFESPAN":
543 return provider.Spec.PIN.Expire
544 case "IAM_PROFILE_LIFESPAN":
545 return provider.Spec.Profile.Expire
546 case "IAM_BARCODE_LIFESPAN":
547 return provider.Spec.Barcode.Expire
548 case "FF_BARCODE_ENFORCE_ROLES":
549 if provider.Spec.Barcode.Role {
550 return "true"
551 }
552 return ""
553 case "FF_ENFORCE_PERMISSIONS":
554 if len(provider.Spec.FF) > 0 {
555 if v, ok := provider.Spec.FF[ff.EnforceEdgeIDPermissions]; ok {
556 return strconv.FormatBool(v)
557 }
558 return ""
559 }
560 return ""
561 default:
562 }
563
564 return ""
565 }
566
567 func updateEnvVarsForResource(resType string, provider api.Provider, resMap resmap.ResMap, log logr.Logger) error {
568
569 var gvk resid.Gvk
570 var resourceName string
571 if resType == "deployment" {
572 gvk = resid.Gvk{Version: "v1", Kind: Deployment, Group: "apps"}
573 resourceName = StoreProvider
574 } else if resType == "daemonset" {
575 gvk = resid.Gvk{Version: "v1", Kind: "DaemonSet", Group: "apps"}
576 resourceName = TouchpointProvider
577 } else {
578 return fmt.Errorf("unsupported resource type %s", resType)
579 }
580
581 resourceID := resid.ResId{
582 Gvk: gvk,
583 Name: resourceName,
584 Namespace: provider.Namespace,
585 }
586
587
588 resource, err := resMap.GetById(resourceID)
589 if err != nil {
590 log.Info("failed to find the resource in the resources list. will try to sync it again soon.", "error", err)
591 return fmt.Errorf("failed to find the resource in the resources list. will try to sync it again soon")
592 }
593
594
595 unstructured, _ := resource.Map()
596
597
598 containers, ok := unstructured["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["containers"].([]interface{})
599 if !ok {
600 return fmt.Errorf("failed to get containers for %s", resType)
601 }
602
603 for _, container := range containers {
604
605 if container.(map[string]interface{})["name"] != ProviderContainer {
606 continue
607 }
608
609
610 env, ok := container.(map[string]interface{})["env"].([]interface{})
611 if !ok {
612 continue
613 }
614
615 var exists bool
616
617 for _, envCandidate := range envsToSync {
618 exists = false
619 for j, e := range env {
620 name, ok := e.(map[string]interface{})["name"].(string)
621 if ok && name == envCandidate {
622
623 exists = true
624 val := getProviderValueFor(provider, name)
625 if val != "" {
626 e.(map[string]interface{})["value"] = val
627 } else {
628 env = append(env[:j], env[j+1:]...)
629 }
630 break
631 }
632 }
633
634 if !exists {
635
636 envValue := getProviderValueFor(provider, envCandidate)
637 if envValue != "" {
638 env = append(env, map[string]interface{}{
639 "name": envCandidate,
640 "value": envValue,
641 })
642 }
643 container.(map[string]interface{})["env"] = env
644 }
645 }
646 }
647
648
649 depProvider := kp.NewDefaultDepProvider()
650 rf := depProvider.GetResourceFactory()
651 updatedResource := rf.FromMap(unstructured)
652
653
654 _, err = resMap.Replace(updatedResource)
655 if err != nil {
656 return fmt.Errorf("failed to replace "+resType+"resource. ", err)
657 }
658
659 log.V(2).Info(resType + " is synced with provider")
660 return nil
661 }
662
663 func (r *ProviderReconciler) ownerRef(provider *api.Provider) []metav1.OwnerReference {
664 kind := reflect.TypeOf(api.Provider{}).Name()
665 ownerRef := []metav1.OwnerReference{
666 *metav1.NewControllerRef(
667 provider,
668 api.GroupVersion.WithKind(kind),
669 ),
670 }
671 return ownerRef
672 }
673
674
675
676
677
678 func (r *ProviderReconciler) updateStatus(ctx context.Context, req ctrl.Request, status api.ProviderStatus) error {
679 var provider api.Provider
680 if err := r.Get(ctx, req.NamespacedName, &provider); err != nil {
681 return err
682 }
683 providerStatus := provider.Status.Conditions
684
685 patch := client.MergeFrom(provider.DeepCopy())
686
687 provider.Status = status
688
689
690
691 for i, condition := range providerStatus {
692 if condition.Reason == EncryptionRotationSucceeded {
693 if provider.Spec.Encryption.Version != "" {
694 edgeConditions.Set(&provider, &condition)
695 } else {
696
697 provider.Status.Conditions = append(providerStatus[:i], providerStatus[i+1:]...)
698 }
699 }
700 }
701
702 return r.Status().Patch(ctx, &provider, patch)
703 }
704
705
706
707
708 func CreateResmaps(paths []string) (map[string]resmap.ResMap, error) {
709 factory := resmap.NewFactory(resource.NewFactory(&hasher.Hasher{}))
710 resMaps := make(map[string]resmap.ResMap)
711
712 for _, path := range paths {
713 readManifests, err := os.Open(path)
714 if err != nil {
715 return nil, err
716 }
717 b, err := os.ReadFile(readManifests.Name())
718 if err != nil {
719 return nil, err
720 }
721 resMap, err := factory.NewResMapFromBytes(b)
722 if err != nil {
723 return nil, err
724 }
725 dir := filepath.Dir(path)
726 key := strings.Split(dir, "/")
727 resMaps[key[len(key)-1]] = resMap
728 }
729 return resMaps, nil
730 }
731
732
733 func encryptionGetDatabaseVersion(status api.ProviderStatus) string {
734 for _, condition := range status.Conditions {
735 if condition.Reason == EncryptionRotationSucceeded {
736 message := condition.Message
737 version := strings.TrimPrefix(message, "successfully updated databases to version: ")
738 return version
739 }
740 }
741 return ""
742 }
743
744
745 func encryptionAddSecretVersion(version string, manifest []*unstructured.Unstructured, log logr.Logger) []*unstructured.Unstructured {
746 secretName := EncryptionKeySecretPrefix + version
747 for i := range manifest {
748 name := manifest[i].GetName()
749
750 if ((name == StoreProvider) || (name == ExternalProvider) || (name == TouchpointProvider)) &&
751 (manifest[i].GetKind() == Deployment || manifest[i].GetKind() == DaemonSet) && manifest[i].GetNamespace() == EdgeIAM {
752 containers := manifest[i].Object["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["containers"].([]interface{})
753
754 for _, container := range containers {
755 containerName := container.(map[string]interface{})["name"]
756 if containerName == ProviderContainer {
757
758 envs := container.(map[string]interface{})["env"].([]interface{})
759 for _, env := range envs {
760 envName := env.(map[string]interface{})["name"]
761
762 if envName == "IAM_ENCRYPTION_KEY" {
763 env.(map[string]interface{})["valueFrom"].(map[string]interface{})["secretKeyRef"].(map[string]interface{})["name"] = secretName
764
765
766 log.Info(fmt.Sprintf("Updated encryption key env on %s to use the encryption key secret", name), "secret", secretName)
767 break
768 }
769 }
770 }
771 }
772 }
773 }
774 return manifest
775 }
776
777
778 func encryptionRemoveSecretEnv(manifest []*unstructured.Unstructured, log logr.Logger) []*unstructured.Unstructured {
779 for i := range manifest {
780 name := manifest[i].GetName()
781 if ((name == StoreProvider) || (name == ExternalProvider) || (name == TouchpointProvider)) &&
782 (manifest[i].GetKind() == Deployment || manifest[i].GetKind() == DaemonSet) && manifest[i].GetNamespace() == EdgeIAM {
783 containers := manifest[i].Object["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["containers"].([]interface{})
784 for _, container := range containers {
785 containerName := container.(map[string]interface{})["name"]
786 if containerName == ProviderContainer {
787
788 envs := container.(map[string]interface{})["env"].([]interface{})
789 for j, env := range envs {
790 envName := env.(map[string]interface{})["name"]
791
792 if envName == "IAM_ENCRYPTION_KEY" {
793 envs = append(envs[:j], envs[j+1:]...)
794 container.(map[string]interface{})["env"] = envs
795 log.Info(fmt.Sprintf("removed encryption key env on %s to use the encryption key secret", name), "object", name)
796 break
797 }
798 }
799 }
800 }
801 }
802 }
803 return manifest
804 }
805
View as plain text