externalsecret_controller_template.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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. err = template.Execute(tplMap, dataMap, secret)
  48. if err != nil {
  49. return fmt.Errorf(errExecTpl, err)
  50. }
  51. // if no data was provided by template fallback
  52. // to value from the provider
  53. if len(es.Spec.Target.Template.Data) == 0 {
  54. secret.Data = dataMap
  55. }
  56. secret.Annotations[esv1beta1.AnnotationDataHash] = utils.ObjectHash(secret.Data)
  57. return nil
  58. }
  59. // we do not want to force-override the label/annotations
  60. // and only copy the necessary key/value pairs.
  61. func mergeMetadata(secret *v1.Secret, externalSecret *esv1beta1.ExternalSecret) {
  62. if secret.ObjectMeta.Labels == nil {
  63. secret.ObjectMeta.Labels = make(map[string]string)
  64. }
  65. if secret.ObjectMeta.Annotations == nil {
  66. secret.ObjectMeta.Annotations = make(map[string]string)
  67. }
  68. if externalSecret.Spec.Target.Template == nil {
  69. utils.MergeStringMap(secret.ObjectMeta.Labels, externalSecret.ObjectMeta.Labels)
  70. utils.MergeStringMap(secret.ObjectMeta.Annotations, externalSecret.ObjectMeta.Annotations)
  71. return
  72. }
  73. // if template is defined: use those labels/annotations
  74. secret.Type = externalSecret.Spec.Target.Template.Type
  75. utils.MergeStringMap(secret.ObjectMeta.Labels, externalSecret.Spec.Target.Template.Metadata.Labels)
  76. utils.MergeStringMap(secret.ObjectMeta.Annotations, externalSecret.Spec.Target.Template.Metadata.Annotations)
  77. }
  78. func (r *Reconciler) getTemplateData(ctx context.Context, externalSecret *esv1beta1.ExternalSecret) (map[string][]byte, error) {
  79. out := make(map[string][]byte)
  80. if externalSecret.Spec.Target.Template == nil {
  81. return out, nil
  82. }
  83. for _, tpl := range externalSecret.Spec.Target.Template.TemplateFrom {
  84. err := mergeConfigMap(ctx, r.Client, externalSecret, tpl, out)
  85. if err != nil {
  86. return nil, err
  87. }
  88. err = mergeSecret(ctx, r.Client, externalSecret, tpl, out)
  89. if err != nil {
  90. return nil, err
  91. }
  92. }
  93. return out, nil
  94. }
  95. func mergeConfigMap(ctx context.Context, k8sClient client.Client, es *esv1beta1.ExternalSecret, tpl esv1beta1.TemplateFrom, out map[string][]byte) error {
  96. if tpl.ConfigMap == nil {
  97. return nil
  98. }
  99. var cm v1.ConfigMap
  100. err := k8sClient.Get(ctx, types.NamespacedName{
  101. Name: tpl.ConfigMap.Name,
  102. Namespace: es.Namespace,
  103. }, &cm)
  104. if err != nil {
  105. return err
  106. }
  107. for _, k := range tpl.ConfigMap.Items {
  108. val, ok := cm.Data[k.Key]
  109. if !ok {
  110. return fmt.Errorf(errTplCMMissingKey, tpl.ConfigMap.Name, k.Key)
  111. }
  112. out[k.Key] = []byte(val)
  113. }
  114. return nil
  115. }
  116. func mergeSecret(ctx context.Context, k8sClient client.Client, es *esv1beta1.ExternalSecret, tpl esv1beta1.TemplateFrom, out map[string][]byte) error {
  117. if tpl.Secret == nil {
  118. return nil
  119. }
  120. var sec v1.Secret
  121. err := k8sClient.Get(ctx, types.NamespacedName{
  122. Name: tpl.Secret.Name,
  123. Namespace: es.Namespace,
  124. }, &sec)
  125. if err != nil {
  126. return err
  127. }
  128. for _, k := range tpl.Secret.Items {
  129. val, ok := sec.Data[k.Key]
  130. if !ok {
  131. return fmt.Errorf(errTplSecMissingKey, tpl.Secret.Name, k.Key)
  132. }
  133. out[k.Key] = val
  134. }
  135. return nil
  136. }