client.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. Copyright © 2025 ESO Maintainer Team
  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 vault
  14. import (
  15. "context"
  16. "crypto/tls"
  17. "crypto/x509"
  18. "errors"
  19. "fmt"
  20. "net/http"
  21. "github.com/go-logr/logr"
  22. vault "github.com/hashicorp/vault/api"
  23. corev1 "k8s.io/api/core/v1"
  24. typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  25. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  26. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  27. vaultutil "github.com/external-secrets/external-secrets/providers/v1/vault/util"
  28. "github.com/external-secrets/external-secrets/runtime/esutils"
  29. "github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
  30. )
  31. var _ esv1.SecretsClient = &client{}
  32. type client struct {
  33. kube kclient.Client
  34. store *esv1.VaultProvider
  35. log logr.Logger
  36. corev1 typedcorev1.CoreV1Interface
  37. client vaultutil.Client
  38. auth vaultutil.Auth
  39. logical vaultutil.Logical
  40. token vaultutil.Token
  41. namespace string
  42. storeKind string
  43. }
  44. func (c *client) newConfig(ctx context.Context) (*vault.Config, error) {
  45. cfg := vault.DefaultConfig()
  46. cfg.Address = c.store.Server
  47. if len(c.store.CABundle) != 0 || c.store.CAProvider != nil {
  48. caCertPool := x509.NewCertPool()
  49. ca, err := esutils.FetchCACertFromSource(ctx, esutils.CreateCertOpts{
  50. CABundle: c.store.CABundle,
  51. CAProvider: c.store.CAProvider,
  52. StoreKind: c.storeKind,
  53. Namespace: c.namespace,
  54. Client: c.kube,
  55. })
  56. if err != nil {
  57. return nil, err
  58. }
  59. ok := caCertPool.AppendCertsFromPEM(ca)
  60. if !ok {
  61. return nil, fmt.Errorf(errVaultCert, errors.New("failed to parse certificates from CertPool"))
  62. }
  63. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  64. transport.TLSClientConfig.RootCAs = caCertPool
  65. }
  66. }
  67. err := c.configureClientTLS(ctx, cfg)
  68. if err != nil {
  69. return nil, err
  70. }
  71. // If either read-after-write consistency feature is enabled, enable ReadYourWrites
  72. cfg.ReadYourWrites = c.store.ReadYourWrites || c.store.ForwardInconsistent
  73. return cfg, nil
  74. }
  75. func (c *client) configureClientTLS(ctx context.Context, cfg *vault.Config) error {
  76. clientTLS := c.store.ClientTLS
  77. if clientTLS.CertSecretRef != nil && clientTLS.KeySecretRef != nil {
  78. if clientTLS.KeySecretRef.Key == "" {
  79. clientTLS.KeySecretRef.Key = corev1.TLSPrivateKeyKey
  80. }
  81. clientKey, err := resolvers.SecretKeyRef(ctx, c.kube, c.storeKind, c.namespace, clientTLS.KeySecretRef)
  82. if err != nil {
  83. return err
  84. }
  85. if clientTLS.CertSecretRef.Key == "" {
  86. clientTLS.CertSecretRef.Key = corev1.TLSCertKey
  87. }
  88. clientCert, err := resolvers.SecretKeyRef(ctx, c.kube, c.storeKind, c.namespace, clientTLS.CertSecretRef)
  89. if err != nil {
  90. return err
  91. }
  92. cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
  93. if err != nil {
  94. return fmt.Errorf(errClientTLSAuth, err)
  95. }
  96. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  97. transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
  98. }
  99. }
  100. return nil
  101. }
  102. func (c *client) Close(ctx context.Context) error {
  103. // Revoke the token if we have one set, it wasn't sourced from a TokenSecretRef,
  104. // and token caching isn't enabled
  105. if !enableCache && c.client.Token() != "" && c.store.Auth != nil && c.store.Auth.TokenSecretRef == nil {
  106. err := revokeTokenIfValid(ctx, c.client)
  107. if err != nil {
  108. return err
  109. }
  110. }
  111. return nil
  112. }