externalsecret_controller_template.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package externalsecret
  14. import (
  15. "context"
  16. "fmt"
  17. "maps"
  18. v1 "k8s.io/api/core/v1"
  19. "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
  20. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  21. "github.com/external-secrets/external-secrets/pkg/controllers/templating"
  22. "github.com/external-secrets/external-secrets/runtime/esutils"
  23. "github.com/external-secrets/external-secrets/runtime/template"
  24. _ "github.com/external-secrets/external-secrets/pkg/register" // Loading registered providers.
  25. )
  26. // ApplyTemplate merges templates in the following order:
  27. // * template.Data (highest precedence)
  28. // * template.TemplateFrom
  29. // * secret via es.data or es.dataFrom (if template.MergePolicy is Merge, or there is no template)
  30. // * existing secret keys (if CreationPolicy is Merge or CreateOrMerge).
  31. func (r *Reconciler) ApplyTemplate(ctx context.Context, es *esv1.ExternalSecret, secret *v1.Secret, dataMap map[string][]byte) error {
  32. // update metadata (labels, annotations, finalizers) of the secret
  33. if err := setMetadata(secret, es); err != nil {
  34. return err
  35. }
  36. // we only keep existing keys if creation policy is Merge or CreateOrMerge,
  37. // otherwise we clear the secret
  38. if es.Spec.Target.CreationPolicy != esv1.CreatePolicyMerge &&
  39. es.Spec.Target.CreationPolicy != esv1.CreatePolicyCreateOrMerge {
  40. secret.Data = make(map[string][]byte)
  41. }
  42. // no template: copy data and return
  43. if es.Spec.Target.Template == nil {
  44. maps.Insert(secret.Data, maps.All(dataMap))
  45. return nil
  46. }
  47. // set the secret type if it is defined in the template, otherwise keep the existing type
  48. if es.Spec.Target.Template.Type != "" {
  49. secret.Type = es.Spec.Target.Template.Type
  50. }
  51. // when TemplateMergePolicy is Merge, or there is no data template, we include the keys from `dataMap`
  52. noTemplate := len(es.Spec.Target.Template.Data) == 0 && len(es.Spec.Target.Template.TemplateFrom) == 0
  53. if es.Spec.Target.Template.MergePolicy == esv1.MergePolicyMerge || noTemplate {
  54. maps.Insert(secret.Data, maps.All(dataMap))
  55. }
  56. execute, err := template.EngineForVersion(es.Spec.Target.Template.EngineVersion)
  57. if err != nil {
  58. return err
  59. }
  60. p := templating.Parser{
  61. Client: r.Client,
  62. TargetSecret: secret,
  63. DataMap: dataMap,
  64. Exec: execute,
  65. }
  66. // apply templates defined in template.templateFrom
  67. err = p.MergeTemplateFrom(ctx, es.Namespace, es.Spec.Target.Template)
  68. if err != nil {
  69. return fmt.Errorf(errFetchTplFrom, err)
  70. }
  71. // apply data templates
  72. // NOTE: explicitly defined template.data templates take precedence over templateFrom
  73. err = p.MergeMap(es.Spec.Target.Template.Data, esv1.TemplateTargetData)
  74. if err != nil {
  75. return fmt.Errorf(errExecTpl, err)
  76. }
  77. // apply templates for labels
  78. // NOTE: this only works for v2 templates
  79. err = p.MergeMap(es.Spec.Target.Template.Metadata.Labels, esv1.TemplateTargetLabels)
  80. if err != nil {
  81. return fmt.Errorf(errExecTpl, err)
  82. }
  83. // apply template for annotations
  84. // NOTE: this only works for v2 templates
  85. err = p.MergeMap(es.Spec.Target.Template.Metadata.Annotations, esv1.TemplateTargetAnnotations)
  86. if err != nil {
  87. return fmt.Errorf(errExecTpl, err)
  88. }
  89. return nil
  90. }
  91. // setMetadata sets Labels and Annotations to the given secret.
  92. func setMetadata(secret *v1.Secret, es *esv1.ExternalSecret) error {
  93. // ensure that Labels and Annotations are not nil
  94. // so it is safe to merge them
  95. if secret.Labels == nil {
  96. secret.Labels = make(map[string]string)
  97. }
  98. if secret.Annotations == nil {
  99. secret.Annotations = make(map[string]string)
  100. }
  101. // remove any existing labels managed by this external secret
  102. // this is to ensure that we don't have any stale labels
  103. labelKeys, err := templating.GetManagedLabelKeys(secret, es.Name)
  104. if err != nil {
  105. return err
  106. }
  107. for _, key := range labelKeys {
  108. delete(secret.ObjectMeta.Labels, key)
  109. }
  110. annotationKeys, err := templating.GetManagedAnnotationKeys(secret, es.Name)
  111. if err != nil {
  112. return err
  113. }
  114. for _, key := range annotationKeys {
  115. delete(secret.ObjectMeta.Annotations, key)
  116. }
  117. // if no template is defined, copy labels and annotations from the ExternalSecret
  118. if es.Spec.Target.Template == nil {
  119. esutils.MergeStringMap(secret.ObjectMeta.Labels, es.ObjectMeta.Labels)
  120. esutils.MergeStringMap(secret.ObjectMeta.Annotations, es.ObjectMeta.Annotations)
  121. return nil
  122. }
  123. // copy labels and annotations from the template
  124. esutils.MergeStringMap(secret.ObjectMeta.Labels, es.Spec.Target.Template.Metadata.Labels)
  125. esutils.MergeStringMap(secret.ObjectMeta.Annotations, es.Spec.Target.Template.Metadata.Annotations)
  126. // add finalizers from the template
  127. if secret.ObjectMeta.DeletionTimestamp.IsZero() {
  128. for _, finalizer := range es.Spec.Target.Template.Metadata.Finalizers {
  129. if !controllerutil.ContainsFinalizer(secret, finalizer) {
  130. controllerutil.AddFinalizer(secret, finalizer)
  131. }
  132. }
  133. }
  134. return nil
  135. }