parser.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. Copyright © 2025 ESO Maintainer Team
  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 templating
  14. import (
  15. "context"
  16. "crypto/sha3"
  17. "encoding/json"
  18. "fmt"
  19. "strings"
  20. v1 "k8s.io/api/core/v1"
  21. "k8s.io/apimachinery/pkg/types"
  22. "sigs.k8s.io/controller-runtime/pkg/client"
  23. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  24. "github.com/external-secrets/external-secrets/pkg/template"
  25. )
  26. const fieldOwnerTemplate = "externalsecrets.external-secrets.io/%v"
  27. const fieldOwnerTemplateSha = "externalsecrets.external-secrets.io/sha3/%x"
  28. var (
  29. errTplCMMissingKey = "error in configmap %s: missing key %s"
  30. errTplSecMissingKey = "error in secret %s: missing key %s"
  31. errExecTpl = "could not execute template: %w"
  32. )
  33. type Parser struct {
  34. Exec template.ExecFunc
  35. DataMap map[string][]byte
  36. Client client.Client
  37. TargetSecret *v1.Secret
  38. TemplateFromConfigMap *v1.ConfigMap
  39. TemplateFromSecret *v1.Secret
  40. }
  41. func (p *Parser) MergeConfigMap(ctx context.Context, namespace string, tpl esv1.TemplateFrom) error {
  42. if tpl.ConfigMap == nil {
  43. return nil
  44. }
  45. var cm v1.ConfigMap
  46. if p.TemplateFromConfigMap != nil {
  47. cm = *p.TemplateFromConfigMap
  48. } else {
  49. err := p.Client.Get(ctx, types.NamespacedName{
  50. Name: tpl.ConfigMap.Name,
  51. Namespace: namespace,
  52. }, &cm)
  53. if err != nil {
  54. return err
  55. }
  56. }
  57. for _, k := range tpl.ConfigMap.Items {
  58. val, ok := cm.Data[k.Key]
  59. out := make(map[string][]byte)
  60. if !ok {
  61. return fmt.Errorf(errTplCMMissingKey, tpl.ConfigMap.Name, k.Key)
  62. }
  63. switch k.TemplateAs {
  64. case esv1.TemplateScopeValues:
  65. out[k.Key] = []byte(val)
  66. case esv1.TemplateScopeKeysAndValues:
  67. out[val] = []byte(val)
  68. }
  69. err := p.Exec(out, p.DataMap, k.TemplateAs, tpl.Target, p.TargetSecret)
  70. if err != nil {
  71. return err
  72. }
  73. }
  74. return nil
  75. }
  76. func (p *Parser) MergeSecret(ctx context.Context, namespace string, tpl esv1.TemplateFrom) error {
  77. if tpl.Secret == nil {
  78. return nil
  79. }
  80. var sec v1.Secret
  81. if p.TemplateFromSecret != nil {
  82. sec = *p.TemplateFromSecret
  83. } else {
  84. err := p.Client.Get(ctx, types.NamespacedName{
  85. Name: tpl.Secret.Name,
  86. Namespace: namespace,
  87. }, &sec)
  88. if err != nil {
  89. return err
  90. }
  91. }
  92. for _, k := range tpl.Secret.Items {
  93. val, ok := sec.Data[k.Key]
  94. if !ok {
  95. return fmt.Errorf(errTplSecMissingKey, tpl.Secret.Name, k.Key)
  96. }
  97. out := make(map[string][]byte)
  98. switch k.TemplateAs {
  99. case esv1.TemplateScopeValues:
  100. out[k.Key] = val
  101. case esv1.TemplateScopeKeysAndValues:
  102. out[string(val)] = val
  103. }
  104. err := p.Exec(out, p.DataMap, k.TemplateAs, tpl.Target, p.TargetSecret)
  105. if err != nil {
  106. return err
  107. }
  108. }
  109. return nil
  110. }
  111. func (p *Parser) MergeLiteral(_ context.Context, tpl esv1.TemplateFrom) error {
  112. if tpl.Literal == nil {
  113. return nil
  114. }
  115. out := make(map[string][]byte)
  116. out[*tpl.Literal] = []byte(*tpl.Literal)
  117. return p.Exec(out, p.DataMap, esv1.TemplateScopeKeysAndValues, tpl.Target, p.TargetSecret)
  118. }
  119. func (p *Parser) MergeTemplateFrom(ctx context.Context, namespace string, template *esv1.ExternalSecretTemplate) error {
  120. if template == nil {
  121. return nil
  122. }
  123. for _, tpl := range template.TemplateFrom {
  124. err := p.MergeConfigMap(ctx, namespace, tpl)
  125. if err != nil {
  126. return err
  127. }
  128. err = p.MergeSecret(ctx, namespace, tpl)
  129. if err != nil {
  130. return err
  131. }
  132. err = p.MergeLiteral(ctx, tpl)
  133. if err != nil {
  134. return err
  135. }
  136. }
  137. return nil
  138. }
  139. func (p *Parser) MergeMap(tplMap map[string]string, target esv1.TemplateTarget) error {
  140. byteMap := make(map[string][]byte)
  141. for k, v := range tplMap {
  142. byteMap[k] = []byte(v)
  143. }
  144. err := p.Exec(byteMap, p.DataMap, esv1.TemplateScopeValues, target, p.TargetSecret)
  145. if err != nil {
  146. return fmt.Errorf(errExecTpl, err)
  147. }
  148. return nil
  149. }
  150. func GetManagedAnnotationKeys(secret *v1.Secret, fieldOwner string) ([]string, error) {
  151. return getManagedFieldKeys(secret, fieldOwner, func(fields map[string]any) []string {
  152. metadataFields, exists := fields["f:metadata"]
  153. if !exists {
  154. return nil
  155. }
  156. mf, ok := metadataFields.(map[string]any)
  157. if !ok {
  158. return nil
  159. }
  160. annotationFields, exists := mf["f:annotations"]
  161. if !exists {
  162. return nil
  163. }
  164. af, ok := annotationFields.(map[string]any)
  165. if !ok {
  166. return nil
  167. }
  168. var keys []string
  169. for k := range af {
  170. keys = append(keys, k)
  171. }
  172. return keys
  173. })
  174. }
  175. func GetManagedLabelKeys(secret *v1.Secret, fieldOwner string) ([]string, error) {
  176. return getManagedFieldKeys(secret, fieldOwner, func(fields map[string]any) []string {
  177. metadataFields, exists := fields["f:metadata"]
  178. if !exists {
  179. return nil
  180. }
  181. mf, ok := metadataFields.(map[string]any)
  182. if !ok {
  183. return nil
  184. }
  185. labelFields, exists := mf["f:labels"]
  186. if !exists {
  187. return nil
  188. }
  189. lf, ok := labelFields.(map[string]any)
  190. if !ok {
  191. return nil
  192. }
  193. var keys []string
  194. for k := range lf {
  195. keys = append(keys, k)
  196. }
  197. return keys
  198. })
  199. }
  200. func getManagedFieldKeys(
  201. secret *v1.Secret,
  202. fieldOwner string,
  203. process func(fields map[string]any) []string,
  204. ) ([]string, error) {
  205. // If secret name is just too big, use the SHA3 hash of the secret name
  206. // Done this way for backwards compatibility thus avoiding breaking changes
  207. fqdn := fmt.Sprintf(fieldOwnerTemplate, fieldOwner)
  208. if len(fieldOwner) > 63 {
  209. fqdn = fmt.Sprintf(fieldOwnerTemplateSha, sha3.Sum224([]byte(fieldOwner)))
  210. }
  211. var keys []string
  212. for _, v := range secret.ObjectMeta.ManagedFields {
  213. if v.Manager != fqdn {
  214. continue
  215. }
  216. fields := make(map[string]any)
  217. err := json.Unmarshal(v.FieldsV1.Raw, &fields)
  218. if err != nil {
  219. return nil, fmt.Errorf("error unmarshaling managed fields: %w", err)
  220. }
  221. for _, key := range process(fields) {
  222. if key == "." {
  223. continue
  224. }
  225. keys = append(keys, strings.TrimPrefix(key, "f:"))
  226. }
  227. }
  228. return keys, nil
  229. }