parser.go 7.1 KB

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