client.go 6.5 KB

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