externalsecret_controller_template.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. type Parser struct {
  26. exec template.ExecFunc
  27. dataMap map[string][]byte
  28. client client.Client
  29. targetSecret *v1.Secret
  30. }
  31. func (p *Parser) MergeConfigMap(ctx context.Context, namespace string, tpl esv1beta1.TemplateFrom) error {
  32. if tpl.ConfigMap == nil {
  33. return nil
  34. }
  35. var cm v1.ConfigMap
  36. err := p.client.Get(ctx, types.NamespacedName{
  37. Name: tpl.ConfigMap.Name,
  38. Namespace: namespace,
  39. }, &cm)
  40. if err != nil {
  41. return err
  42. }
  43. for _, k := range tpl.ConfigMap.Items {
  44. val, ok := cm.Data[k.Key]
  45. out := make(map[string][]byte)
  46. if !ok {
  47. return fmt.Errorf(errTplCMMissingKey, tpl.ConfigMap.Name, k.Key)
  48. }
  49. switch k.TemplateAs {
  50. case esv1beta1.TemplateScopeValues:
  51. out[k.Key] = []byte(val)
  52. case esv1beta1.TemplateScopeKeysAndValues:
  53. out[val] = []byte(val)
  54. }
  55. err = p.exec(out, p.dataMap, k.TemplateAs, tpl.Target, p.targetSecret)
  56. if err != nil {
  57. return err
  58. }
  59. }
  60. return nil
  61. }
  62. func (p *Parser) MergeSecret(ctx context.Context, namespace string, tpl esv1beta1.TemplateFrom) error {
  63. if tpl.Secret == nil {
  64. return nil
  65. }
  66. var sec v1.Secret
  67. err := p.client.Get(ctx, types.NamespacedName{
  68. Name: tpl.Secret.Name,
  69. Namespace: namespace,
  70. }, &sec)
  71. if err != nil {
  72. return err
  73. }
  74. for _, k := range tpl.Secret.Items {
  75. val, ok := sec.Data[k.Key]
  76. if !ok {
  77. return fmt.Errorf(errTplSecMissingKey, tpl.Secret.Name, k.Key)
  78. }
  79. out := make(map[string][]byte)
  80. switch k.TemplateAs {
  81. case esv1beta1.TemplateScopeValues:
  82. out[k.Key] = val
  83. case esv1beta1.TemplateScopeKeysAndValues:
  84. out[string(val)] = val
  85. }
  86. err = p.exec(out, p.dataMap, k.TemplateAs, tpl.Target, p.targetSecret)
  87. if err != nil {
  88. return err
  89. }
  90. }
  91. return nil
  92. }
  93. func (p *Parser) MergeLiteral(_ context.Context, tpl esv1beta1.TemplateFrom) error {
  94. if tpl.Literal == nil {
  95. return nil
  96. }
  97. out := make(map[string][]byte)
  98. out[*tpl.Literal] = []byte(*tpl.Literal)
  99. return p.exec(out, p.dataMap, esv1beta1.TemplateScopeKeysAndValues, tpl.Target, p.targetSecret)
  100. }
  101. func (p *Parser) MergeTemplateFrom(ctx context.Context, es *esv1beta1.ExternalSecret) error {
  102. if es.Spec.Target.Template == nil {
  103. return nil
  104. }
  105. for _, tpl := range es.Spec.Target.Template.TemplateFrom {
  106. err := p.MergeConfigMap(ctx, es.Namespace, tpl)
  107. if err != nil {
  108. return err
  109. }
  110. err = p.MergeSecret(ctx, es.Namespace, tpl)
  111. if err != nil {
  112. return err
  113. }
  114. err = p.MergeLiteral(ctx, tpl)
  115. if err != nil {
  116. return err
  117. }
  118. }
  119. return nil
  120. }
  121. func (p *Parser) MergeMap(tplMap map[string]string, target esv1beta1.TemplateTarget) error {
  122. byteMap := make(map[string][]byte)
  123. for k, v := range tplMap {
  124. byteMap[k] = []byte(v)
  125. }
  126. err := p.exec(byteMap, p.dataMap, esv1beta1.TemplateScopeValues, target, p.targetSecret)
  127. if err != nil {
  128. return fmt.Errorf(errExecTpl, err)
  129. }
  130. return nil
  131. }
  132. // merge template in the following order:
  133. // * template.Data (highest precedence)
  134. // * template.templateFrom
  135. // * secret via es.data or es.dataFrom.
  136. func (r *Reconciler) applyTemplate(ctx context.Context, es *esv1beta1.ExternalSecret, secret *v1.Secret, dataMap map[string][]byte) error {
  137. mergeMetadata(secret, es)
  138. // no template: copy data and return
  139. if es.Spec.Target.Template == nil {
  140. secret.Data = dataMap
  141. return nil
  142. }
  143. // Merge Policy should merge secrets
  144. if es.Spec.Target.Template.MergePolicy == esv1beta1.MergePolicyMerge {
  145. for k, v := range dataMap {
  146. secret.Data[k] = v
  147. }
  148. }
  149. execute, err := template.EngineForVersion(es.Spec.Target.Template.EngineVersion)
  150. if err != nil {
  151. return err
  152. }
  153. p := Parser{
  154. client: r.Client,
  155. targetSecret: secret,
  156. dataMap: dataMap,
  157. exec: execute,
  158. }
  159. // apply templates defined in template.templateFrom
  160. err = p.MergeTemplateFrom(ctx, es)
  161. if err != nil {
  162. return fmt.Errorf(errFetchTplFrom, err)
  163. }
  164. // explicitly defined template.Data takes precedence over templateFrom
  165. err = p.MergeMap(es.Spec.Target.Template.Data, esv1beta1.TemplateTargetData)
  166. if err != nil {
  167. return fmt.Errorf(errExecTpl, err)
  168. }
  169. // get template data for labels
  170. err = p.MergeMap(es.Spec.Target.Template.Metadata.Labels, esv1beta1.TemplateTargetLabels)
  171. if err != nil {
  172. return fmt.Errorf(errExecTpl, err)
  173. }
  174. // get template data for labels
  175. err = p.MergeMap(es.Spec.Target.Template.Metadata.Annotations, esv1beta1.TemplateTargetAnnotations)
  176. if err != nil {
  177. return fmt.Errorf(errExecTpl, err)
  178. }
  179. // if no data was provided by template fallback
  180. // to value from the provider
  181. if len(es.Spec.Target.Template.Data) == 0 && len(es.Spec.Target.Template.TemplateFrom) == 0 {
  182. secret.Data = dataMap
  183. }
  184. return nil
  185. }
  186. // we do not want to force-override the label/annotations
  187. // and only copy the necessary key/value pairs.
  188. func mergeMetadata(secret *v1.Secret, externalSecret *esv1beta1.ExternalSecret) {
  189. if secret.ObjectMeta.Labels == nil {
  190. secret.ObjectMeta.Labels = make(map[string]string)
  191. }
  192. if secret.ObjectMeta.Annotations == nil {
  193. secret.ObjectMeta.Annotations = make(map[string]string)
  194. }
  195. if externalSecret.Spec.Target.Template == nil {
  196. utils.MergeStringMap(secret.ObjectMeta.Labels, externalSecret.ObjectMeta.Labels)
  197. utils.MergeStringMap(secret.ObjectMeta.Annotations, externalSecret.ObjectMeta.Annotations)
  198. return
  199. }
  200. // if template is defined: use those labels/annotations
  201. secret.Type = externalSecret.Spec.Target.Template.Type
  202. utils.MergeStringMap(secret.ObjectMeta.Labels, externalSecret.Spec.Target.Template.Metadata.Labels)
  203. utils.MergeStringMap(secret.ObjectMeta.Annotations, externalSecret.Spec.Target.Template.Metadata.Annotations)
  204. }