client.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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 implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package conjur
  13. import (
  14. "context"
  15. "fmt"
  16. "strings"
  17. "github.com/cyberark/conjur-api-go/conjurapi"
  18. "github.com/cyberark/conjur-api-go/conjurapi/authn"
  19. corev1 "k8s.io/api/core/v1"
  20. typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  21. "sigs.k8s.io/controller-runtime/pkg/client"
  22. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  23. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  24. "github.com/external-secrets/external-secrets/pkg/provider/conjur/util"
  25. "github.com/external-secrets/external-secrets/pkg/utils"
  26. "github.com/external-secrets/external-secrets/pkg/utils/resolvers"
  27. )
  28. var (
  29. errConjurClient = "cannot setup new Conjur client: %w"
  30. errBadCertBundle = "caBundle failed to base64 decode: %w"
  31. errBadServiceUser = "could not get Auth.Apikey.UserRef: %w"
  32. errBadServiceAPIKey = "could not get Auth.Apikey.ApiKeyRef: %w"
  33. errGetKubeSATokenRequest = "cannot request Kubernetes service account token for service account %q: %w"
  34. errUnableToFetchCAProviderCM = "unable to fetch Server.CAProvider ConfigMap: %w"
  35. errUnableToFetchCAProviderSecret = "unable to fetch Server.CAProvider Secret: %w"
  36. errSecretKeyFmt = "cannot find secret data for key: %q"
  37. )
  38. // Client is a provider for Conjur.
  39. type Client struct {
  40. StoreKind string
  41. kube client.Client
  42. store esv1beta1.GenericStore
  43. namespace string
  44. corev1 typedcorev1.CoreV1Interface
  45. clientAPI SecretsClientFactory
  46. client SecretsClient
  47. }
  48. func (c *Client) GetConjurClient(ctx context.Context) (SecretsClient, error) {
  49. // if the client is initialized already, return it
  50. if c.client != nil {
  51. return c.client, nil
  52. }
  53. prov, err := util.GetConjurProvider(c.store)
  54. if err != nil {
  55. return nil, err
  56. }
  57. cert, getCertErr := c.getCA(ctx, prov)
  58. if getCertErr != nil {
  59. return nil, getCertErr
  60. }
  61. config := conjurapi.Config{
  62. ApplianceURL: prov.URL,
  63. SSLCert: cert,
  64. }
  65. if prov.Auth.APIKey != nil {
  66. config.Account = prov.Auth.APIKey.Account
  67. conjUser, secErr := resolvers.SecretKeyRef(
  68. ctx,
  69. c.kube,
  70. c.StoreKind,
  71. c.namespace, prov.Auth.APIKey.UserRef)
  72. if secErr != nil {
  73. return nil, fmt.Errorf(errBadServiceUser, secErr)
  74. }
  75. conjAPIKey, secErr := resolvers.SecretKeyRef(
  76. ctx,
  77. c.kube,
  78. c.StoreKind,
  79. c.namespace,
  80. prov.Auth.APIKey.APIKeyRef)
  81. if secErr != nil {
  82. return nil, fmt.Errorf(errBadServiceAPIKey, secErr)
  83. }
  84. conjur, newClientFromKeyError := c.clientAPI.NewClientFromKey(config,
  85. authn.LoginPair{
  86. Login: conjUser,
  87. APIKey: conjAPIKey,
  88. },
  89. )
  90. if newClientFromKeyError != nil {
  91. return nil, fmt.Errorf(errConjurClient, newClientFromKeyError)
  92. }
  93. c.client = conjur
  94. return conjur, nil
  95. } else if prov.Auth.Jwt != nil {
  96. config.Account = prov.Auth.Jwt.Account
  97. conjur, clientFromJwtError := c.newClientFromJwt(ctx, config, prov.Auth.Jwt)
  98. if clientFromJwtError != nil {
  99. return nil, fmt.Errorf(errConjurClient, clientFromJwtError)
  100. }
  101. c.client = conjur
  102. return conjur, nil
  103. } else {
  104. // Should not happen because validate func should catch this
  105. return nil, fmt.Errorf("no authentication method provided")
  106. }
  107. }
  108. // PushSecret will write a single secret into the provider.
  109. func (c *Client) PushSecret(_ context.Context, _ *corev1.Secret, _ esv1beta1.PushSecretData) error {
  110. // NOT IMPLEMENTED
  111. return nil
  112. }
  113. func (c *Client) DeleteSecret(_ context.Context, _ esv1beta1.PushSecretRemoteRef) error {
  114. // NOT IMPLEMENTED
  115. return nil
  116. }
  117. func (c *Client) SecretExists(_ context.Context, _ esv1beta1.PushSecretRemoteRef) (bool, error) {
  118. return false, fmt.Errorf("not implemented")
  119. }
  120. // Validate validates the provider.
  121. func (c *Client) Validate() (esv1beta1.ValidationResult, error) {
  122. return esv1beta1.ValidationResultReady, nil
  123. }
  124. // Close closes the provider.
  125. func (c *Client) Close(_ context.Context) error {
  126. return nil
  127. }
  128. // configMapKeyRef returns the value of a key in a ConfigMap.
  129. func (c *Client) configMapKeyRef(ctx context.Context, cmRef *esmeta.SecretKeySelector) (string, error) {
  130. configMap := &corev1.ConfigMap{}
  131. ref := client.ObjectKey{
  132. Namespace: c.namespace,
  133. Name: cmRef.Name,
  134. }
  135. if (c.StoreKind == esv1beta1.ClusterSecretStoreKind) &&
  136. (cmRef.Namespace != nil) {
  137. ref.Namespace = *cmRef.Namespace
  138. }
  139. err := c.kube.Get(ctx, ref, configMap)
  140. if err != nil {
  141. return "", err
  142. }
  143. keyBytes, ok := configMap.Data[cmRef.Key]
  144. if !ok {
  145. return "", err
  146. }
  147. valueStr := strings.TrimSpace(keyBytes)
  148. return valueStr, nil
  149. }
  150. // getCA try retrieve the CA bundle from the provider CABundle or from the CAProvider.
  151. func (c *Client) getCA(ctx context.Context, provider *esv1beta1.ConjurProvider) (string, error) {
  152. if provider.CAProvider != nil {
  153. var ca string
  154. var err error
  155. switch provider.CAProvider.Type {
  156. case esv1beta1.CAProviderTypeConfigMap:
  157. keySelector := esmeta.SecretKeySelector{
  158. Name: provider.CAProvider.Name,
  159. Namespace: provider.CAProvider.Namespace,
  160. Key: provider.CAProvider.Key,
  161. }
  162. ca, err = c.configMapKeyRef(ctx, &keySelector)
  163. if err != nil {
  164. return "", fmt.Errorf(errUnableToFetchCAProviderCM, err)
  165. }
  166. case esv1beta1.CAProviderTypeSecret:
  167. keySelector := esmeta.SecretKeySelector{
  168. Name: provider.CAProvider.Name,
  169. Namespace: provider.CAProvider.Namespace,
  170. Key: provider.CAProvider.Key,
  171. }
  172. ca, err = resolvers.SecretKeyRef(
  173. ctx,
  174. c.kube,
  175. c.StoreKind,
  176. c.namespace,
  177. &keySelector)
  178. if err != nil {
  179. return "", fmt.Errorf(errUnableToFetchCAProviderSecret, err)
  180. }
  181. }
  182. return ca, nil
  183. }
  184. certBytes, decodeErr := utils.Decode(esv1beta1.ExternalSecretDecodeBase64, []byte(provider.CABundle))
  185. if decodeErr != nil {
  186. return "", fmt.Errorf(errBadCertBundle, decodeErr)
  187. }
  188. return string(certBytes), nil
  189. }