vault.go 29 KB

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