vault.go 29 KB

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