vault.go 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139
  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. "context"
  15. "crypto/tls"
  16. "crypto/x509"
  17. "encoding/json"
  18. "errors"
  19. "fmt"
  20. "net/http"
  21. "os"
  22. "strconv"
  23. "strings"
  24. "github.com/go-logr/logr"
  25. vault "github.com/hashicorp/vault/api"
  26. approle "github.com/hashicorp/vault/api/auth/approle"
  27. authkubernetes "github.com/hashicorp/vault/api/auth/kubernetes"
  28. authldap "github.com/hashicorp/vault/api/auth/ldap"
  29. "github.com/tidwall/gjson"
  30. authenticationv1 "k8s.io/api/authentication/v1"
  31. corev1 "k8s.io/api/core/v1"
  32. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  33. "k8s.io/apimachinery/pkg/types"
  34. "k8s.io/client-go/kubernetes"
  35. typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  36. ctrl "sigs.k8s.io/controller-runtime"
  37. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  38. ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
  39. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  40. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  41. "github.com/external-secrets/external-secrets/pkg/find"
  42. "github.com/external-secrets/external-secrets/pkg/utils"
  43. )
  44. var (
  45. _ esv1beta1.Provider = &connector{}
  46. _ esv1beta1.SecretsClient = &client{}
  47. )
  48. const (
  49. serviceAccTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
  50. errVaultStore = "received invalid Vault SecretStore resource: %w"
  51. errVaultClient = "cannot setup new vault client: %w"
  52. errVaultCert = "cannot set Vault CA certificate: %w"
  53. errReadSecret = "cannot read secret data from Vault: %w"
  54. errAuthFormat = "cannot initialize Vault client: no valid auth method specified"
  55. errInvalidCredentials = "invalid vault credentials: %w"
  56. errDataField = "failed to find data field"
  57. errJSONUnmarshall = "failed to unmarshall JSON"
  58. errPathInvalid = "provided Path isn't a valid kv v2 path"
  59. errSecretFormat = "secret data not in expected format"
  60. errUnexpectedKey = "unexpected key in data: %s"
  61. errVaultToken = "cannot parse Vault authentication token: %w"
  62. errVaultRequest = "error from Vault request: %w"
  63. errServiceAccount = "cannot read Kubernetes service account token from file system: %w"
  64. errJwtNoTokenSource = "neither `secretRef` nor `kubernetesServiceAccountToken` was supplied as token source for jwt authentication"
  65. errUnsupportedKvVersion = "cannot perform find operations with kv version v1"
  66. errNotFound = "secret not found"
  67. errGetKubeSA = "cannot get Kubernetes service account %q: %w"
  68. errGetKubeSASecrets = "cannot find secrets bound to service account: %q"
  69. errGetKubeSANoToken = "cannot find token in secrets bound to service account: %q"
  70. errGetKubeSATokenRequest = "cannot request Kubernetes service account token for service account %q: %w"
  71. errGetKubeSecret = "cannot get Kubernetes secret %q: %w"
  72. errSecretKeyFmt = "cannot find secret data for key: %q"
  73. errConfigMapFmt = "cannot find config map data for key: %q"
  74. errClientTLSAuth = "error from Client TLS Auth: %q"
  75. errVaultRevokeToken = "error while revoking token: %w"
  76. errUnknownCAProvider = "unknown caProvider type given"
  77. errCANamespace = "cannot read secret for CAProvider due to missing namespace on kind ClusterSecretStore"
  78. errInvalidStore = "invalid store"
  79. errInvalidStoreSpec = "invalid store spec"
  80. errInvalidStoreProv = "invalid store provider"
  81. errInvalidVaultProv = "invalid vault provider"
  82. errInvalidAppRoleSec = "invalid Auth.AppRole.SecretRef: %w"
  83. errInvalidClientCert = "invalid Auth.Cert.ClientCert: %w"
  84. errInvalidCertSec = "invalid Auth.Cert.SecretRef: %w"
  85. errInvalidJwtSec = "invalid Auth.Jwt.SecretRef: %w"
  86. errInvalidJwtK8sSA = "invalid Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef: %w"
  87. errInvalidKubeSA = "invalid Auth.Kubernetes.ServiceAccountRef: %w"
  88. errInvalidKubeSec = "invalid Auth.Kubernetes.SecretRef: %w"
  89. errInvalidLdapSec = "invalid Auth.Ldap.SecretRef: %w"
  90. errInvalidTokenRef = "invalid Auth.TokenSecretRef: %w"
  91. )
  92. // https://github.com/external-secrets/external-secrets/issues/644
  93. var _ esv1beta1.SecretsClient = &client{}
  94. var _ esv1beta1.Provider = &connector{}
  95. type Auth interface {
  96. Login(ctx context.Context, authMethod vault.AuthMethod) (*vault.Secret, error)
  97. }
  98. type Token interface {
  99. RevokeSelfWithContext(ctx context.Context, token string) error
  100. LookupSelfWithContext(ctx context.Context) (*vault.Secret, error)
  101. }
  102. type Logical interface {
  103. ReadWithDataWithContext(ctx context.Context, path string, data map[string][]string) (*vault.Secret, error)
  104. ListWithContext(ctx context.Context, path string) (*vault.Secret, error)
  105. WriteWithContext(ctx context.Context, path string, data map[string]interface{}) (*vault.Secret, error)
  106. }
  107. type Client interface {
  108. SetToken(v string)
  109. Token() string
  110. ClearToken()
  111. Auth() Auth
  112. Logical() Logical
  113. AuthToken() Token
  114. SetNamespace(namespace string)
  115. AddHeader(key, value string)
  116. }
  117. type VClient struct {
  118. setToken func(v string)
  119. token func() string
  120. clearToken func()
  121. auth Auth
  122. logical Logical
  123. authToken Token
  124. setNamespace func(namespace string)
  125. addHeader func(key, value string)
  126. }
  127. func (v VClient) AddHeader(key, value string) {
  128. v.addHeader(key, value)
  129. }
  130. func (v VClient) SetNamespace(namespace string) {
  131. v.setNamespace(namespace)
  132. }
  133. func (v VClient) ClearToken() {
  134. v.clearToken()
  135. }
  136. func (v VClient) Token() string {
  137. return v.token()
  138. }
  139. func (v VClient) SetToken(token string) {
  140. v.setToken(token)
  141. }
  142. func (v VClient) Auth() Auth {
  143. return v.auth
  144. }
  145. func (v VClient) AuthToken() Token {
  146. return v.authToken
  147. }
  148. func (v VClient) Logical() Logical {
  149. return v.logical
  150. }
  151. type client struct {
  152. kube kclient.Client
  153. store *esv1beta1.VaultProvider
  154. log logr.Logger
  155. corev1 typedcorev1.CoreV1Interface
  156. client Client
  157. auth Auth
  158. logical Logical
  159. token Token
  160. namespace string
  161. storeKind string
  162. }
  163. func init() {
  164. esv1beta1.Register(&connector{
  165. newVaultClient: newVaultClient,
  166. }, &esv1beta1.SecretStoreProvider{
  167. Vault: &esv1beta1.VaultProvider{},
  168. })
  169. }
  170. func newVaultClient(c *vault.Config) (Client, error) {
  171. cl, err := vault.NewClient(c)
  172. if err != nil {
  173. return nil, err
  174. }
  175. auth := cl.Auth()
  176. logical := cl.Logical()
  177. token := cl.Auth().Token()
  178. out := VClient{
  179. setToken: cl.SetToken,
  180. token: cl.Token,
  181. clearToken: cl.ClearToken,
  182. auth: auth,
  183. authToken: token,
  184. logical: logical,
  185. setNamespace: cl.SetNamespace,
  186. addHeader: cl.AddHeader,
  187. }
  188. return out, nil
  189. }
  190. type connector struct {
  191. newVaultClient func(c *vault.Config) (Client, error)
  192. }
  193. // Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
  194. func (c *connector) Capabilities() esv1beta1.SecretStoreCapabilities {
  195. return esv1beta1.SecretStoreReadOnly
  196. }
  197. func (c *connector) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  198. // controller-runtime/client does not support TokenRequest or other subresource APIs
  199. // so we need to construct our own client and use it to fetch tokens
  200. // (for Kubernetes service account token auth)
  201. restCfg, err := ctrlcfg.GetConfig()
  202. if err != nil {
  203. return nil, err
  204. }
  205. clientset, err := kubernetes.NewForConfig(restCfg)
  206. if err != nil {
  207. return nil, err
  208. }
  209. return c.newClient(ctx, store, kube, clientset.CoreV1(), namespace)
  210. }
  211. func (c *connector) newClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, corev1 typedcorev1.CoreV1Interface, namespace string) (esv1beta1.SecretsClient, error) {
  212. storeSpec := store.GetSpec()
  213. if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.Vault == nil {
  214. return nil, errors.New(errVaultStore)
  215. }
  216. vaultSpec := storeSpec.Provider.Vault
  217. vStore := &client{
  218. kube: kube,
  219. corev1: corev1,
  220. store: vaultSpec,
  221. log: ctrl.Log.WithName("provider").WithName("vault"),
  222. namespace: namespace,
  223. storeKind: store.GetObjectKind().GroupVersionKind().Kind,
  224. }
  225. cfg, err := vStore.newConfig()
  226. if err != nil {
  227. return nil, err
  228. }
  229. client, err := c.newVaultClient(cfg)
  230. if err != nil {
  231. return nil, fmt.Errorf(errVaultClient, err)
  232. }
  233. if vaultSpec.Namespace != nil {
  234. client.SetNamespace(*vaultSpec.Namespace)
  235. }
  236. if vaultSpec.ReadYourWrites && vaultSpec.ForwardInconsistent {
  237. client.AddHeader("X-Vault-Inconsistent", "forward-active-node")
  238. }
  239. vStore.client = client
  240. vStore.auth = client.Auth()
  241. vStore.logical = client.Logical()
  242. vStore.token = client.AuthToken()
  243. if err := vStore.setAuth(ctx, cfg); err != nil {
  244. return nil, err
  245. }
  246. return vStore, nil
  247. }
  248. func (c *connector) ValidateStore(store esv1beta1.GenericStore) error {
  249. if store == nil {
  250. return fmt.Errorf(errInvalidStore)
  251. }
  252. spc := store.GetSpec()
  253. if spc == nil {
  254. return fmt.Errorf(errInvalidStoreSpec)
  255. }
  256. if spc.Provider == nil {
  257. return fmt.Errorf(errInvalidStoreProv)
  258. }
  259. p := spc.Provider.Vault
  260. if p == nil {
  261. return fmt.Errorf(errInvalidVaultProv)
  262. }
  263. if p.Auth.AppRole != nil {
  264. if err := utils.ValidateSecretSelector(store, p.Auth.AppRole.SecretRef); err != nil {
  265. return fmt.Errorf(errInvalidAppRoleSec, err)
  266. }
  267. }
  268. if p.Auth.Cert != nil {
  269. if err := utils.ValidateSecretSelector(store, p.Auth.Cert.ClientCert); err != nil {
  270. return fmt.Errorf(errInvalidClientCert, err)
  271. }
  272. if err := utils.ValidateSecretSelector(store, p.Auth.Cert.SecretRef); err != nil {
  273. return fmt.Errorf(errInvalidCertSec, err)
  274. }
  275. }
  276. if p.Auth.Jwt != nil {
  277. if p.Auth.Jwt.SecretRef != nil {
  278. if err := utils.ValidateSecretSelector(store, *p.Auth.Jwt.SecretRef); err != nil {
  279. return fmt.Errorf(errInvalidJwtSec, err)
  280. }
  281. } else if p.Auth.Jwt.KubernetesServiceAccountToken != nil {
  282. if err := utils.ValidateServiceAccountSelector(store, p.Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef); err != nil {
  283. return fmt.Errorf(errInvalidJwtK8sSA, err)
  284. }
  285. } else {
  286. return fmt.Errorf(errJwtNoTokenSource)
  287. }
  288. }
  289. if p.Auth.Kubernetes != nil {
  290. if p.Auth.Kubernetes.ServiceAccountRef != nil {
  291. if err := utils.ValidateServiceAccountSelector(store, *p.Auth.Kubernetes.ServiceAccountRef); err != nil {
  292. return fmt.Errorf(errInvalidKubeSA, err)
  293. }
  294. }
  295. if p.Auth.Kubernetes.SecretRef != nil {
  296. if err := utils.ValidateSecretSelector(store, *p.Auth.Kubernetes.SecretRef); err != nil {
  297. return fmt.Errorf(errInvalidKubeSec, err)
  298. }
  299. }
  300. }
  301. if p.Auth.Ldap != nil {
  302. if err := utils.ValidateSecretSelector(store, p.Auth.Ldap.SecretRef); err != nil {
  303. return fmt.Errorf(errInvalidLdapSec, err)
  304. }
  305. }
  306. if p.Auth.TokenSecretRef != nil {
  307. if err := utils.ValidateSecretSelector(store, *p.Auth.TokenSecretRef); err != nil {
  308. return fmt.Errorf(errInvalidTokenRef, err)
  309. }
  310. }
  311. return nil
  312. }
  313. // Not Implemented SetSecret.
  314. func (v *client) SetSecret() error {
  315. return fmt.Errorf("not implemented")
  316. }
  317. // GetAllSecrets gets multiple secrets from the provider and loads into a kubernetes secret.
  318. // First load all secrets from secretStore path configuration
  319. // Then, gets secrets from a matching name or matching custom_metadata.
  320. func (v *client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  321. if v.store.Version == esv1beta1.VaultKVStoreV1 {
  322. return nil, errors.New(errUnsupportedKvVersion)
  323. }
  324. searchPath := ""
  325. if ref.Path != nil {
  326. searchPath = *ref.Path + "/"
  327. }
  328. potentialSecrets, err := v.listSecrets(ctx, searchPath)
  329. if err != nil {
  330. return nil, err
  331. }
  332. if ref.Name != nil {
  333. return v.findSecretsFromName(ctx, potentialSecrets, *ref.Name)
  334. }
  335. return v.findSecretsFromTags(ctx, potentialSecrets, ref.Tags)
  336. }
  337. func (v *client) findSecretsFromTags(ctx context.Context, candidates []string, tags map[string]string) (map[string][]byte, error) {
  338. secrets := make(map[string][]byte)
  339. for _, name := range candidates {
  340. match := true
  341. metadata, err := v.readSecretMetadata(ctx, name)
  342. if err != nil {
  343. return nil, err
  344. }
  345. for tk, tv := range tags {
  346. p, ok := metadata[tk]
  347. if !ok || p != tv {
  348. match = false
  349. break
  350. }
  351. }
  352. if match {
  353. secret, err := v.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: name})
  354. if err != nil {
  355. return nil, err
  356. }
  357. secrets[name] = secret
  358. }
  359. }
  360. return secrets, nil
  361. }
  362. func (v *client) findSecretsFromName(ctx context.Context, candidates []string, ref esv1beta1.FindName) (map[string][]byte, error) {
  363. secrets := make(map[string][]byte)
  364. matcher, err := find.New(ref)
  365. if err != nil {
  366. return nil, err
  367. }
  368. for _, name := range candidates {
  369. ok := matcher.MatchName(name)
  370. if ok {
  371. secret, err := v.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: name})
  372. if err != nil {
  373. return nil, err
  374. }
  375. secrets[name] = secret
  376. }
  377. }
  378. return secrets, nil
  379. }
  380. func (v *client) listSecrets(ctx context.Context, path string) ([]string, error) {
  381. secrets := make([]string, 0)
  382. url, err := v.buildMetadataPath(path)
  383. if err != nil {
  384. return nil, err
  385. }
  386. secret, err := v.logical.ListWithContext(ctx, url)
  387. if err != nil {
  388. return nil, fmt.Errorf(errReadSecret, err)
  389. }
  390. t, ok := secret.Data["keys"]
  391. if !ok {
  392. return nil, nil
  393. }
  394. paths := t.([]interface{})
  395. for _, p := range paths {
  396. strPath := p.(string)
  397. fullPath := path + strPath // because path always ends with a /
  398. if path == "" {
  399. fullPath = strPath
  400. }
  401. // Recurrently find secrets
  402. if !strings.HasSuffix(p.(string), "/") {
  403. secrets = append(secrets, fullPath)
  404. } else {
  405. partial, err := v.listSecrets(ctx, fullPath)
  406. if err != nil {
  407. return nil, err
  408. }
  409. secrets = append(secrets, partial...)
  410. }
  411. }
  412. return secrets, nil
  413. }
  414. func (v *client) readSecretMetadata(ctx context.Context, path string) (map[string]string, error) {
  415. metadata := make(map[string]string)
  416. url, err := v.buildMetadataPath(path)
  417. if err != nil {
  418. return nil, err
  419. }
  420. secret, err := v.logical.ReadWithDataWithContext(ctx, url, nil)
  421. if err != nil {
  422. return nil, fmt.Errorf(errReadSecret, err)
  423. }
  424. if secret == nil {
  425. return nil, errors.New(errNotFound)
  426. }
  427. t, ok := secret.Data["custom_metadata"]
  428. if !ok {
  429. return nil, nil
  430. }
  431. d, ok := t.(map[string]interface{})
  432. if !ok {
  433. return metadata, nil
  434. }
  435. for k, v := range d {
  436. metadata[k] = v.(string)
  437. }
  438. return metadata, nil
  439. }
  440. // GetSecret supports two types:
  441. // 1. get the full secret as json-encoded value
  442. // by leaving the ref.Property empty.
  443. // 2. get a key from the secret.
  444. // Nested values are supported by specifying a gjson expression
  445. func (v *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  446. data, err := v.readSecret(ctx, ref.Key, ref.Version)
  447. if err != nil {
  448. return nil, err
  449. }
  450. jsonStr, err := json.Marshal(data)
  451. if err != nil {
  452. return nil, err
  453. }
  454. // (1): return raw json if no property is defined
  455. if ref.Property == "" {
  456. return jsonStr, nil
  457. }
  458. // For backwards compatibility we want the
  459. // actual keys to take precedence over gjson syntax
  460. // (2): extract key from secret with property
  461. if _, ok := data[ref.Property]; ok {
  462. return getTypedKey(data, ref.Property)
  463. }
  464. // (3): extract key from secret using gjson
  465. val := gjson.Get(string(jsonStr), ref.Property)
  466. if !val.Exists() {
  467. return nil, fmt.Errorf(errSecretKeyFmt, ref.Property)
  468. }
  469. return []byte(val.String()), nil
  470. }
  471. // GetSecretMap supports two modes of operation:
  472. // 1. get the full secret from the vault data payload (by leaving .property empty).
  473. // 2. extract key/value pairs from a (nested) object.
  474. func (v *client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  475. data, err := v.GetSecret(ctx, ref)
  476. if err != nil {
  477. return nil, err
  478. }
  479. var secretData map[string]interface{}
  480. err = json.Unmarshal(data, &secretData)
  481. if err != nil {
  482. return nil, err
  483. }
  484. byteMap := make(map[string][]byte, len(secretData))
  485. for k := range secretData {
  486. byteMap[k], err = getTypedKey(secretData, k)
  487. if err != nil {
  488. return nil, err
  489. }
  490. }
  491. return byteMap, nil
  492. }
  493. func getTypedKey(data map[string]interface{}, key string) ([]byte, error) {
  494. v, ok := data[key]
  495. if !ok {
  496. return nil, fmt.Errorf(errUnexpectedKey, key)
  497. }
  498. switch t := v.(type) {
  499. case string:
  500. return []byte(t), nil
  501. case map[string]interface{}:
  502. return json.Marshal(t)
  503. case []byte:
  504. return t, nil
  505. // also covers int and float32 due to json.Marshal
  506. case float64:
  507. return []byte(strconv.FormatFloat(t, 'f', -1, 64)), nil
  508. case bool:
  509. return []byte(strconv.FormatBool(t)), nil
  510. case nil:
  511. return []byte(nil), nil
  512. default:
  513. return nil, errors.New(errSecretFormat)
  514. }
  515. }
  516. func (v *client) Close(ctx context.Context) error {
  517. // Revoke the token if we have one set and it wasn't sourced from a TokenSecretRef
  518. if v.client.Token() != "" && v.store.Auth.TokenSecretRef == nil {
  519. revoke, err := checkToken(ctx, v)
  520. if err != nil {
  521. return fmt.Errorf(errVaultRevokeToken, err)
  522. }
  523. if revoke {
  524. err = v.token.RevokeSelfWithContext(ctx, v.client.Token())
  525. if err != nil {
  526. return fmt.Errorf(errVaultRevokeToken, err)
  527. }
  528. v.client.ClearToken()
  529. }
  530. }
  531. return nil
  532. }
  533. func (v *client) Validate() (esv1beta1.ValidationResult, error) {
  534. _, err := checkToken(context.Background(), v)
  535. if err != nil {
  536. return esv1beta1.ValidationResultError, fmt.Errorf(errInvalidCredentials, err)
  537. }
  538. return esv1beta1.ValidationResultReady, nil
  539. }
  540. func (v *client) buildMetadataPath(path string) (string, error) {
  541. var url string
  542. if v.store.Path == nil && !strings.Contains(path, "data") {
  543. return "", fmt.Errorf(errPathInvalid)
  544. }
  545. if v.store.Path == nil {
  546. path = strings.Replace(path, "data", "metadata", 1)
  547. url = path
  548. } else {
  549. url = fmt.Sprintf("%s/metadata/%s", *v.store.Path, path)
  550. }
  551. return url, nil
  552. }
  553. func (v *client) buildPath(path string) string {
  554. optionalMount := v.store.Path
  555. origPath := strings.Split(path, "/")
  556. newPath := make([]string, 0)
  557. cursor := 0
  558. if optionalMount != nil && origPath[0] != *optionalMount {
  559. // Default case before path was optional
  560. // Ensure that the requested path includes the SecretStores paths as prefix
  561. newPath = append(newPath, *optionalMount)
  562. } else {
  563. newPath = append(newPath, origPath[cursor])
  564. cursor++
  565. }
  566. if v.store.Version == esv1beta1.VaultKVStoreV2 {
  567. // Add the required `data` part of the URL for the v2 API
  568. if len(origPath) < 2 || origPath[1] != "data" {
  569. newPath = append(newPath, "data")
  570. }
  571. }
  572. newPath = append(newPath, origPath[cursor:]...)
  573. returnPath := strings.Join(newPath, "/")
  574. return returnPath
  575. }
  576. func (v *client) readSecret(ctx context.Context, path, version string) (map[string]interface{}, error) {
  577. dataPath := v.buildPath(path)
  578. // path formated according to vault docs for v1 and v2 API
  579. // v1: https://www.vaultproject.io/api-docs/secret/kv/kv-v1#read-secret
  580. // v2: https://www.vaultproject.io/api/secret/kv/kv-v2#read-secret-version
  581. var params map[string][]string
  582. if version != "" {
  583. params = make(map[string][]string)
  584. params["version"] = []string{version}
  585. }
  586. vaultSecret, err := v.logical.ReadWithDataWithContext(ctx, dataPath, params)
  587. if err != nil {
  588. return nil, fmt.Errorf(errReadSecret, err)
  589. }
  590. if vaultSecret == nil {
  591. return nil, errors.New(errNotFound)
  592. }
  593. secretData := vaultSecret.Data
  594. if v.store.Version == esv1beta1.VaultKVStoreV2 {
  595. // Vault KV2 has data embedded within sub-field
  596. // reference - https://www.vaultproject.io/api/secret/kv/kv-v2#read-secret-version
  597. dataInt, ok := vaultSecret.Data["data"]
  598. if !ok {
  599. return nil, errors.New(errDataField)
  600. }
  601. secretData, ok = dataInt.(map[string]interface{})
  602. if !ok {
  603. return nil, errors.New(errJSONUnmarshall)
  604. }
  605. }
  606. return secretData, nil
  607. }
  608. func (v *client) newConfig() (*vault.Config, error) {
  609. cfg := vault.DefaultConfig()
  610. cfg.Address = v.store.Server
  611. // In a controller-runtime context, we rely on the reconciliation process for retrying
  612. cfg.MaxRetries = 0
  613. if len(v.store.CABundle) == 0 && v.store.CAProvider == nil {
  614. return cfg, nil
  615. }
  616. caCertPool := x509.NewCertPool()
  617. if len(v.store.CABundle) > 0 {
  618. ok := caCertPool.AppendCertsFromPEM(v.store.CABundle)
  619. if !ok {
  620. return nil, errors.New(errVaultCert)
  621. }
  622. }
  623. if v.store.CAProvider != nil && v.storeKind == esv1beta1.ClusterSecretStoreKind && v.store.CAProvider.Namespace == nil {
  624. return nil, errors.New(errCANamespace)
  625. }
  626. if v.store.CAProvider != nil {
  627. var cert []byte
  628. var err error
  629. switch v.store.CAProvider.Type {
  630. case esv1beta1.CAProviderTypeSecret:
  631. cert, err = getCertFromSecret(v)
  632. case esv1beta1.CAProviderTypeConfigMap:
  633. cert, err = getCertFromConfigMap(v)
  634. default:
  635. return nil, errors.New(errUnknownCAProvider)
  636. }
  637. if err != nil {
  638. return nil, err
  639. }
  640. ok := caCertPool.AppendCertsFromPEM(cert)
  641. if !ok {
  642. return nil, errors.New(errVaultCert)
  643. }
  644. }
  645. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  646. transport.TLSClientConfig.RootCAs = caCertPool
  647. }
  648. // If either read-after-write consistency feature is enabled, enable ReadYourWrites
  649. cfg.ReadYourWrites = v.store.ReadYourWrites || v.store.ForwardInconsistent
  650. return cfg, nil
  651. }
  652. func getCertFromSecret(v *client) ([]byte, error) {
  653. secretRef := esmeta.SecretKeySelector{
  654. Name: v.store.CAProvider.Name,
  655. Key: v.store.CAProvider.Key,
  656. }
  657. if v.store.CAProvider.Namespace != nil {
  658. secretRef.Namespace = v.store.CAProvider.Namespace
  659. }
  660. ctx := context.Background()
  661. res, err := v.secretKeyRef(ctx, &secretRef)
  662. if err != nil {
  663. return nil, fmt.Errorf(errVaultCert, err)
  664. }
  665. return []byte(res), nil
  666. }
  667. func getCertFromConfigMap(v *client) ([]byte, error) {
  668. objKey := types.NamespacedName{
  669. Name: v.store.CAProvider.Name,
  670. }
  671. if v.store.CAProvider.Namespace != nil {
  672. objKey.Namespace = *v.store.CAProvider.Namespace
  673. }
  674. configMapRef := &corev1.ConfigMap{}
  675. ctx := context.Background()
  676. err := v.kube.Get(ctx, objKey, configMapRef)
  677. if err != nil {
  678. return nil, fmt.Errorf(errVaultCert, err)
  679. }
  680. val, ok := configMapRef.Data[v.store.CAProvider.Key]
  681. if !ok {
  682. return nil, fmt.Errorf(errConfigMapFmt, v.store.CAProvider.Key)
  683. }
  684. return []byte(val), nil
  685. }
  686. func (v *client) setAuth(ctx context.Context, cfg *vault.Config) error {
  687. tokenExists, err := setSecretKeyToken(ctx, v)
  688. if tokenExists {
  689. return err
  690. }
  691. tokenExists, err = setAppRoleToken(ctx, v)
  692. if tokenExists {
  693. return err
  694. }
  695. tokenExists, err = setKubernetesAuthToken(ctx, v)
  696. if tokenExists {
  697. return err
  698. }
  699. tokenExists, err = setLdapAuthToken(ctx, v)
  700. if tokenExists {
  701. return err
  702. }
  703. tokenExists, err = setJwtAuthToken(ctx, v)
  704. if tokenExists {
  705. return err
  706. }
  707. tokenExists, err = setCertAuthToken(ctx, v, cfg)
  708. if tokenExists {
  709. return err
  710. }
  711. return errors.New(errAuthFormat)
  712. }
  713. func setAppRoleToken(ctx context.Context, v *client) (bool, error) {
  714. tokenRef := v.store.Auth.TokenSecretRef
  715. if tokenRef != nil {
  716. token, err := v.secretKeyRef(ctx, tokenRef)
  717. if err != nil {
  718. return true, err
  719. }
  720. v.client.SetToken(token)
  721. return true, nil
  722. }
  723. return false, nil
  724. }
  725. func setSecretKeyToken(ctx context.Context, v *client) (bool, error) {
  726. appRole := v.store.Auth.AppRole
  727. if appRole != nil {
  728. err := v.requestTokenWithAppRoleRef(ctx, appRole)
  729. if err != nil {
  730. return true, err
  731. }
  732. return true, nil
  733. }
  734. return false, nil
  735. }
  736. func setKubernetesAuthToken(ctx context.Context, v *client) (bool, error) {
  737. kubernetesAuth := v.store.Auth.Kubernetes
  738. if kubernetesAuth != nil {
  739. err := v.requestTokenWithKubernetesAuth(ctx, kubernetesAuth)
  740. if err != nil {
  741. return true, err
  742. }
  743. return true, nil
  744. }
  745. return false, nil
  746. }
  747. func setLdapAuthToken(ctx context.Context, v *client) (bool, error) {
  748. ldapAuth := v.store.Auth.Ldap
  749. if ldapAuth != nil {
  750. err := v.requestTokenWithLdapAuth(ctx, ldapAuth)
  751. if err != nil {
  752. return true, err
  753. }
  754. return true, nil
  755. }
  756. return false, nil
  757. }
  758. func setJwtAuthToken(ctx context.Context, v *client) (bool, error) {
  759. jwtAuth := v.store.Auth.Jwt
  760. if jwtAuth != nil {
  761. err := v.requestTokenWithJwtAuth(ctx, jwtAuth)
  762. if err != nil {
  763. return true, err
  764. }
  765. return true, nil
  766. }
  767. return false, nil
  768. }
  769. func setCertAuthToken(ctx context.Context, v *client, cfg *vault.Config) (bool, error) {
  770. certAuth := v.store.Auth.Cert
  771. if certAuth != nil {
  772. err := v.requestTokenWithCertAuth(ctx, certAuth, cfg)
  773. if err != nil {
  774. return true, err
  775. }
  776. return true, nil
  777. }
  778. return false, nil
  779. }
  780. func (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccountRef *esmeta.ServiceAccountSelector) (string, error) {
  781. serviceAccount := &corev1.ServiceAccount{}
  782. ref := types.NamespacedName{
  783. Namespace: v.namespace,
  784. Name: serviceAccountRef.Name,
  785. }
  786. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  787. (serviceAccountRef.Namespace != nil) {
  788. ref.Namespace = *serviceAccountRef.Namespace
  789. }
  790. err := v.kube.Get(ctx, ref, serviceAccount)
  791. if err != nil {
  792. return "", fmt.Errorf(errGetKubeSA, ref.Name, err)
  793. }
  794. if len(serviceAccount.Secrets) == 0 {
  795. return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
  796. }
  797. for _, tokenRef := range serviceAccount.Secrets {
  798. retval, err := v.secretKeyRef(ctx, &esmeta.SecretKeySelector{
  799. Name: tokenRef.Name,
  800. Namespace: &ref.Namespace,
  801. Key: "token",
  802. })
  803. if err != nil {
  804. continue
  805. }
  806. return retval, nil
  807. }
  808. return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
  809. }
  810. func (v *client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
  811. secret := &corev1.Secret{}
  812. ref := types.NamespacedName{
  813. Namespace: v.namespace,
  814. Name: secretRef.Name,
  815. }
  816. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  817. (secretRef.Namespace != nil) {
  818. ref.Namespace = *secretRef.Namespace
  819. }
  820. err := v.kube.Get(ctx, ref, secret)
  821. if err != nil {
  822. return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
  823. }
  824. keyBytes, ok := secret.Data[secretRef.Key]
  825. if !ok {
  826. return "", fmt.Errorf(errSecretKeyFmt, secretRef.Key)
  827. }
  828. value := string(keyBytes)
  829. valueStr := strings.TrimSpace(value)
  830. return valueStr, nil
  831. }
  832. func (v *client) serviceAccountToken(ctx context.Context, serviceAccountRef esmeta.ServiceAccountSelector, audiences []string, expirationSeconds int64) (string, error) {
  833. tokenRequest := &authenticationv1.TokenRequest{
  834. ObjectMeta: metav1.ObjectMeta{
  835. Namespace: v.namespace,
  836. },
  837. Spec: authenticationv1.TokenRequestSpec{
  838. Audiences: audiences,
  839. ExpirationSeconds: &expirationSeconds,
  840. },
  841. }
  842. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  843. (serviceAccountRef.Namespace != nil) {
  844. tokenRequest.Namespace = *serviceAccountRef.Namespace
  845. }
  846. tokenResponse, err := v.corev1.ServiceAccounts(tokenRequest.Namespace).CreateToken(ctx, serviceAccountRef.Name, tokenRequest, metav1.CreateOptions{})
  847. if err != nil {
  848. return "", fmt.Errorf(errGetKubeSATokenRequest, serviceAccountRef.Name, err)
  849. }
  850. return tokenResponse.Status.Token, nil
  851. }
  852. // checkToken does a lookup and checks if the provided token exists.
  853. func checkToken(ctx context.Context, vStore *client) (bool, error) {
  854. // https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
  855. resp, err := vStore.token.LookupSelfWithContext(ctx)
  856. if err != nil {
  857. return false, err
  858. }
  859. t, ok := resp.Data["type"]
  860. if !ok {
  861. return false, fmt.Errorf("could not assert token type")
  862. }
  863. tokenType := t.(string)
  864. if tokenType == "batch" {
  865. return false, nil
  866. }
  867. return true, nil
  868. }
  869. func (v *client) requestTokenWithAppRoleRef(ctx context.Context, appRole *esv1beta1.VaultAppRole) error {
  870. roleID := strings.TrimSpace(appRole.RoleID)
  871. secretID, err := v.secretKeyRef(ctx, &appRole.SecretRef)
  872. if err != nil {
  873. return err
  874. }
  875. secret := approle.SecretID{FromString: secretID}
  876. appRoleClient, err := approle.NewAppRoleAuth(roleID, &secret, approle.WithMountPath(appRole.Path))
  877. if err != nil {
  878. return err
  879. }
  880. _, err = v.auth.Login(ctx, appRoleClient)
  881. if err != nil {
  882. return err
  883. }
  884. return nil
  885. }
  886. func (v *client) requestTokenWithKubernetesAuth(ctx context.Context, kubernetesAuth *esv1beta1.VaultKubernetesAuth) error {
  887. jwtString, err := getJwtString(ctx, v, kubernetesAuth)
  888. if err != nil {
  889. return err
  890. }
  891. k, err := authkubernetes.NewKubernetesAuth(kubernetesAuth.Role, authkubernetes.WithServiceAccountToken(jwtString), authkubernetes.WithMountPath(kubernetesAuth.Path))
  892. if err != nil {
  893. return err
  894. }
  895. _, err = v.auth.Login(ctx, k)
  896. if err != nil {
  897. return err
  898. }
  899. return nil
  900. }
  901. func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.VaultKubernetesAuth) (string, error) {
  902. if kubernetesAuth.ServiceAccountRef != nil {
  903. jwt, err := v.secretKeyRefForServiceAccount(ctx, kubernetesAuth.ServiceAccountRef)
  904. if err != nil {
  905. return "", err
  906. }
  907. return jwt, nil
  908. } else if kubernetesAuth.SecretRef != nil {
  909. tokenRef := kubernetesAuth.SecretRef
  910. if tokenRef.Key == "" {
  911. tokenRef = kubernetesAuth.SecretRef.DeepCopy()
  912. tokenRef.Key = "token"
  913. }
  914. jwt, err := v.secretKeyRef(ctx, tokenRef)
  915. if err != nil {
  916. return "", err
  917. }
  918. return jwt, nil
  919. } else {
  920. // Kubernetes authentication is specified, but without a referenced
  921. // Kubernetes secret. We check if the file path for in-cluster service account
  922. // exists and attempt to use the token for Vault Kubernetes auth.
  923. if _, err := os.Stat(serviceAccTokenPath); err != nil {
  924. return "", fmt.Errorf(errServiceAccount, err)
  925. }
  926. jwtByte, err := os.ReadFile(serviceAccTokenPath)
  927. if err != nil {
  928. return "", fmt.Errorf(errServiceAccount, err)
  929. }
  930. return string(jwtByte), nil
  931. }
  932. }
  933. func (v *client) requestTokenWithLdapAuth(ctx context.Context, ldapAuth *esv1beta1.VaultLdapAuth) error {
  934. username := strings.TrimSpace(ldapAuth.Username)
  935. password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
  936. if err != nil {
  937. return err
  938. }
  939. pass := authldap.Password{FromString: password}
  940. l, err := authldap.NewLDAPAuth(username, &pass, authldap.WithMountPath(ldapAuth.Path))
  941. if err != nil {
  942. return err
  943. }
  944. _, err = v.auth.Login(ctx, l)
  945. if err != nil {
  946. return err
  947. }
  948. return nil
  949. }
  950. func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1.VaultJwtAuth) error {
  951. role := strings.TrimSpace(jwtAuth.Role)
  952. var jwt string
  953. var err error
  954. if jwtAuth.SecretRef != nil {
  955. jwt, err = v.secretKeyRef(ctx, jwtAuth.SecretRef)
  956. } else if k8sServiceAccountToken := jwtAuth.KubernetesServiceAccountToken; k8sServiceAccountToken != nil {
  957. audiences := k8sServiceAccountToken.Audiences
  958. if audiences == nil {
  959. audiences = &[]string{"vault"}
  960. }
  961. expirationSeconds := k8sServiceAccountToken.ExpirationSeconds
  962. if expirationSeconds == nil {
  963. tmp := int64(600)
  964. expirationSeconds = &tmp
  965. }
  966. jwt, err = v.serviceAccountToken(ctx, k8sServiceAccountToken.ServiceAccountRef, *audiences, *expirationSeconds)
  967. } else {
  968. err = fmt.Errorf(errJwtNoTokenSource)
  969. }
  970. if err != nil {
  971. return err
  972. }
  973. parameters := map[string]interface{}{
  974. "role": role,
  975. "jwt": jwt,
  976. }
  977. url := strings.Join([]string{"auth", jwtAuth.Path, "login"}, "/")
  978. vaultResult, err := v.logical.WriteWithContext(ctx, url, parameters)
  979. if err != nil {
  980. return err
  981. }
  982. token, err := vaultResult.TokenID()
  983. if err != nil {
  984. return fmt.Errorf(errVaultToken, err)
  985. }
  986. v.client.SetToken(token)
  987. return nil
  988. }
  989. func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1beta1.VaultCertAuth, cfg *vault.Config) error {
  990. clientKey, err := v.secretKeyRef(ctx, &certAuth.SecretRef)
  991. if err != nil {
  992. return err
  993. }
  994. clientCert, err := v.secretKeyRef(ctx, &certAuth.ClientCert)
  995. if err != nil {
  996. return err
  997. }
  998. cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
  999. if err != nil {
  1000. return fmt.Errorf(errClientTLSAuth, err)
  1001. }
  1002. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  1003. transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
  1004. }
  1005. url := strings.Join([]string{"auth", "cert", "login"}, "/")
  1006. vaultResult, err := v.logical.WriteWithContext(ctx, url, nil)
  1007. if err != nil {
  1008. return fmt.Errorf(errVaultRequest, err)
  1009. }
  1010. token, err := vaultResult.TokenID()
  1011. if err != nil {
  1012. return fmt.Errorf(errVaultToken, err)
  1013. }
  1014. v.client.SetToken(token)
  1015. return nil
  1016. }