vault.go 32 KB

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