secrets_client.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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 mysterybox
  14. import (
  15. "context"
  16. "encoding/json"
  17. "errors"
  18. "fmt"
  19. "google.golang.org/grpc/codes"
  20. "google.golang.org/grpc/status"
  21. corev1 "k8s.io/api/core/v1"
  22. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  23. "github.com/external-secrets/external-secrets/providers/v1/nebius/common/sdk/mysterybox"
  24. "github.com/external-secrets/external-secrets/runtime/constants"
  25. "github.com/external-secrets/external-secrets/runtime/metrics"
  26. )
  27. const (
  28. errNotImplemented = "not implemented"
  29. errJSONMarshal = "failed to marshal JSON"
  30. errSecretNotFound = "secret %q not found: %w"
  31. errSecretByKeyNotFound = "key %q not found in secret %q: %w"
  32. errSecretVersionByKeyNotFound = "version %q of secret %q not found by key %q: %w"
  33. errSecretVersionNotFound = "version %q of secret %q not found: %w"
  34. )
  35. // SecretsClient provides methods to interact with secrets in the Mysterybox service.
  36. // It wraps a mysterybox.Client instance and uses a token for authentication.
  37. type SecretsClient struct {
  38. mysteryboxClient mysterybox.Client
  39. token string
  40. }
  41. // GetSecret retrieves the value of a secret from Mysterybox based on the provided reference.
  42. func (c *SecretsClient) GetSecret(ctx context.Context, ref esv1.ExternalSecretDataRemoteRef) ([]byte, error) {
  43. secretKey := ref.Property
  44. if secretKey == "" {
  45. payload, err := c.mysteryboxClient.GetSecret(ctx, c.token, ref.Key, ref.Version)
  46. metrics.ObserveAPICall(constants.ProviderNebiusMysterybox, constants.CallNebiusMysteryboxGetSecret, err)
  47. if err != nil {
  48. return nil, handleGetSecretError(err, ref)
  49. }
  50. keyToValue := make(map[string]any, len(payload.Entries))
  51. for _, entry := range payload.Entries {
  52. value := getValue(&entry)
  53. keyToValue[entry.Key] = value
  54. }
  55. out, err := json.Marshal(keyToValue)
  56. if err != nil {
  57. return nil, errors.New(errJSONMarshal)
  58. }
  59. return out, nil
  60. }
  61. payloadEntry, err := c.mysteryboxClient.GetSecretByKey(ctx, c.token, ref.Key, ref.Version, secretKey)
  62. metrics.ObserveAPICall(constants.ProviderNebiusMysterybox, constants.CallNebiusMysteryboxGetSecretByKey, err)
  63. if err != nil {
  64. return nil, handleGetSecretByKeyError(err, ref)
  65. }
  66. return getValueAsBinary(&payloadEntry.Entry), nil
  67. }
  68. // GetSecretMap retrieves a map of secret key-value pairs from Mysterybox using the provided reference.
  69. func (c *SecretsClient) GetSecretMap(ctx context.Context, ref esv1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  70. payload, err := c.mysteryboxClient.GetSecret(ctx, c.token, ref.Key, ref.Version)
  71. metrics.ObserveAPICall(constants.ProviderNebiusMysterybox, constants.CallNebiusMysteryboxGetSecret, err)
  72. if err != nil {
  73. return nil, handleGetSecretError(err, ref)
  74. }
  75. secretMap := make(map[string][]byte, len(payload.Entries))
  76. for _, entry := range payload.Entries {
  77. value := getValueAsBinary(&entry)
  78. secretMap[entry.Key] = value
  79. }
  80. return secretMap, nil
  81. }
  82. // DeleteSecret not implemented for Nebius Mysterybox provider.
  83. func (c *SecretsClient) DeleteSecret(_ context.Context, _ esv1.PushSecretRemoteRef) error {
  84. return errors.New(errNotImplemented)
  85. }
  86. // SecretExists not implemented for Nebius Mysterybox provider.
  87. func (c *SecretsClient) SecretExists(_ context.Context, _ esv1.PushSecretRemoteRef) (bool, error) {
  88. return false, errors.New(errNotImplemented)
  89. }
  90. // PushSecret not implemented for Nebius Mysterybox provider.
  91. func (c *SecretsClient) PushSecret(_ context.Context, _ *corev1.Secret, _ esv1.PushSecretData) error {
  92. return errors.New(errNotImplemented)
  93. }
  94. // Validate checks the configuration of the SecretsClient and returns its validation result.
  95. func (c *SecretsClient) Validate() (esv1.ValidationResult, error) {
  96. return esv1.ValidationResultReady, nil
  97. }
  98. // GetAllSecrets not implemented for Nebius Mysterybox provider.
  99. func (c *SecretsClient) GetAllSecrets(_ context.Context, _ esv1.ExternalSecretFind) (map[string][]byte, error) {
  100. return nil, errors.New(errNotImplemented)
  101. }
  102. // Close cleans up resources when the provider is done being used.
  103. func (c *SecretsClient) Close(_ context.Context) error {
  104. return nil
  105. }
  106. func getValueAsBinary(entry *mysterybox.Entry) []byte {
  107. if entry.BinaryValue != nil {
  108. return entry.BinaryValue
  109. }
  110. return []byte(entry.StringValue)
  111. }
  112. func getValue(entry *mysterybox.Entry) any {
  113. if entry.BinaryValue != nil {
  114. return entry.BinaryValue
  115. }
  116. return entry.StringValue
  117. }
  118. func handleGetSecretError(err error, ref esv1.ExternalSecretDataRemoteRef) error {
  119. if err == nil {
  120. return nil
  121. }
  122. st, ok := status.FromError(err)
  123. if !ok {
  124. return err // not a grpc error
  125. }
  126. if st.Code() == codes.NotFound {
  127. if ref.Version != "" {
  128. return fmt.Errorf(errSecretVersionNotFound, ref.Version, ref.Key, esv1.NoSecretErr)
  129. }
  130. return fmt.Errorf(errSecretNotFound, ref.Key, esv1.NoSecretErr)
  131. }
  132. return MapGrpcErrors("get secret", err)
  133. }
  134. func handleGetSecretByKeyError(err error, ref esv1.ExternalSecretDataRemoteRef) error {
  135. if err == nil {
  136. return nil
  137. }
  138. st, ok := status.FromError(err)
  139. if !ok {
  140. return err // not a grpc error
  141. }
  142. if st.Code() == codes.NotFound {
  143. if ref.Version != "" {
  144. return fmt.Errorf(errSecretVersionByKeyNotFound, ref.Version, ref.Key, ref.Property, esv1.NoSecretErr)
  145. }
  146. return fmt.Errorf(errSecretByKeyNotFound, ref.Property, ref.Key, esv1.NoSecretErr)
  147. }
  148. return MapGrpcErrors("get secret by key", err)
  149. }
  150. var _ esv1.SecretsClient = &SecretsClient{}