vault.go 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461
  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 vault
  13. import (
  14. "bytes"
  15. "context"
  16. "crypto/tls"
  17. "crypto/x509"
  18. "encoding/json"
  19. "errors"
  20. "fmt"
  21. "net/http"
  22. "os"
  23. "strconv"
  24. "strings"
  25. "github.com/go-logr/logr"
  26. vault "github.com/hashicorp/vault/api"
  27. approle "github.com/hashicorp/vault/api/auth/approle"
  28. authkubernetes "github.com/hashicorp/vault/api/auth/kubernetes"
  29. authldap "github.com/hashicorp/vault/api/auth/ldap"
  30. "github.com/spf13/pflag"
  31. "github.com/tidwall/gjson"
  32. authenticationv1 "k8s.io/api/authentication/v1"
  33. corev1 "k8s.io/api/core/v1"
  34. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  35. "k8s.io/apimachinery/pkg/types"
  36. "k8s.io/client-go/kubernetes"
  37. typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  38. ctrl "sigs.k8s.io/controller-runtime"
  39. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  40. ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
  41. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  42. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  43. "github.com/external-secrets/external-secrets/pkg/cache"
  44. "github.com/external-secrets/external-secrets/pkg/feature"
  45. "github.com/external-secrets/external-secrets/pkg/find"
  46. "github.com/external-secrets/external-secrets/pkg/provider/metrics"
  47. "github.com/external-secrets/external-secrets/pkg/utils"
  48. )
  49. var (
  50. _ esv1beta1.Provider = &connector{}
  51. _ esv1beta1.SecretsClient = &client{}
  52. enableCache bool
  53. logger = ctrl.Log.WithName("provider").WithName("vault")
  54. clientCache *cache.Cache[Client]
  55. )
  56. const (
  57. serviceAccTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
  58. errVaultStore = "received invalid Vault SecretStore resource: %w"
  59. errVaultCacheCreate = "cannot create Vault client cache: %s"
  60. errVaultCacheRemove = "error removing item from Vault client cache: %w"
  61. errVaultCacheEviction = "unexpected eviction from Vault client cache"
  62. errVaultClient = "cannot setup new vault client: %w"
  63. errVaultCert = "cannot set Vault CA certificate: %w"
  64. errReadSecret = "cannot read secret data from Vault: %w"
  65. errAuthFormat = "cannot initialize Vault client: no valid auth method specified"
  66. errInvalidCredentials = "invalid vault credentials: %w"
  67. errDataField = "failed to find data field"
  68. errJSONUnmarshall = "failed to unmarshall JSON"
  69. errPathInvalid = "provided Path isn't a valid kv v2 path"
  70. errSecretFormat = "secret data not in expected format"
  71. errUnexpectedKey = "unexpected key in data: %s"
  72. errVaultToken = "cannot parse Vault authentication token: %w"
  73. errVaultRequest = "error from Vault request: %w"
  74. errServiceAccount = "cannot read Kubernetes service account token from file system: %w"
  75. errJwtNoTokenSource = "neither `secretRef` nor `kubernetesServiceAccountToken` was supplied as token source for jwt authentication"
  76. errUnsupportedKvVersion = "cannot perform find operations with kv version v1"
  77. errUnsupportedMetadataKvVersion = "cannot perform metadata fetch operations with kv version v1"
  78. errNotFound = "secret not found"
  79. errGetKubeSA = "cannot get Kubernetes service account %q: %w"
  80. errGetKubeSASecrets = "cannot find secrets bound to service account: %q"
  81. errGetKubeSANoToken = "cannot find token in secrets bound to service account: %q"
  82. errGetKubeSATokenRequest = "cannot request Kubernetes service account token for service account %q: %w"
  83. errGetKubeSecret = "cannot get Kubernetes secret %q: %w"
  84. errSecretKeyFmt = "cannot find secret data for key: %q"
  85. errConfigMapFmt = "cannot find config map data for key: %q"
  86. errClientTLSAuth = "error from Client TLS Auth: %q"
  87. errVaultRevokeToken = "error while revoking token: %w"
  88. errUnknownCAProvider = "unknown caProvider type given"
  89. errCANamespace = "cannot read secret for CAProvider due to missing namespace on kind ClusterSecretStore"
  90. errInvalidStore = "invalid store"
  91. errInvalidStoreSpec = "invalid store spec"
  92. errInvalidStoreProv = "invalid store provider"
  93. errInvalidVaultProv = "invalid vault provider"
  94. errInvalidAppRoleSec = "invalid Auth.AppRole.SecretRef: %w"
  95. errInvalidClientCert = "invalid Auth.Cert.ClientCert: %w"
  96. errInvalidCertSec = "invalid Auth.Cert.SecretRef: %w"
  97. errInvalidJwtSec = "invalid Auth.Jwt.SecretRef: %w"
  98. errInvalidJwtK8sSA = "invalid Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef: %w"
  99. errInvalidKubeSA = "invalid Auth.Kubernetes.ServiceAccountRef: %w"
  100. errInvalidKubeSec = "invalid Auth.Kubernetes.SecretRef: %w"
  101. errInvalidLdapSec = "invalid Auth.Ldap.SecretRef: %w"
  102. errInvalidTokenRef = "invalid Auth.TokenSecretRef: %w"
  103. )
  104. // https://github.com/external-secrets/external-secrets/issues/644
  105. var _ esv1beta1.SecretsClient = &client{}
  106. var _ esv1beta1.Provider = &connector{}
  107. type Auth interface {
  108. Login(ctx context.Context, authMethod vault.AuthMethod) (*vault.Secret, error)
  109. }
  110. type Token interface {
  111. RevokeSelfWithContext(ctx context.Context, token string) error
  112. LookupSelfWithContext(ctx context.Context) (*vault.Secret, error)
  113. }
  114. type Logical interface {
  115. ReadWithDataWithContext(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error)
  116. ListWithContext(ctx context.Context, path string) (*vault.Secret, error)
  117. WriteWithContext(ctx context.Context, path string, data map[string]interface{}) (*vault.Secret, error)
  118. DeleteWithContext(ctx context.Context, path string) (*vault.Secret, error)
  119. }
  120. type Client interface {
  121. SetToken(v string)
  122. Token() string
  123. ClearToken()
  124. Auth() Auth
  125. Logical() Logical
  126. AuthToken() Token
  127. SetNamespace(namespace string)
  128. AddHeader(key, value string)
  129. }
  130. type VClient struct {
  131. setToken func(v string)
  132. token func() string
  133. clearToken func()
  134. auth Auth
  135. logical Logical
  136. authToken Token
  137. setNamespace func(namespace string)
  138. addHeader func(key, value string)
  139. }
  140. func (v VClient) AddHeader(key, value string) {
  141. v.addHeader(key, value)
  142. }
  143. func (v VClient) SetNamespace(namespace string) {
  144. v.setNamespace(namespace)
  145. }
  146. func (v VClient) ClearToken() {
  147. v.clearToken()
  148. }
  149. func (v VClient) Token() string {
  150. return v.token()
  151. }
  152. func (v VClient) SetToken(token string) {
  153. v.setToken(token)
  154. }
  155. func (v VClient) Auth() Auth {
  156. return v.auth
  157. }
  158. func (v VClient) AuthToken() Token {
  159. return v.authToken
  160. }
  161. func (v VClient) Logical() Logical {
  162. return v.logical
  163. }
  164. type client struct {
  165. kube kclient.Client
  166. store *esv1beta1.VaultProvider
  167. log logr.Logger
  168. corev1 typedcorev1.CoreV1Interface
  169. client Client
  170. auth Auth
  171. logical Logical
  172. token Token
  173. namespace string
  174. storeKind string
  175. }
  176. func newVaultClient(c *vault.Config) (Client, error) {
  177. cl, err := vault.NewClient(c)
  178. if err != nil {
  179. return nil, err
  180. }
  181. auth := cl.Auth()
  182. logical := cl.Logical()
  183. token := cl.Auth().Token()
  184. out := VClient{
  185. setToken: cl.SetToken,
  186. token: cl.Token,
  187. clearToken: cl.ClearToken,
  188. auth: auth,
  189. authToken: token,
  190. logical: logical,
  191. setNamespace: cl.SetNamespace,
  192. addHeader: cl.AddHeader,
  193. }
  194. return out, nil
  195. }
  196. func getVaultClient(c *connector, store esv1beta1.GenericStore, cfg *vault.Config) (Client, error) {
  197. isStaticToken := store.GetSpec().Provider.Vault.Auth.TokenSecretRef != nil
  198. useCache := enableCache && !isStaticToken
  199. key := cache.Key{
  200. Name: store.GetObjectMeta().Name,
  201. Namespace: store.GetObjectMeta().Namespace,
  202. Kind: store.GetTypeMeta().Kind,
  203. }
  204. if useCache {
  205. client, ok := clientCache.Get(store.GetObjectMeta().ResourceVersion, key)
  206. if ok {
  207. return client, nil
  208. }
  209. }
  210. client, err := c.newVaultClient(cfg)
  211. if err != nil {
  212. return nil, fmt.Errorf(errVaultClient, err)
  213. }
  214. if useCache && !clientCache.Contains(key) {
  215. clientCache.Add(store.GetObjectMeta().ResourceVersion, key, client)
  216. }
  217. return client, nil
  218. }
  219. type connector struct {
  220. newVaultClient func(c *vault.Config) (Client, error)
  221. }
  222. // Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
  223. func (c *connector) Capabilities() esv1beta1.SecretStoreCapabilities {
  224. return esv1beta1.SecretStoreReadWrite
  225. }
  226. func (c *connector) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  227. // controller-runtime/client does not support TokenRequest or other subresource APIs
  228. // so we need to construct our own client and use it to fetch tokens
  229. // (for Kubernetes service account token auth)
  230. restCfg, err := ctrlcfg.GetConfig()
  231. if err != nil {
  232. return nil, err
  233. }
  234. clientset, err := kubernetes.NewForConfig(restCfg)
  235. if err != nil {
  236. return nil, err
  237. }
  238. return c.newClient(ctx, store, kube, clientset.CoreV1(), namespace)
  239. }
  240. func (c *connector) newClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, corev1 typedcorev1.CoreV1Interface, namespace string) (esv1beta1.SecretsClient, error) {
  241. storeSpec := store.GetSpec()
  242. if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.Vault == nil {
  243. return nil, errors.New(errVaultStore)
  244. }
  245. vaultSpec := storeSpec.Provider.Vault
  246. vStore := &client{
  247. kube: kube,
  248. corev1: corev1,
  249. store: vaultSpec,
  250. log: logger,
  251. namespace: namespace,
  252. storeKind: store.GetObjectKind().GroupVersionKind().Kind,
  253. }
  254. cfg, err := vStore.newConfig()
  255. if err != nil {
  256. return nil, err
  257. }
  258. client, err := getVaultClient(c, store, cfg)
  259. if err != nil {
  260. return nil, fmt.Errorf(errVaultClient, err)
  261. }
  262. if vaultSpec.Namespace != nil {
  263. client.SetNamespace(*vaultSpec.Namespace)
  264. }
  265. if vaultSpec.ReadYourWrites && vaultSpec.ForwardInconsistent {
  266. client.AddHeader("X-Vault-Inconsistent", "forward-active-node")
  267. }
  268. vStore.client = client
  269. vStore.auth = client.Auth()
  270. vStore.logical = client.Logical()
  271. vStore.token = client.AuthToken()
  272. // allow SecretStore controller validation to pass
  273. // when using referent namespace.
  274. if vStore.storeKind == esv1beta1.ClusterSecretStoreKind && vStore.namespace == "" && isReferentSpec(vaultSpec) {
  275. return vStore, nil
  276. }
  277. if err := vStore.setAuth(ctx, cfg); err != nil {
  278. return nil, err
  279. }
  280. return vStore, nil
  281. }
  282. func (c *connector) ValidateStore(store esv1beta1.GenericStore) error {
  283. if store == nil {
  284. return fmt.Errorf(errInvalidStore)
  285. }
  286. spc := store.GetSpec()
  287. if spc == nil {
  288. return fmt.Errorf(errInvalidStoreSpec)
  289. }
  290. if spc.Provider == nil {
  291. return fmt.Errorf(errInvalidStoreProv)
  292. }
  293. p := spc.Provider.Vault
  294. if p == nil {
  295. return fmt.Errorf(errInvalidVaultProv)
  296. }
  297. if p.Auth.AppRole != nil {
  298. if err := utils.ValidateReferentSecretSelector(store, p.Auth.AppRole.SecretRef); err != nil {
  299. return fmt.Errorf(errInvalidAppRoleSec, err)
  300. }
  301. }
  302. if p.Auth.Cert != nil {
  303. if err := utils.ValidateReferentSecretSelector(store, p.Auth.Cert.ClientCert); err != nil {
  304. return fmt.Errorf(errInvalidClientCert, err)
  305. }
  306. if err := utils.ValidateReferentSecretSelector(store, p.Auth.Cert.SecretRef); err != nil {
  307. return fmt.Errorf(errInvalidCertSec, err)
  308. }
  309. }
  310. if p.Auth.Jwt != nil {
  311. if p.Auth.Jwt.SecretRef != nil {
  312. if err := utils.ValidateReferentSecretSelector(store, *p.Auth.Jwt.SecretRef); err != nil {
  313. return fmt.Errorf(errInvalidJwtSec, err)
  314. }
  315. } else if p.Auth.Jwt.KubernetesServiceAccountToken != nil {
  316. if err := utils.ValidateReferentServiceAccountSelector(store, p.Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef); err != nil {
  317. return fmt.Errorf(errInvalidJwtK8sSA, err)
  318. }
  319. } else {
  320. return fmt.Errorf(errJwtNoTokenSource)
  321. }
  322. }
  323. if p.Auth.Kubernetes != nil {
  324. if p.Auth.Kubernetes.ServiceAccountRef != nil {
  325. if err := utils.ValidateReferentServiceAccountSelector(store, *p.Auth.Kubernetes.ServiceAccountRef); err != nil {
  326. return fmt.Errorf(errInvalidKubeSA, err)
  327. }
  328. }
  329. if p.Auth.Kubernetes.SecretRef != nil {
  330. if err := utils.ValidateReferentSecretSelector(store, *p.Auth.Kubernetes.SecretRef); err != nil {
  331. return fmt.Errorf(errInvalidKubeSec, err)
  332. }
  333. }
  334. }
  335. if p.Auth.Ldap != nil {
  336. if err := utils.ValidateReferentSecretSelector(store, p.Auth.Ldap.SecretRef); err != nil {
  337. return fmt.Errorf(errInvalidLdapSec, err)
  338. }
  339. }
  340. if p.Auth.TokenSecretRef != nil {
  341. if err := utils.ValidateReferentSecretSelector(store, *p.Auth.TokenSecretRef); err != nil {
  342. return fmt.Errorf(errInvalidTokenRef, err)
  343. }
  344. }
  345. return nil
  346. }
  347. func (v *client) DeleteSecret(ctx context.Context, remoteRef esv1beta1.PushRemoteRef) error {
  348. path := v.buildPath(remoteRef.GetRemoteKey())
  349. metaPath, err := v.buildMetadataPath(remoteRef.GetRemoteKey())
  350. if err != nil {
  351. return err
  352. }
  353. // Retrieve the secret map from vault and convert the secret value in string form.
  354. _, err = v.readSecret(ctx, path, "")
  355. // If error is not of type secret not found, we should error
  356. if err != nil && errors.Is(err, esv1beta1.NoSecretError{}) {
  357. return nil
  358. }
  359. if err != nil {
  360. return err
  361. }
  362. metadata, err := v.readSecretMetadata(ctx, remoteRef.GetRemoteKey())
  363. if err != nil {
  364. return err
  365. }
  366. manager, ok := metadata["managed-by"]
  367. if !ok || manager != "external-secrets" {
  368. return nil
  369. }
  370. _, err = v.logical.DeleteWithContext(ctx, path)
  371. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultDeleteSecret, err)
  372. if err != nil {
  373. return fmt.Errorf("could not delete secret %v: %w", remoteRef.GetRemoteKey(), err)
  374. }
  375. _, err = v.logical.DeleteWithContext(ctx, metaPath)
  376. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultDeleteSecret, err)
  377. if err != nil {
  378. return fmt.Errorf("could not delete secret metadata %v: %w", remoteRef.GetRemoteKey(), err)
  379. }
  380. return nil
  381. }
  382. func (v *client) PushSecret(ctx context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
  383. label := map[string]interface{}{
  384. "custom_metadata": map[string]string{
  385. "managed-by": "external-secrets",
  386. },
  387. }
  388. secretVal := make(map[string]interface{})
  389. err := json.Unmarshal(value, &secretVal)
  390. if err != nil {
  391. return fmt.Errorf("failed to convert value to a valid JSON: %w", err)
  392. }
  393. secretToPush := map[string]interface{}{
  394. "data": secretVal,
  395. }
  396. path := v.buildPath(remoteRef.GetRemoteKey())
  397. metaPath, err := v.buildMetadataPath(remoteRef.GetRemoteKey())
  398. if err != nil {
  399. return err
  400. }
  401. // Retrieve the secret map from vault and convert the secret value in string form.
  402. vaultSecret, err := v.readSecret(ctx, path, "")
  403. // If error is not of type secret not found, we should error
  404. if err != nil && !errors.Is(err, esv1beta1.NoSecretError{}) {
  405. return err
  406. }
  407. // If the secret exists (err == nil), we should check if it is managed by external-secrets
  408. if err == nil {
  409. metadata, err := v.readSecretMetadata(ctx, remoteRef.GetRemoteKey())
  410. if err != nil {
  411. return err
  412. }
  413. manager, ok := metadata["managed-by"]
  414. if !ok || manager != "external-secrets" {
  415. return fmt.Errorf("secret not managed by external-secrets")
  416. }
  417. }
  418. vaultSecretValue, err := json.Marshal(vaultSecret)
  419. if err != nil {
  420. return fmt.Errorf("error marshaling vault secret: %w", err)
  421. }
  422. if bytes.Equal(vaultSecretValue, value) {
  423. return nil
  424. }
  425. _, err = v.logical.WriteWithContext(ctx, metaPath, label)
  426. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultWriteSecretData, err)
  427. if err != nil {
  428. return err
  429. }
  430. // Otherwise, create or update the version.
  431. _, err = v.logical.WriteWithContext(ctx, path, secretToPush)
  432. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultWriteSecretData, err)
  433. return err
  434. }
  435. // GetAllSecrets gets multiple secrets from the provider and loads into a kubernetes secret.
  436. // First load all secrets from secretStore path configuration
  437. // Then, gets secrets from a matching name or matching custom_metadata.
  438. func (v *client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  439. if v.store.Version == esv1beta1.VaultKVStoreV1 {
  440. return nil, errors.New(errUnsupportedKvVersion)
  441. }
  442. searchPath := ""
  443. if ref.Path != nil {
  444. searchPath = *ref.Path + "/"
  445. }
  446. potentialSecrets, err := v.listSecrets(ctx, searchPath)
  447. if err != nil {
  448. return nil, err
  449. }
  450. if ref.Name != nil {
  451. return v.findSecretsFromName(ctx, potentialSecrets, *ref.Name)
  452. }
  453. return v.findSecretsFromTags(ctx, potentialSecrets, ref.Tags)
  454. }
  455. func (v *client) findSecretsFromTags(ctx context.Context, candidates []string, tags map[string]string) (map[string][]byte, error) {
  456. secrets := make(map[string][]byte)
  457. for _, name := range candidates {
  458. match := true
  459. metadata, err := v.readSecretMetadata(ctx, name)
  460. if err != nil {
  461. return nil, err
  462. }
  463. for tk, tv := range tags {
  464. p, ok := metadata[tk]
  465. if !ok || p != tv {
  466. match = false
  467. break
  468. }
  469. }
  470. if match {
  471. secret, err := v.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: name})
  472. if err != nil {
  473. return nil, err
  474. }
  475. if secret != nil {
  476. secrets[name] = secret
  477. }
  478. }
  479. }
  480. return secrets, nil
  481. }
  482. func (v *client) findSecretsFromName(ctx context.Context, candidates []string, ref esv1beta1.FindName) (map[string][]byte, error) {
  483. secrets := make(map[string][]byte)
  484. matcher, err := find.New(ref)
  485. if err != nil {
  486. return nil, err
  487. }
  488. for _, name := range candidates {
  489. ok := matcher.MatchName(name)
  490. if ok {
  491. secret, err := v.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: name})
  492. if err != nil {
  493. return nil, err
  494. }
  495. if secret != nil {
  496. secrets[name] = secret
  497. }
  498. }
  499. }
  500. return secrets, nil
  501. }
  502. func (v *client) listSecrets(ctx context.Context, path string) ([]string, error) {
  503. secrets := make([]string, 0)
  504. url, err := v.buildMetadataPath(path)
  505. if err != nil {
  506. return nil, err
  507. }
  508. secret, err := v.logical.ListWithContext(ctx, url)
  509. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultListSecrets, err)
  510. if err != nil {
  511. return nil, fmt.Errorf(errReadSecret, err)
  512. }
  513. if secret == nil {
  514. return nil, fmt.Errorf("provided path %v does not contain any secrets", url)
  515. }
  516. t, ok := secret.Data["keys"]
  517. if !ok {
  518. return nil, nil
  519. }
  520. paths := t.([]interface{})
  521. for _, p := range paths {
  522. strPath := p.(string)
  523. fullPath := path + strPath // because path always ends with a /
  524. if path == "" {
  525. fullPath = strPath
  526. }
  527. // Recurrently find secrets
  528. if !strings.HasSuffix(p.(string), "/") {
  529. secrets = append(secrets, fullPath)
  530. } else {
  531. partial, err := v.listSecrets(ctx, fullPath)
  532. if err != nil {
  533. return nil, err
  534. }
  535. secrets = append(secrets, partial...)
  536. }
  537. }
  538. return secrets, nil
  539. }
  540. func (v *client) readSecretMetadata(ctx context.Context, path string) (map[string]string, error) {
  541. metadata := make(map[string]string)
  542. url, err := v.buildMetadataPath(path)
  543. if err != nil {
  544. return nil, err
  545. }
  546. secret, err := v.logical.ReadWithDataWithContext(ctx, url, nil)
  547. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultReadSecretData, err)
  548. if err != nil {
  549. return nil, fmt.Errorf(errReadSecret, err)
  550. }
  551. if secret == nil {
  552. return nil, errors.New(errNotFound)
  553. }
  554. t, ok := secret.Data["custom_metadata"]
  555. if !ok {
  556. return nil, nil
  557. }
  558. d, ok := t.(map[string]interface{})
  559. if !ok {
  560. return metadata, nil
  561. }
  562. for k, v := range d {
  563. metadata[k] = v.(string)
  564. }
  565. return metadata, nil
  566. }
  567. // GetSecret supports two types:
  568. // 1. get the full secret as json-encoded value
  569. // by leaving the ref.Property empty.
  570. // 2. get a key from the secret.
  571. // Nested values are supported by specifying a gjson expression
  572. func (v *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  573. var data map[string]interface{}
  574. var err error
  575. if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
  576. if v.store.Version == esv1beta1.VaultKVStoreV1 {
  577. return nil, errors.New(errUnsupportedMetadataKvVersion)
  578. }
  579. metadata, err := v.readSecretMetadata(ctx, ref.Key)
  580. if err != nil {
  581. return nil, err
  582. }
  583. if len(metadata) == 0 {
  584. return nil, nil
  585. }
  586. data = make(map[string]interface{}, len(metadata))
  587. for k, v := range metadata {
  588. data[k] = v
  589. }
  590. } else {
  591. data, err = v.readSecret(ctx, ref.Key, ref.Version)
  592. if err != nil {
  593. return nil, err
  594. }
  595. }
  596. // Return nil if secret value is null
  597. if data == nil {
  598. return nil, nil
  599. }
  600. jsonStr, err := json.Marshal(data)
  601. if err != nil {
  602. return nil, err
  603. }
  604. // (1): return raw json if no property is defined
  605. if ref.Property == "" {
  606. return jsonStr, nil
  607. }
  608. // For backwards compatibility we want the
  609. // actual keys to take precedence over gjson syntax
  610. // (2): extract key from secret with property
  611. if _, ok := data[ref.Property]; ok {
  612. return getTypedKey(data, ref.Property)
  613. }
  614. // (3): extract key from secret using gjson
  615. val := gjson.Get(string(jsonStr), ref.Property)
  616. if !val.Exists() {
  617. return nil, fmt.Errorf(errSecretKeyFmt, ref.Property)
  618. }
  619. return []byte(val.String()), nil
  620. }
  621. // GetSecretMap supports two modes of operation:
  622. // 1. get the full secret from the vault data payload (by leaving .property empty).
  623. // 2. extract key/value pairs from a (nested) object.
  624. func (v *client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  625. data, err := v.GetSecret(ctx, ref)
  626. if err != nil {
  627. return nil, err
  628. }
  629. var secretData map[string]interface{}
  630. err = json.Unmarshal(data, &secretData)
  631. if err != nil {
  632. return nil, err
  633. }
  634. byteMap := make(map[string][]byte, len(secretData))
  635. for k := range secretData {
  636. byteMap[k], err = getTypedKey(secretData, k)
  637. if err != nil {
  638. return nil, err
  639. }
  640. }
  641. return byteMap, nil
  642. }
  643. func getTypedKey(data map[string]interface{}, key string) ([]byte, error) {
  644. v, ok := data[key]
  645. if !ok {
  646. return nil, fmt.Errorf(errUnexpectedKey, key)
  647. }
  648. switch t := v.(type) {
  649. case string:
  650. return []byte(t), nil
  651. case map[string]interface{}:
  652. return json.Marshal(t)
  653. case []byte:
  654. return t, nil
  655. // also covers int and float32 due to json.Marshal
  656. case float64:
  657. return []byte(strconv.FormatFloat(t, 'f', -1, 64)), nil
  658. case bool:
  659. return []byte(strconv.FormatBool(t)), nil
  660. case nil:
  661. return []byte(nil), nil
  662. default:
  663. return nil, errors.New(errSecretFormat)
  664. }
  665. }
  666. func (v *client) Close(ctx context.Context) error {
  667. // Revoke the token if we have one set, it wasn't sourced from a TokenSecretRef,
  668. // and token caching isn't enabled
  669. if !enableCache && v.client.Token() != "" && v.store.Auth.TokenSecretRef == nil {
  670. err := revokeTokenIfValid(ctx, v.client)
  671. if err != nil {
  672. return err
  673. }
  674. }
  675. return nil
  676. }
  677. func isReferentSpec(prov *esv1beta1.VaultProvider) bool {
  678. if prov.Auth.TokenSecretRef != nil && prov.Auth.TokenSecretRef.Namespace == nil {
  679. return true
  680. }
  681. if prov.Auth.AppRole != nil && prov.Auth.AppRole.SecretRef.Namespace == nil {
  682. return true
  683. }
  684. if prov.Auth.Kubernetes != nil && prov.Auth.Kubernetes.SecretRef != nil && prov.Auth.Kubernetes.SecretRef.Namespace == nil {
  685. return true
  686. }
  687. if prov.Auth.Kubernetes != nil && prov.Auth.Kubernetes.ServiceAccountRef != nil && prov.Auth.Kubernetes.ServiceAccountRef.Namespace == nil {
  688. return true
  689. }
  690. if prov.Auth.Ldap != nil && prov.Auth.Ldap.SecretRef.Namespace == nil {
  691. return true
  692. }
  693. if prov.Auth.Jwt != nil && prov.Auth.Jwt.SecretRef != nil && prov.Auth.Jwt.SecretRef.Namespace == nil {
  694. return true
  695. }
  696. if prov.Auth.Jwt != nil && prov.Auth.Jwt.KubernetesServiceAccountToken != nil && prov.Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef.Namespace == nil {
  697. return true
  698. }
  699. if prov.Auth.Cert != nil && prov.Auth.Cert.SecretRef.Namespace == nil {
  700. return true
  701. }
  702. return false
  703. }
  704. func (v *client) Validate() (esv1beta1.ValidationResult, error) {
  705. // when using referent namespace we can not validate the token
  706. // because the namespace is not known yet when Validate() is called
  707. // from the SecretStore controller.
  708. if v.storeKind == esv1beta1.ClusterSecretStoreKind && isReferentSpec(v.store) {
  709. return esv1beta1.ValidationResultUnknown, nil
  710. }
  711. _, err := checkToken(context.Background(), v.token)
  712. if err != nil {
  713. return esv1beta1.ValidationResultError, fmt.Errorf(errInvalidCredentials, err)
  714. }
  715. return esv1beta1.ValidationResultReady, nil
  716. }
  717. func (v *client) buildMetadataPath(path string) (string, error) {
  718. var url string
  719. if v.store.Path == nil && !strings.Contains(path, "data") {
  720. return "", fmt.Errorf(errPathInvalid)
  721. }
  722. if v.store.Path == nil {
  723. path = strings.Replace(path, "data", "metadata", 1)
  724. url = path
  725. } else {
  726. url = fmt.Sprintf("%s/metadata/%s", *v.store.Path, path)
  727. }
  728. return url, nil
  729. }
  730. /*
  731. buildPath is a helper method to build the vault equivalent path
  732. from ExternalSecrets and SecretStore manifests. the path build logic
  733. varies depending on the SecretStore KV version:
  734. Example inputs/outputs:
  735. # simple build:
  736. kv version == "v2":
  737. provider_path: "secret/path"
  738. input: "foo"
  739. output: "secret/path/data/foo" # provider_path and data are prepended
  740. kv version == "v1":
  741. provider_path: "secret/path"
  742. input: "foo"
  743. output: "secret/path/foo" # provider_path is prepended
  744. # inheriting paths:
  745. kv version == "v2":
  746. provider_path: "secret/path"
  747. input: "secret/path/foo"
  748. output: "secret/path/data/foo" #data is prepended
  749. kv version == "v2":
  750. provider_path: "secret/path"
  751. input: "secret/path/data/foo"
  752. output: "secret/path/data/foo" #noop
  753. kv version == "v1":
  754. provider_path: "secret/path"
  755. input: "secret/path/foo"
  756. output: "secret/path/foo" #noop
  757. # provider path not defined:
  758. kv version == "v2":
  759. provider_path: nil
  760. input: "secret/path/foo"
  761. output: "secret/data/path/foo" # data is prepended to secret/
  762. kv version == "v2":
  763. provider_path: nil
  764. input: "secret/path/data/foo"
  765. output: "secret/path/data/foo" #noop
  766. kv version == "v1":
  767. provider_path: nil
  768. input: "secret/path/foo"
  769. output: "secret/path/foo" #noop
  770. */
  771. func (v *client) buildPath(path string) string {
  772. optionalMount := v.store.Path
  773. out := path
  774. // if optionalMount is Set, remove it from path if its there
  775. if optionalMount != nil {
  776. cut := *optionalMount + "/"
  777. if strings.HasPrefix(out, cut) {
  778. // This current logic induces a bug when the actual secret resides on same path names as the mount path.
  779. _, out, _ = strings.Cut(out, cut)
  780. // if data succeeds optionalMount on v2 store, we should remove it as well
  781. if strings.HasPrefix(out, "data/") && v.store.Version == esv1beta1.VaultKVStoreV2 {
  782. _, out, _ = strings.Cut(out, "data/")
  783. }
  784. }
  785. buildPath := strings.Split(out, "/")
  786. buildMount := strings.Split(*optionalMount, "/")
  787. if v.store.Version == esv1beta1.VaultKVStoreV2 {
  788. buildMount = append(buildMount, "data")
  789. }
  790. buildMount = append(buildMount, buildPath...)
  791. out = strings.Join(buildMount, "/")
  792. return out
  793. }
  794. if !strings.Contains(out, "/data/") && v.store.Version == esv1beta1.VaultKVStoreV2 {
  795. buildPath := strings.Split(out, "/")
  796. buildMount := []string{buildPath[0], "data"}
  797. buildMount = append(buildMount, buildPath[1:]...)
  798. out = strings.Join(buildMount, "/")
  799. return out
  800. }
  801. return out
  802. }
  803. func (v *client) readSecret(ctx context.Context, path, version string) (map[string]interface{}, error) {
  804. dataPath := v.buildPath(path)
  805. // path formated according to vault docs for v1 and v2 API
  806. // v1: https://www.vaultproject.io/api-docs/secret/kv/kv-v1#read-secret
  807. // v2: https://www.vaultproject.io/api/secret/kv/kv-v2#read-secret-version
  808. var params map[string][]string
  809. if version != "" {
  810. params = make(map[string][]string)
  811. params["version"] = []string{version}
  812. }
  813. vaultSecret, err := v.logical.ReadWithDataWithContext(ctx, dataPath, params)
  814. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultReadSecretData, err)
  815. if err != nil {
  816. return nil, fmt.Errorf(errReadSecret, err)
  817. }
  818. if vaultSecret == nil {
  819. return nil, esv1beta1.NoSecretError{}
  820. }
  821. secretData := vaultSecret.Data
  822. if v.store.Version == esv1beta1.VaultKVStoreV2 {
  823. // Vault KV2 has data embedded within sub-field
  824. // reference - https://www.vaultproject.io/api/secret/kv/kv-v2#read-secret-version
  825. dataInt, ok := vaultSecret.Data["data"]
  826. if !ok {
  827. return nil, errors.New(errDataField)
  828. }
  829. if dataInt == nil {
  830. return nil, nil
  831. }
  832. secretData, ok = dataInt.(map[string]interface{})
  833. if !ok {
  834. return nil, errors.New(errJSONUnmarshall)
  835. }
  836. }
  837. return secretData, nil
  838. }
  839. func (v *client) newConfig() (*vault.Config, error) {
  840. cfg := vault.DefaultConfig()
  841. cfg.Address = v.store.Server
  842. // In a controller-runtime context, we rely on the reconciliation process for retrying
  843. cfg.MaxRetries = 0
  844. if len(v.store.CABundle) == 0 && v.store.CAProvider == nil {
  845. return cfg, nil
  846. }
  847. caCertPool := x509.NewCertPool()
  848. if len(v.store.CABundle) > 0 {
  849. ok := caCertPool.AppendCertsFromPEM(v.store.CABundle)
  850. if !ok {
  851. return nil, errors.New(errVaultCert)
  852. }
  853. }
  854. if v.store.CAProvider != nil && v.storeKind == esv1beta1.ClusterSecretStoreKind && v.store.CAProvider.Namespace == nil {
  855. return nil, errors.New(errCANamespace)
  856. }
  857. if v.store.CAProvider != nil {
  858. var cert []byte
  859. var err error
  860. switch v.store.CAProvider.Type {
  861. case esv1beta1.CAProviderTypeSecret:
  862. cert, err = getCertFromSecret(v)
  863. case esv1beta1.CAProviderTypeConfigMap:
  864. cert, err = getCertFromConfigMap(v)
  865. default:
  866. return nil, errors.New(errUnknownCAProvider)
  867. }
  868. if err != nil {
  869. return nil, err
  870. }
  871. ok := caCertPool.AppendCertsFromPEM(cert)
  872. if !ok {
  873. return nil, errors.New(errVaultCert)
  874. }
  875. }
  876. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  877. transport.TLSClientConfig.RootCAs = caCertPool
  878. }
  879. // If either read-after-write consistency feature is enabled, enable ReadYourWrites
  880. cfg.ReadYourWrites = v.store.ReadYourWrites || v.store.ForwardInconsistent
  881. return cfg, nil
  882. }
  883. func getCertFromSecret(v *client) ([]byte, error) {
  884. secretRef := esmeta.SecretKeySelector{
  885. Name: v.store.CAProvider.Name,
  886. Key: v.store.CAProvider.Key,
  887. }
  888. if v.store.CAProvider.Namespace != nil {
  889. secretRef.Namespace = v.store.CAProvider.Namespace
  890. }
  891. ctx := context.Background()
  892. res, err := v.secretKeyRef(ctx, &secretRef)
  893. if err != nil {
  894. return nil, fmt.Errorf(errVaultCert, err)
  895. }
  896. return []byte(res), nil
  897. }
  898. func getCertFromConfigMap(v *client) ([]byte, error) {
  899. objKey := types.NamespacedName{
  900. Name: v.store.CAProvider.Name,
  901. }
  902. if v.store.CAProvider.Namespace != nil {
  903. objKey.Namespace = *v.store.CAProvider.Namespace
  904. }
  905. configMapRef := &corev1.ConfigMap{}
  906. ctx := context.Background()
  907. err := v.kube.Get(ctx, objKey, configMapRef)
  908. if err != nil {
  909. return nil, fmt.Errorf(errVaultCert, err)
  910. }
  911. val, ok := configMapRef.Data[v.store.CAProvider.Key]
  912. if !ok {
  913. return nil, fmt.Errorf(errConfigMapFmt, v.store.CAProvider.Key)
  914. }
  915. return []byte(val), nil
  916. }
  917. /*
  918. setAuth gets a new token using the configured mechanism.
  919. If there's already a valid token, does nothing.
  920. */
  921. func (v *client) setAuth(ctx context.Context, cfg *vault.Config) error {
  922. tokenExists := false
  923. var err error
  924. if v.client.Token() != "" {
  925. tokenExists, err = checkToken(ctx, v.token)
  926. }
  927. if tokenExists {
  928. v.log.V(1).Info("Re-using existing token")
  929. return err
  930. }
  931. tokenExists, err = setSecretKeyToken(ctx, v)
  932. if tokenExists {
  933. v.log.V(1).Info("Set token from secret")
  934. return err
  935. }
  936. tokenExists, err = setAppRoleToken(ctx, v)
  937. if tokenExists {
  938. v.log.V(1).Info("Retrieved new token using AppRole auth")
  939. return err
  940. }
  941. tokenExists, err = setKubernetesAuthToken(ctx, v)
  942. if tokenExists {
  943. v.log.V(1).Info("Retrieved new token using Kubernetes auth")
  944. return err
  945. }
  946. tokenExists, err = setLdapAuthToken(ctx, v)
  947. if tokenExists {
  948. v.log.V(1).Info("Retrieved new token using LDAP auth")
  949. return err
  950. }
  951. tokenExists, err = setJwtAuthToken(ctx, v)
  952. if tokenExists {
  953. v.log.V(1).Info("Retrieved new token using JWT auth")
  954. return err
  955. }
  956. tokenExists, err = setCertAuthToken(ctx, v, cfg)
  957. if tokenExists {
  958. v.log.V(1).Info("Retrieved new token using certificate auth")
  959. return err
  960. }
  961. return errors.New(errAuthFormat)
  962. }
  963. func setSecretKeyToken(ctx context.Context, v *client) (bool, error) {
  964. tokenRef := v.store.Auth.TokenSecretRef
  965. if tokenRef != nil {
  966. token, err := v.secretKeyRef(ctx, tokenRef)
  967. if err != nil {
  968. return true, err
  969. }
  970. v.client.SetToken(token)
  971. return true, nil
  972. }
  973. return false, nil
  974. }
  975. func setAppRoleToken(ctx context.Context, v *client) (bool, error) {
  976. appRole := v.store.Auth.AppRole
  977. if appRole != nil {
  978. err := v.requestTokenWithAppRoleRef(ctx, appRole)
  979. if err != nil {
  980. return true, err
  981. }
  982. return true, nil
  983. }
  984. return false, nil
  985. }
  986. func setKubernetesAuthToken(ctx context.Context, v *client) (bool, error) {
  987. kubernetesAuth := v.store.Auth.Kubernetes
  988. if kubernetesAuth != nil {
  989. err := v.requestTokenWithKubernetesAuth(ctx, kubernetesAuth)
  990. if err != nil {
  991. return true, err
  992. }
  993. return true, nil
  994. }
  995. return false, nil
  996. }
  997. func setLdapAuthToken(ctx context.Context, v *client) (bool, error) {
  998. ldapAuth := v.store.Auth.Ldap
  999. if ldapAuth != nil {
  1000. err := v.requestTokenWithLdapAuth(ctx, ldapAuth)
  1001. if err != nil {
  1002. return true, err
  1003. }
  1004. return true, nil
  1005. }
  1006. return false, nil
  1007. }
  1008. func setJwtAuthToken(ctx context.Context, v *client) (bool, error) {
  1009. jwtAuth := v.store.Auth.Jwt
  1010. if jwtAuth != nil {
  1011. err := v.requestTokenWithJwtAuth(ctx, jwtAuth)
  1012. if err != nil {
  1013. return true, err
  1014. }
  1015. return true, nil
  1016. }
  1017. return false, nil
  1018. }
  1019. func setCertAuthToken(ctx context.Context, v *client, cfg *vault.Config) (bool, error) {
  1020. certAuth := v.store.Auth.Cert
  1021. if certAuth != nil {
  1022. err := v.requestTokenWithCertAuth(ctx, certAuth, cfg)
  1023. if err != nil {
  1024. return true, err
  1025. }
  1026. return true, nil
  1027. }
  1028. return false, nil
  1029. }
  1030. func (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccountRef *esmeta.ServiceAccountSelector) (string, error) {
  1031. serviceAccount := &corev1.ServiceAccount{}
  1032. ref := types.NamespacedName{
  1033. Namespace: v.namespace,
  1034. Name: serviceAccountRef.Name,
  1035. }
  1036. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  1037. (serviceAccountRef.Namespace != nil) {
  1038. ref.Namespace = *serviceAccountRef.Namespace
  1039. }
  1040. err := v.kube.Get(ctx, ref, serviceAccount)
  1041. if err != nil {
  1042. return "", fmt.Errorf(errGetKubeSA, ref.Name, err)
  1043. }
  1044. if len(serviceAccount.Secrets) == 0 {
  1045. return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
  1046. }
  1047. for _, tokenRef := range serviceAccount.Secrets {
  1048. retval, err := v.secretKeyRef(ctx, &esmeta.SecretKeySelector{
  1049. Name: tokenRef.Name,
  1050. Namespace: &ref.Namespace,
  1051. Key: "token",
  1052. })
  1053. if err != nil {
  1054. continue
  1055. }
  1056. return retval, nil
  1057. }
  1058. return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
  1059. }
  1060. func (v *client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
  1061. secret := &corev1.Secret{}
  1062. ref := types.NamespacedName{
  1063. Namespace: v.namespace,
  1064. Name: secretRef.Name,
  1065. }
  1066. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  1067. (secretRef.Namespace != nil) {
  1068. ref.Namespace = *secretRef.Namespace
  1069. }
  1070. err := v.kube.Get(ctx, ref, secret)
  1071. if err != nil {
  1072. return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
  1073. }
  1074. keyBytes, ok := secret.Data[secretRef.Key]
  1075. if !ok {
  1076. return "", fmt.Errorf(errSecretKeyFmt, secretRef.Key)
  1077. }
  1078. value := string(keyBytes)
  1079. valueStr := strings.TrimSpace(value)
  1080. return valueStr, nil
  1081. }
  1082. func (v *client) serviceAccountToken(ctx context.Context, serviceAccountRef esmeta.ServiceAccountSelector, additionalAud []string, expirationSeconds int64) (string, error) {
  1083. audiences := serviceAccountRef.Audiences
  1084. if len(additionalAud) > 0 {
  1085. audiences = append(audiences, additionalAud...)
  1086. }
  1087. tokenRequest := &authenticationv1.TokenRequest{
  1088. ObjectMeta: metav1.ObjectMeta{
  1089. Namespace: v.namespace,
  1090. },
  1091. Spec: authenticationv1.TokenRequestSpec{
  1092. Audiences: audiences,
  1093. ExpirationSeconds: &expirationSeconds,
  1094. },
  1095. }
  1096. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  1097. (serviceAccountRef.Namespace != nil) {
  1098. tokenRequest.Namespace = *serviceAccountRef.Namespace
  1099. }
  1100. tokenResponse, err := v.corev1.ServiceAccounts(tokenRequest.Namespace).CreateToken(ctx, serviceAccountRef.Name, tokenRequest, metav1.CreateOptions{})
  1101. if err != nil {
  1102. return "", fmt.Errorf(errGetKubeSATokenRequest, serviceAccountRef.Name, err)
  1103. }
  1104. return tokenResponse.Status.Token, nil
  1105. }
  1106. // checkToken does a lookup and checks if the provided token exists.
  1107. func checkToken(ctx context.Context, token Token) (bool, error) {
  1108. // https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
  1109. resp, err := token.LookupSelfWithContext(ctx)
  1110. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLookupSelf, err)
  1111. if err != nil {
  1112. return false, err
  1113. }
  1114. t, ok := resp.Data["type"]
  1115. if !ok {
  1116. return false, fmt.Errorf("could not assert token type")
  1117. }
  1118. tokenType := t.(string)
  1119. if tokenType == "batch" {
  1120. return false, nil
  1121. }
  1122. return true, nil
  1123. }
  1124. func revokeTokenIfValid(ctx context.Context, client Client) error {
  1125. valid, err := checkToken(ctx, client.AuthToken())
  1126. if err != nil {
  1127. return fmt.Errorf(errVaultRevokeToken, err)
  1128. }
  1129. if valid {
  1130. err = client.AuthToken().RevokeSelfWithContext(ctx, client.Token())
  1131. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultRevokeSelf, err)
  1132. if err != nil {
  1133. return fmt.Errorf(errVaultRevokeToken, err)
  1134. }
  1135. client.ClearToken()
  1136. }
  1137. return nil
  1138. }
  1139. func (v *client) requestTokenWithAppRoleRef(ctx context.Context, appRole *esv1beta1.VaultAppRole) error {
  1140. roleID := strings.TrimSpace(appRole.RoleID)
  1141. secretID, err := v.secretKeyRef(ctx, &appRole.SecretRef)
  1142. if err != nil {
  1143. return err
  1144. }
  1145. secret := approle.SecretID{FromString: secretID}
  1146. appRoleClient, err := approle.NewAppRoleAuth(roleID, &secret, approle.WithMountPath(appRole.Path))
  1147. if err != nil {
  1148. return err
  1149. }
  1150. _, err = v.auth.Login(ctx, appRoleClient)
  1151. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLogin, err)
  1152. if err != nil {
  1153. return err
  1154. }
  1155. return nil
  1156. }
  1157. func (v *client) requestTokenWithKubernetesAuth(ctx context.Context, kubernetesAuth *esv1beta1.VaultKubernetesAuth) error {
  1158. jwtString, err := getJwtString(ctx, v, kubernetesAuth)
  1159. if err != nil {
  1160. return err
  1161. }
  1162. k, err := authkubernetes.NewKubernetesAuth(kubernetesAuth.Role, authkubernetes.WithServiceAccountToken(jwtString), authkubernetes.WithMountPath(kubernetesAuth.Path))
  1163. if err != nil {
  1164. return err
  1165. }
  1166. _, err = v.auth.Login(ctx, k)
  1167. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLogin, err)
  1168. if err != nil {
  1169. return err
  1170. }
  1171. return nil
  1172. }
  1173. func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.VaultKubernetesAuth) (string, error) {
  1174. if kubernetesAuth.ServiceAccountRef != nil {
  1175. // Kubernetes <v1.24 fetch token via ServiceAccount.Secrets[]
  1176. // this behavior was removed in v1.24 and we must use TokenRequest API (see below)
  1177. jwt, err := v.secretKeyRefForServiceAccount(ctx, kubernetesAuth.ServiceAccountRef)
  1178. if jwt != "" {
  1179. return jwt, err
  1180. }
  1181. if err != nil {
  1182. v.log.V(1).Info("unable to fetch jwt from service account secret, trying service account token next")
  1183. }
  1184. // Kubernetes >=v1.24: fetch token via TokenRequest API
  1185. // note: this is a massive change from vault perspective: the `iss` claim will very likely change.
  1186. // Vault 1.9 deprecated issuer validation by default, and authentication with Vault clusters <1.9 will likely fail.
  1187. jwt, err = v.serviceAccountToken(ctx, *kubernetesAuth.ServiceAccountRef, nil, 600)
  1188. if err != nil {
  1189. return "", err
  1190. }
  1191. return jwt, nil
  1192. } else if kubernetesAuth.SecretRef != nil {
  1193. tokenRef := kubernetesAuth.SecretRef
  1194. if tokenRef.Key == "" {
  1195. tokenRef = kubernetesAuth.SecretRef.DeepCopy()
  1196. tokenRef.Key = "token"
  1197. }
  1198. jwt, err := v.secretKeyRef(ctx, tokenRef)
  1199. if err != nil {
  1200. return "", err
  1201. }
  1202. return jwt, nil
  1203. } else {
  1204. // Kubernetes authentication is specified, but without a referenced
  1205. // Kubernetes secret. We check if the file path for in-cluster service account
  1206. // exists and attempt to use the token for Vault Kubernetes auth.
  1207. if _, err := os.Stat(serviceAccTokenPath); err != nil {
  1208. return "", fmt.Errorf(errServiceAccount, err)
  1209. }
  1210. jwtByte, err := os.ReadFile(serviceAccTokenPath)
  1211. if err != nil {
  1212. return "", fmt.Errorf(errServiceAccount, err)
  1213. }
  1214. return string(jwtByte), nil
  1215. }
  1216. }
  1217. func (v *client) requestTokenWithLdapAuth(ctx context.Context, ldapAuth *esv1beta1.VaultLdapAuth) error {
  1218. username := strings.TrimSpace(ldapAuth.Username)
  1219. password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
  1220. if err != nil {
  1221. return err
  1222. }
  1223. pass := authldap.Password{FromString: password}
  1224. l, err := authldap.NewLDAPAuth(username, &pass, authldap.WithMountPath(ldapAuth.Path))
  1225. if err != nil {
  1226. return err
  1227. }
  1228. _, err = v.auth.Login(ctx, l)
  1229. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLogin, err)
  1230. if err != nil {
  1231. return err
  1232. }
  1233. return nil
  1234. }
  1235. func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1.VaultJwtAuth) error {
  1236. role := strings.TrimSpace(jwtAuth.Role)
  1237. var jwt string
  1238. var err error
  1239. if jwtAuth.SecretRef != nil {
  1240. jwt, err = v.secretKeyRef(ctx, jwtAuth.SecretRef)
  1241. } else if k8sServiceAccountToken := jwtAuth.KubernetesServiceAccountToken; k8sServiceAccountToken != nil {
  1242. audiences := k8sServiceAccountToken.Audiences
  1243. if audiences == nil {
  1244. audiences = &[]string{"vault"}
  1245. }
  1246. expirationSeconds := k8sServiceAccountToken.ExpirationSeconds
  1247. if expirationSeconds == nil {
  1248. tmp := int64(600)
  1249. expirationSeconds = &tmp
  1250. }
  1251. jwt, err = v.serviceAccountToken(ctx, k8sServiceAccountToken.ServiceAccountRef, *audiences, *expirationSeconds)
  1252. } else {
  1253. err = fmt.Errorf(errJwtNoTokenSource)
  1254. }
  1255. if err != nil {
  1256. return err
  1257. }
  1258. parameters := map[string]interface{}{
  1259. "role": role,
  1260. "jwt": jwt,
  1261. }
  1262. url := strings.Join([]string{"auth", jwtAuth.Path, "login"}, "/")
  1263. vaultResult, err := v.logical.WriteWithContext(ctx, url, parameters)
  1264. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultWriteSecretData, err)
  1265. if err != nil {
  1266. return err
  1267. }
  1268. token, err := vaultResult.TokenID()
  1269. if err != nil {
  1270. return fmt.Errorf(errVaultToken, err)
  1271. }
  1272. v.client.SetToken(token)
  1273. return nil
  1274. }
  1275. func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1beta1.VaultCertAuth, cfg *vault.Config) error {
  1276. clientKey, err := v.secretKeyRef(ctx, &certAuth.SecretRef)
  1277. if err != nil {
  1278. return err
  1279. }
  1280. clientCert, err := v.secretKeyRef(ctx, &certAuth.ClientCert)
  1281. if err != nil {
  1282. return err
  1283. }
  1284. cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
  1285. if err != nil {
  1286. return fmt.Errorf(errClientTLSAuth, err)
  1287. }
  1288. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  1289. transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
  1290. }
  1291. url := strings.Join([]string{"auth", "cert", "login"}, "/")
  1292. vaultResult, err := v.logical.WriteWithContext(ctx, url, nil)
  1293. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultWriteSecretData, err)
  1294. if err != nil {
  1295. return fmt.Errorf(errVaultRequest, err)
  1296. }
  1297. token, err := vaultResult.TokenID()
  1298. if err != nil {
  1299. return fmt.Errorf(errVaultToken, err)
  1300. }
  1301. v.client.SetToken(token)
  1302. return nil
  1303. }
  1304. func init() {
  1305. var vaultTokenCacheSize int
  1306. fs := pflag.NewFlagSet("vault", pflag.ExitOnError)
  1307. fs.BoolVar(&enableCache, "experimental-enable-vault-token-cache", false, "Enable experimental Vault token cache. External secrets will reuse the Vault token without creating a new one on each request.")
  1308. // max. 265k vault leases with 30bytes each ~= 7MB
  1309. fs.IntVar(&vaultTokenCacheSize, "experimental-vault-token-cache-size", 2<<17, "Maximum size of Vault token cache. When more tokens than Only used if --experimental-enable-vault-token-cache is set.")
  1310. lateInit := func() {
  1311. logger.Info("initializing vault cache with size=%d", vaultTokenCacheSize)
  1312. clientCache = cache.Must(vaultTokenCacheSize, func(client Client) {
  1313. err := revokeTokenIfValid(context.Background(), client)
  1314. if err != nil {
  1315. logger.Error(err, "unable to revoke cached token on eviction")
  1316. }
  1317. })
  1318. }
  1319. feature.Register(feature.Feature{
  1320. Flags: fs,
  1321. Initialize: lateInit,
  1322. })
  1323. esv1beta1.Register(&connector{
  1324. newVaultClient: newVaultClient,
  1325. }, &esv1beta1.SecretStoreProvider{
  1326. Vault: &esv1beta1.VaultProvider{},
  1327. })
  1328. }