client.go 7.4 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 onboardbase
  13. import (
  14. "context"
  15. "encoding/json"
  16. "fmt"
  17. "net/url"
  18. "strings"
  19. "time"
  20. "github.com/tidwall/gjson"
  21. corev1 "k8s.io/api/core/v1"
  22. "k8s.io/apimachinery/pkg/types"
  23. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  24. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  25. "github.com/external-secrets/external-secrets/pkg/find"
  26. onboardbaseClient "github.com/external-secrets/external-secrets/pkg/provider/onboardbase/client"
  27. "github.com/external-secrets/external-secrets/pkg/utils"
  28. )
  29. const (
  30. errGetSecret = "could not get secret %s: %s"
  31. errGetSecrets = "could not get secrets %s"
  32. errUnmarshalSecretMap = "unable to unmarshal secret %s: %w"
  33. errOnboardbaseAPIKeySecretName = "missing auth.secretRef.onboardbaseAPIKey.name"
  34. errInvalidClusterStoreMissingOnboardbaseAPIKeyNamespace = "missing auth.secretRef.onboardbaseAPIKey.namespace"
  35. errFetchOnboardbaseAPIKeySecret = "unable to find find OnboardbaseAPIKey secret: %w"
  36. errMissingOnboardbaseAPIKey = "auth.secretRef.onboardbaseAPIKey.key '%s' not found in secret '%s'"
  37. errMissingOnboardbasePasscode = "auth.secretRef.onboardbasePasscode.key '%s' not found in secret '%s'"
  38. errSecretKeyFmt = "cannot find property %s in secret data for key: %q"
  39. )
  40. type Client struct {
  41. onboardbase SecretsClientInterface
  42. onboardbaseAPIKey string
  43. onboardbasePasscode string
  44. project string
  45. environment string
  46. kube kclient.Client
  47. store *esv1beta1.OnboardbaseProvider
  48. namespace string
  49. storeKind string
  50. }
  51. // SecretsClientInterface defines the required Onboardbase Client methods.
  52. type SecretsClientInterface interface {
  53. BaseURL() *url.URL
  54. Authenticate() error
  55. GetSecret(request onboardbaseClient.SecretRequest) (*onboardbaseClient.SecretResponse, error)
  56. DeleteSecret(request onboardbaseClient.SecretRequest) error
  57. GetSecrets(request onboardbaseClient.SecretsRequest) (*onboardbaseClient.SecretsResponse, error)
  58. }
  59. func (c *Client) setAuth(ctx context.Context) error {
  60. credentialsSecret := &corev1.Secret{}
  61. credentialsSecretName := c.store.Auth.OnboardbaseAPIKeyRef.Name
  62. if credentialsSecretName == "" {
  63. return fmt.Errorf(errOnboardbaseAPIKeySecretName)
  64. }
  65. objectKey := types.NamespacedName{
  66. Name: credentialsSecretName,
  67. Namespace: c.namespace,
  68. }
  69. // only ClusterStore is allowed to set namespace (and then it's required)
  70. if c.storeKind == esv1beta1.ClusterSecretStoreKind {
  71. if c.store.Auth.OnboardbaseAPIKeyRef.Namespace == nil {
  72. return fmt.Errorf(errInvalidClusterStoreMissingOnboardbaseAPIKeyNamespace)
  73. }
  74. objectKey.Namespace = *c.store.Auth.OnboardbaseAPIKeyRef.Namespace
  75. }
  76. err := c.kube.Get(ctx, objectKey, credentialsSecret)
  77. if err != nil {
  78. return fmt.Errorf(errFetchOnboardbaseAPIKeySecret, err)
  79. }
  80. onboardbaseAPIKey := credentialsSecret.Data[c.store.Auth.OnboardbaseAPIKeyRef.Key]
  81. if (onboardbaseAPIKey == nil) || (len(onboardbaseAPIKey) == 0) {
  82. return fmt.Errorf(errMissingOnboardbaseAPIKey, c.store.Auth.OnboardbaseAPIKeyRef.Key, credentialsSecretName)
  83. }
  84. c.onboardbaseAPIKey = string(onboardbaseAPIKey)
  85. onboardbasePasscode := credentialsSecret.Data[c.store.Auth.OnboardbasePasscodeRef.Key]
  86. if (onboardbasePasscode == nil) || (len(onboardbasePasscode) == 0) {
  87. return fmt.Errorf(errMissingOnboardbasePasscode, c.store.Auth.OnboardbasePasscodeRef.Key, credentialsSecretName)
  88. }
  89. c.onboardbasePasscode = string(onboardbasePasscode)
  90. return nil
  91. }
  92. func (c *Client) Validate() (esv1beta1.ValidationResult, error) {
  93. timeout := 15 * time.Second
  94. clientURL := c.onboardbase.BaseURL().String()
  95. if err := utils.NetworkValidate(clientURL, timeout); err != nil {
  96. return esv1beta1.ValidationResultError, err
  97. }
  98. if err := c.onboardbase.Authenticate(); err != nil {
  99. return esv1beta1.ValidationResultError, err
  100. }
  101. return esv1beta1.ValidationResultReady, nil
  102. }
  103. func (c *Client) DeleteSecret(_ context.Context, _ esv1beta1.PushSecretRemoteRef) error {
  104. // not implemented
  105. return nil
  106. }
  107. func (c *Client) SecretExists(_ context.Context, _ esv1beta1.PushSecretRemoteRef) (bool, error) {
  108. // not implemented
  109. return false, nil
  110. }
  111. func (c *Client) PushSecret(_ context.Context, _ *corev1.Secret, _ esv1beta1.PushSecretData) error {
  112. // not implemented
  113. return nil
  114. }
  115. func (c *Client) GetSecret(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  116. request := onboardbaseClient.SecretRequest{
  117. Project: c.project,
  118. Environment: c.environment,
  119. Name: ref.Key,
  120. }
  121. secret, err := c.onboardbase.GetSecret(request)
  122. if err != nil {
  123. return nil, fmt.Errorf(errGetSecret, ref.Key, err)
  124. }
  125. value := secret.Value
  126. if ref.Property != "" {
  127. jsonRes := gjson.Get(secret.Value, ref.Property)
  128. if !jsonRes.Exists() {
  129. return nil, fmt.Errorf(errSecretKeyFmt, ref.Property, ref.Key)
  130. }
  131. value = jsonRes.Raw
  132. }
  133. return []byte(value), nil
  134. }
  135. func (c *Client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  136. data, err := c.GetSecret(ctx, ref)
  137. if err != nil {
  138. return nil, err
  139. }
  140. kv := make(map[string]json.RawMessage)
  141. err = json.Unmarshal(data, &kv)
  142. if err != nil {
  143. return nil, fmt.Errorf(errUnmarshalSecretMap, ref.Key, err)
  144. }
  145. secretData := make(map[string][]byte)
  146. for k, v := range kv {
  147. var strVal string
  148. err = json.Unmarshal(v, &strVal)
  149. if err == nil {
  150. secretData[k] = []byte(strVal)
  151. } else {
  152. secretData[k] = v
  153. }
  154. }
  155. return secretData, nil
  156. }
  157. func (c *Client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  158. if len(ref.Tags) > 0 {
  159. return nil, fmt.Errorf("find by tags not supported")
  160. }
  161. secrets, err := c.getSecrets(ctx)
  162. if err != nil {
  163. return nil, err
  164. }
  165. if ref.Name == nil && ref.Path == nil {
  166. return secrets, nil
  167. }
  168. var matcher *find.Matcher
  169. if ref.Name != nil {
  170. m, err := find.New(*ref.Name)
  171. if err != nil {
  172. return nil, err
  173. }
  174. matcher = m
  175. }
  176. selected := map[string][]byte{}
  177. for key, value := range secrets {
  178. if (matcher != nil && !matcher.MatchName(key)) || (ref.Path != nil && !strings.HasPrefix(key, *ref.Path)) {
  179. continue
  180. }
  181. selected[key] = value
  182. }
  183. return selected, nil
  184. }
  185. func (c *Client) Close(_ context.Context) error {
  186. return nil
  187. }
  188. func (c *Client) getSecrets(_ context.Context) (map[string][]byte, error) {
  189. request := onboardbaseClient.SecretsRequest{
  190. Project: c.project,
  191. Environment: c.environment,
  192. }
  193. response, err := c.onboardbase.GetSecrets(request)
  194. if err != nil {
  195. return nil, fmt.Errorf(errGetSecrets, err)
  196. }
  197. return externalSecretsFormat(response.Secrets), nil
  198. }
  199. func externalSecretsFormat(secrets onboardbaseClient.Secrets) map[string][]byte {
  200. converted := make(map[string][]byte, len(secrets))
  201. for key, value := range secrets {
  202. converted[key] = []byte(value)
  203. }
  204. return converted
  205. }