externalsecret_controller_template.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package externalsecret
  13. import (
  14. "context"
  15. "fmt"
  16. v1 "k8s.io/api/core/v1"
  17. "k8s.io/apimachinery/pkg/types"
  18. "sigs.k8s.io/controller-runtime/pkg/client"
  19. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  20. // Loading registered providers.
  21. _ "github.com/external-secrets/external-secrets/pkg/provider/register"
  22. "github.com/external-secrets/external-secrets/pkg/template"
  23. utils "github.com/external-secrets/external-secrets/pkg/utils"
  24. )
  25. // merge template in the following order:
  26. // * template.Data (highest precedence)
  27. // * template.templateFrom
  28. // * secret via es.data or es.dataFrom.
  29. func (r *Reconciler) applyTemplate(ctx context.Context, es *esv1beta1.ExternalSecret, secret *v1.Secret, dataMap map[string][]byte) error {
  30. mergeMetadata(secret, es)
  31. // no template: copy data and return
  32. if es.Spec.Target.Template == nil {
  33. secret.Data = dataMap
  34. secret.Annotations[esv1beta1.AnnotationDataHash] = utils.ObjectHash(secret.Data)
  35. return nil
  36. }
  37. // fetch templates defined in template.templateFrom
  38. tplMap, err := r.getTemplateData(ctx, es)
  39. if err != nil {
  40. return fmt.Errorf(errFetchTplFrom, err)
  41. }
  42. // explicitly defined template.Data takes precedence over templateFrom
  43. for k, v := range es.Spec.Target.Template.Data {
  44. tplMap[k] = []byte(v)
  45. }
  46. r.Log.V(1).Info("found template data", "tpl_data", tplMap)
  47. tplMapLabels := make(map[string][]byte)
  48. tplMapAnnotations := make(map[string][]byte)
  49. // get template data for labels
  50. if es.Spec.Target.Template.Metadata.Labels != nil {
  51. for k, v := range es.Spec.Target.Template.Metadata.Labels {
  52. tplMapLabels[k] = []byte(v)
  53. }
  54. r.Log.V(1).Info("found template metadata (labels)", "tpl_labels", tplMapLabels)
  55. }
  56. // get template data for annotations
  57. if es.Spec.Target.Template.Metadata.Annotations != nil {
  58. for k, v := range es.Spec.Target.Template.Metadata.Annotations {
  59. tplMapAnnotations[k] = []byte(v)
  60. }
  61. r.Log.V(1).Info("found template metadata (annotations)", "tpl_annotations", tplMapAnnotations)
  62. }
  63. execute, err := template.EngineForVersion(es.Spec.Target.Template.EngineVersion)
  64. if err != nil {
  65. return err
  66. }
  67. err = execute(tplMap, tplMapLabels, tplMapAnnotations, dataMap, secret)
  68. if err != nil {
  69. return fmt.Errorf(errExecTpl, err)
  70. }
  71. // if no data was provided by template fallback
  72. // to value from the provider
  73. if len(es.Spec.Target.Template.Data) == 0 && len(es.Spec.Target.Template.TemplateFrom) == 0 {
  74. secret.Data = dataMap
  75. }
  76. secret.Annotations[esv1beta1.AnnotationDataHash] = utils.ObjectHash(secret.Data)
  77. return nil
  78. }
  79. // we do not want to force-override the label/annotations
  80. // and only copy the necessary key/value pairs.
  81. func mergeMetadata(secret *v1.Secret, externalSecret *esv1beta1.ExternalSecret) {
  82. if secret.ObjectMeta.Labels == nil {
  83. secret.ObjectMeta.Labels = make(map[string]string)
  84. }
  85. if secret.ObjectMeta.Annotations == nil {
  86. secret.ObjectMeta.Annotations = make(map[string]string)
  87. }
  88. if externalSecret.Spec.Target.Template == nil {
  89. utils.MergeStringMap(secret.ObjectMeta.Labels, externalSecret.ObjectMeta.Labels)
  90. utils.MergeStringMap(secret.ObjectMeta.Annotations, externalSecret.ObjectMeta.Annotations)
  91. return
  92. }
  93. // if template is defined: use those labels/annotations
  94. secret.Type = externalSecret.Spec.Target.Template.Type
  95. utils.MergeStringMap(secret.ObjectMeta.Labels, externalSecret.Spec.Target.Template.Metadata.Labels)
  96. utils.MergeStringMap(secret.ObjectMeta.Annotations, externalSecret.Spec.Target.Template.Metadata.Annotations)
  97. }
  98. func (r *Reconciler) getTemplateData(ctx context.Context, externalSecret *esv1beta1.ExternalSecret) (map[string][]byte, error) {
  99. out := make(map[string][]byte)
  100. if externalSecret.Spec.Target.Template == nil {
  101. return out, nil
  102. }
  103. for _, tpl := range externalSecret.Spec.Target.Template.TemplateFrom {
  104. err := mergeConfigMap(ctx, r.Client, externalSecret, tpl, out)
  105. if err != nil {
  106. return nil, err
  107. }
  108. err = mergeSecret(ctx, r.Client, externalSecret, tpl, out)
  109. if err != nil {
  110. return nil, err
  111. }
  112. }
  113. return out, nil
  114. }
  115. func mergeConfigMap(ctx context.Context, k8sClient client.Client, es *esv1beta1.ExternalSecret, tpl esv1beta1.TemplateFrom, out map[string][]byte) error {
  116. if tpl.ConfigMap == nil {
  117. return nil
  118. }
  119. var cm v1.ConfigMap
  120. err := k8sClient.Get(ctx, types.NamespacedName{
  121. Name: tpl.ConfigMap.Name,
  122. Namespace: es.Namespace,
  123. }, &cm)
  124. if err != nil {
  125. return err
  126. }
  127. for _, k := range tpl.ConfigMap.Items {
  128. val, ok := cm.Data[k.Key]
  129. if !ok {
  130. return fmt.Errorf(errTplCMMissingKey, tpl.ConfigMap.Name, k.Key)
  131. }
  132. out[k.Key] = []byte(val)
  133. }
  134. return nil
  135. }
  136. func mergeSecret(ctx context.Context, k8sClient client.Client, es *esv1beta1.ExternalSecret, tpl esv1beta1.TemplateFrom, out map[string][]byte) error {
  137. if tpl.Secret == nil {
  138. return nil
  139. }
  140. var sec v1.Secret
  141. err := k8sClient.Get(ctx, types.NamespacedName{
  142. Name: tpl.Secret.Name,
  143. Namespace: es.Namespace,
  144. }, &sec)
  145. if err != nil {
  146. return err
  147. }
  148. for _, k := range tpl.Secret.Items {
  149. val, ok := sec.Data[k.Key]
  150. if !ok {
  151. return fmt.Errorf(errTplSecMissingKey, tpl.Secret.Name, k.Key)
  152. }
  153. out[k.Key] = val
  154. }
  155. return nil
  156. }