client.go 3.9 KB

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