client.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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 impliec.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package doppler
  13. import (
  14. "context"
  15. "encoding/json"
  16. "fmt"
  17. "net/url"
  18. "strings"
  19. "time"
  20. corev1 "k8s.io/api/core/v1"
  21. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  22. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  23. "github.com/external-secrets/external-secrets/pkg/find"
  24. dClient "github.com/external-secrets/external-secrets/pkg/provider/doppler/client"
  25. "github.com/external-secrets/external-secrets/pkg/utils"
  26. "github.com/external-secrets/external-secrets/pkg/utils/resolvers"
  27. )
  28. const (
  29. customBaseURLEnvVar = "DOPPLER_BASE_URL"
  30. verifyTLSOverrideEnvVar = "DOPPLER_VERIFY_TLS"
  31. errGetSecret = "could not get secret %s: %w"
  32. errGetSecrets = "could not get secrets %w"
  33. errDeleteSecrets = "could not delete secrets %s: %w"
  34. errPushSecrets = "could not push secrets %s: %w"
  35. errUnmarshalSecretMap = "unable to unmarshal secret %s: %w"
  36. secretsDownloadFileKey = "DOPPLER_SECRETS_FILE"
  37. errDopplerTokenSecretName = "missing auth.secretRef.dopplerToken.name"
  38. errInvalidClusterStoreMissingDopplerTokenNamespace = "missing auth.secretRef.dopplerToken.namespace"
  39. )
  40. type Client struct {
  41. doppler SecretsClientInterface
  42. dopplerToken string
  43. project string
  44. config string
  45. nameTransformer string
  46. format string
  47. kube kclient.Client
  48. store *esv1beta1.DopplerProvider
  49. namespace string
  50. storeKind string
  51. }
  52. // SecretsClientInterface defines the required Doppler Client methods.
  53. type SecretsClientInterface interface {
  54. BaseURL() *url.URL
  55. Authenticate() error
  56. GetSecret(request dClient.SecretRequest) (*dClient.SecretResponse, error)
  57. GetSecrets(request dClient.SecretsRequest) (*dClient.SecretsResponse, error)
  58. UpdateSecrets(request dClient.UpdateSecretsRequest) error
  59. }
  60. func (c *Client) setAuth(ctx context.Context) error {
  61. token, err := resolvers.SecretKeyRef(
  62. ctx,
  63. c.kube,
  64. c.storeKind,
  65. c.namespace,
  66. &c.store.Auth.SecretRef.DopplerToken)
  67. if err != nil {
  68. return err
  69. }
  70. c.dopplerToken = token
  71. return nil
  72. }
  73. func (c *Client) Validate() (esv1beta1.ValidationResult, error) {
  74. timeout := 15 * time.Second
  75. clientURL := c.doppler.BaseURL().String()
  76. if err := utils.NetworkValidate(clientURL, timeout); err != nil {
  77. return esv1beta1.ValidationResultError, err
  78. }
  79. if err := c.doppler.Authenticate(); err != nil {
  80. return esv1beta1.ValidationResultError, err
  81. }
  82. return esv1beta1.ValidationResultReady, nil
  83. }
  84. func (c *Client) DeleteSecret(_ context.Context, ref esv1beta1.PushSecretRemoteRef) error {
  85. request := dClient.UpdateSecretsRequest{
  86. ChangeRequests: []dClient.Change{
  87. {
  88. Name: ref.GetRemoteKey(),
  89. OriginalName: ref.GetRemoteKey(),
  90. ShouldDelete: true,
  91. },
  92. },
  93. Project: c.project,
  94. Config: c.config,
  95. }
  96. err := c.doppler.UpdateSecrets(request)
  97. if err != nil {
  98. return fmt.Errorf(errDeleteSecrets, ref.GetRemoteKey(), err)
  99. }
  100. return nil
  101. }
  102. func (c *Client) SecretExists(_ context.Context, _ esv1beta1.PushSecretRemoteRef) (bool, error) {
  103. return false, fmt.Errorf("not implemented")
  104. }
  105. func (c *Client) PushSecret(_ context.Context, secret *corev1.Secret, data esv1beta1.PushSecretData) error {
  106. value := secret.Data[data.GetSecretKey()]
  107. request := dClient.UpdateSecretsRequest{
  108. Secrets: dClient.Secrets{
  109. data.GetRemoteKey(): string(value),
  110. },
  111. Project: c.project,
  112. Config: c.config,
  113. }
  114. err := c.doppler.UpdateSecrets(request)
  115. if err != nil {
  116. return fmt.Errorf(errPushSecrets, data.GetRemoteKey(), err)
  117. }
  118. return nil
  119. }
  120. func (c *Client) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  121. request := dClient.SecretRequest{
  122. Name: ref.Key,
  123. Project: c.project,
  124. Config: c.config,
  125. }
  126. secret, err := c.doppler.GetSecret(request)
  127. if err != nil {
  128. return nil, fmt.Errorf(errGetSecret, ref.Key, err)
  129. }
  130. return []byte(secret.Value), nil
  131. }
  132. func (c *Client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  133. data, err := c.GetSecret(ctx, ref)
  134. if err != nil {
  135. return nil, err
  136. }
  137. kv := make(map[string]json.RawMessage)
  138. err = json.Unmarshal(data, &kv)
  139. if err != nil {
  140. return nil, fmt.Errorf(errUnmarshalSecretMap, ref.Key, err)
  141. }
  142. secretData := make(map[string][]byte)
  143. for k, v := range kv {
  144. var strVal string
  145. err = json.Unmarshal(v, &strVal)
  146. if err == nil {
  147. secretData[k] = []byte(strVal)
  148. } else {
  149. secretData[k] = v
  150. }
  151. }
  152. return secretData, nil
  153. }
  154. func (c *Client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  155. secrets, err := c.getSecrets(ctx)
  156. selected := map[string][]byte{}
  157. if err != nil {
  158. return nil, err
  159. }
  160. if ref.Name == nil && ref.Path == nil {
  161. return secrets, nil
  162. }
  163. var matcher *find.Matcher
  164. if ref.Name != nil {
  165. m, err := find.New(*ref.Name)
  166. if err != nil {
  167. return nil, err
  168. }
  169. matcher = m
  170. }
  171. for key, value := range secrets {
  172. if (matcher != nil && !matcher.MatchName(key)) || (ref.Path != nil && !strings.HasPrefix(key, *ref.Path)) {
  173. continue
  174. }
  175. selected[key] = value
  176. }
  177. return selected, nil
  178. }
  179. func (c *Client) Close(_ context.Context) error {
  180. return nil
  181. }
  182. func (c *Client) getSecrets(_ context.Context) (map[string][]byte, error) {
  183. request := dClient.SecretsRequest{
  184. Project: c.project,
  185. Config: c.config,
  186. NameTransformer: c.nameTransformer,
  187. Format: c.format,
  188. }
  189. response, err := c.doppler.GetSecrets(request)
  190. if err != nil {
  191. return nil, fmt.Errorf(errGetSecrets, err)
  192. }
  193. if c.format != "" {
  194. return map[string][]byte{
  195. secretsDownloadFileKey: response.Body,
  196. }, nil
  197. }
  198. return externalSecretsFormat(response.Secrets), nil
  199. }
  200. func externalSecretsFormat(secrets dClient.Secrets) map[string][]byte {
  201. converted := make(map[string][]byte, len(secrets))
  202. for key, value := range secrets {
  203. converted[key] = []byte(value)
  204. }
  205. return converted
  206. }