vault.go 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  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. corev1 "k8s.io/api/core/v1"
  28. "k8s.io/apimachinery/pkg/types"
  29. ctrl "sigs.k8s.io/controller-runtime"
  30. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  31. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  32. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  33. "github.com/external-secrets/external-secrets/pkg/find"
  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. matcher, err := find.New(ref)
  254. if err != nil {
  255. return nil, err
  256. }
  257. for _, name := range candidates {
  258. ok := matcher.MatchName(name)
  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. // In a controller-runtime context, we rely on the reconciliation process for retrying
  507. cfg.MaxRetries = 0
  508. if len(v.store.CABundle) == 0 && v.store.CAProvider == nil {
  509. return cfg, nil
  510. }
  511. caCertPool := x509.NewCertPool()
  512. if len(v.store.CABundle) > 0 {
  513. ok := caCertPool.AppendCertsFromPEM(v.store.CABundle)
  514. if !ok {
  515. return nil, errors.New(errVaultCert)
  516. }
  517. }
  518. if v.store.CAProvider != nil && v.storeKind == esv1beta1.ClusterSecretStoreKind && v.store.CAProvider.Namespace == nil {
  519. return nil, errors.New(errCANamespace)
  520. }
  521. if v.store.CAProvider != nil {
  522. var cert []byte
  523. var err error
  524. switch v.store.CAProvider.Type {
  525. case esv1beta1.CAProviderTypeSecret:
  526. cert, err = getCertFromSecret(v)
  527. case esv1beta1.CAProviderTypeConfigMap:
  528. cert, err = getCertFromConfigMap(v)
  529. default:
  530. return nil, errors.New(errUnknownCAProvider)
  531. }
  532. if err != nil {
  533. return nil, err
  534. }
  535. ok := caCertPool.AppendCertsFromPEM(cert)
  536. if !ok {
  537. return nil, errors.New(errVaultCert)
  538. }
  539. }
  540. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  541. transport.TLSClientConfig.RootCAs = caCertPool
  542. }
  543. // If either read-after-write consistency feature is enabled, enable ReadYourWrites
  544. cfg.ReadYourWrites = v.store.ReadYourWrites || v.store.ForwardInconsistent
  545. return cfg, nil
  546. }
  547. func getCertFromSecret(v *client) ([]byte, error) {
  548. secretRef := esmeta.SecretKeySelector{
  549. Name: v.store.CAProvider.Name,
  550. Key: v.store.CAProvider.Key,
  551. }
  552. if v.store.CAProvider.Namespace != nil {
  553. secretRef.Namespace = v.store.CAProvider.Namespace
  554. }
  555. ctx := context.Background()
  556. res, err := v.secretKeyRef(ctx, &secretRef)
  557. if err != nil {
  558. return nil, fmt.Errorf(errVaultCert, err)
  559. }
  560. return []byte(res), nil
  561. }
  562. func getCertFromConfigMap(v *client) ([]byte, error) {
  563. objKey := types.NamespacedName{
  564. Name: v.store.CAProvider.Name,
  565. }
  566. if v.store.CAProvider.Namespace != nil {
  567. objKey.Namespace = *v.store.CAProvider.Namespace
  568. }
  569. configMapRef := &corev1.ConfigMap{}
  570. ctx := context.Background()
  571. err := v.kube.Get(ctx, objKey, configMapRef)
  572. if err != nil {
  573. return nil, fmt.Errorf(errVaultCert, err)
  574. }
  575. val, ok := configMapRef.Data[v.store.CAProvider.Key]
  576. if !ok {
  577. return nil, fmt.Errorf(errConfigMapFmt, v.store.CAProvider.Key)
  578. }
  579. return []byte(val), nil
  580. }
  581. func (v *client) setAuth(ctx context.Context, client Client, cfg *vault.Config) error {
  582. tokenExists, err := setSecretKeyToken(ctx, v, client)
  583. if tokenExists {
  584. return err
  585. }
  586. tokenExists, err = setAppRoleToken(ctx, v, client)
  587. if tokenExists {
  588. return err
  589. }
  590. tokenExists, err = setKubernetesAuthToken(ctx, v, client)
  591. if tokenExists {
  592. return err
  593. }
  594. tokenExists, err = setLdapAuthToken(ctx, v, client)
  595. if tokenExists {
  596. return err
  597. }
  598. tokenExists, err = setJwtAuthToken(ctx, v, client)
  599. if tokenExists {
  600. return err
  601. }
  602. tokenExists, err = setCertAuthToken(ctx, v, client, cfg)
  603. if tokenExists {
  604. return err
  605. }
  606. return errors.New(errAuthFormat)
  607. }
  608. func setAppRoleToken(ctx context.Context, v *client, client Client) (bool, error) {
  609. tokenRef := v.store.Auth.TokenSecretRef
  610. if tokenRef != nil {
  611. token, err := v.secretKeyRef(ctx, tokenRef)
  612. if err != nil {
  613. return true, err
  614. }
  615. client.SetToken(token)
  616. return true, nil
  617. }
  618. return false, nil
  619. }
  620. func setSecretKeyToken(ctx context.Context, v *client, client Client) (bool, error) {
  621. appRole := v.store.Auth.AppRole
  622. if appRole != nil {
  623. token, err := v.requestTokenWithAppRoleRef(ctx, client, appRole)
  624. if err != nil {
  625. return true, err
  626. }
  627. client.SetToken(token)
  628. return true, nil
  629. }
  630. return false, nil
  631. }
  632. func setKubernetesAuthToken(ctx context.Context, v *client, client Client) (bool, error) {
  633. kubernetesAuth := v.store.Auth.Kubernetes
  634. if kubernetesAuth != nil {
  635. token, err := v.requestTokenWithKubernetesAuth(ctx, client, kubernetesAuth)
  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 setLdapAuthToken(ctx context.Context, v *client, client Client) (bool, error) {
  645. ldapAuth := v.store.Auth.Ldap
  646. if ldapAuth != nil {
  647. token, err := v.requestTokenWithLdapAuth(ctx, client, ldapAuth)
  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 setJwtAuthToken(ctx context.Context, v *client, client Client) (bool, error) {
  657. jwtAuth := v.store.Auth.Jwt
  658. if jwtAuth != nil {
  659. token, err := v.requestTokenWithJwtAuth(ctx, client, jwtAuth)
  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 setCertAuthToken(ctx context.Context, v *client, client Client, cfg *vault.Config) (bool, error) {
  669. certAuth := v.store.Auth.Cert
  670. if certAuth != nil {
  671. token, err := v.requestTokenWithCertAuth(ctx, client, certAuth, cfg)
  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 (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccountRef *esmeta.ServiceAccountSelector) (string, error) {
  681. serviceAccount := &corev1.ServiceAccount{}
  682. ref := types.NamespacedName{
  683. Namespace: v.namespace,
  684. Name: serviceAccountRef.Name,
  685. }
  686. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  687. (serviceAccountRef.Namespace != nil) {
  688. ref.Namespace = *serviceAccountRef.Namespace
  689. }
  690. err := v.kube.Get(ctx, ref, serviceAccount)
  691. if err != nil {
  692. return "", fmt.Errorf(errGetKubeSA, ref.Name, err)
  693. }
  694. if len(serviceAccount.Secrets) == 0 {
  695. return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
  696. }
  697. for _, tokenRef := range serviceAccount.Secrets {
  698. retval, err := v.secretKeyRef(ctx, &esmeta.SecretKeySelector{
  699. Name: tokenRef.Name,
  700. Namespace: &ref.Namespace,
  701. Key: "token",
  702. })
  703. if err != nil {
  704. continue
  705. }
  706. return retval, nil
  707. }
  708. return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
  709. }
  710. func (v *client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
  711. secret := &corev1.Secret{}
  712. ref := types.NamespacedName{
  713. Namespace: v.namespace,
  714. Name: secretRef.Name,
  715. }
  716. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  717. (secretRef.Namespace != nil) {
  718. ref.Namespace = *secretRef.Namespace
  719. }
  720. err := v.kube.Get(ctx, ref, secret)
  721. if err != nil {
  722. return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
  723. }
  724. keyBytes, ok := secret.Data[secretRef.Key]
  725. if !ok {
  726. return "", fmt.Errorf(errSecretKeyFmt, secretRef.Key)
  727. }
  728. value := string(keyBytes)
  729. valueStr := strings.TrimSpace(value)
  730. return valueStr, nil
  731. }
  732. // checkToken does a lookup and checks if the provided token exists.
  733. func checkToken(ctx context.Context, vStore *client) error {
  734. // https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
  735. req := vStore.client.NewRequest("GET", "/v1/auth/token/lookup-self")
  736. _, err := vStore.client.RawRequestWithContext(ctx, req)
  737. return err
  738. }
  739. // appRoleParameters creates the required body for Vault AppRole Auth.
  740. // Reference - https://www.vaultproject.io/api-docs/auth/approle#login-with-approle
  741. func appRoleParameters(role, secret string) map[string]string {
  742. return map[string]string{
  743. "role_id": role,
  744. "secret_id": secret,
  745. }
  746. }
  747. func (v *client) requestTokenWithAppRoleRef(ctx context.Context, client Client, appRole *esv1beta1.VaultAppRole) (string, error) {
  748. roleID := strings.TrimSpace(appRole.RoleID)
  749. secretID, err := v.secretKeyRef(ctx, &appRole.SecretRef)
  750. if err != nil {
  751. return "", err
  752. }
  753. parameters := appRoleParameters(roleID, secretID)
  754. url := strings.Join([]string{"/v1", "auth", appRole.Path, "login"}, "/")
  755. request := client.NewRequest("POST", url)
  756. err = request.SetJSONBody(parameters)
  757. if err != nil {
  758. return "", fmt.Errorf(errVaultReqParams, err)
  759. }
  760. resp, err := client.RawRequestWithContext(ctx, request)
  761. if err != nil {
  762. return "", fmt.Errorf(errVaultRequest, err)
  763. }
  764. defer resp.Body.Close()
  765. vaultResult := vault.Secret{}
  766. if err = resp.DecodeJSON(&vaultResult); err != nil {
  767. return "", fmt.Errorf(errVaultResponse, err)
  768. }
  769. token, err := vaultResult.TokenID()
  770. if err != nil {
  771. return "", fmt.Errorf(errVaultToken, err)
  772. }
  773. return token, nil
  774. }
  775. // kubeParameters creates the required body for Vault Kubernetes auth.
  776. // Reference - https://www.vaultproject.io/api/auth/kubernetes#login
  777. func kubeParameters(role, jwt string) map[string]string {
  778. return map[string]string{
  779. "role": role,
  780. "jwt": jwt,
  781. }
  782. }
  783. func (v *client) requestTokenWithKubernetesAuth(ctx context.Context, client Client, kubernetesAuth *esv1beta1.VaultKubernetesAuth) (string, error) {
  784. jwtString, err := getJwtString(ctx, v, kubernetesAuth)
  785. if err != nil {
  786. return "", err
  787. }
  788. parameters := kubeParameters(kubernetesAuth.Role, jwtString)
  789. url := strings.Join([]string{"/v1", "auth", kubernetesAuth.Path, "login"}, "/")
  790. request := client.NewRequest("POST", url)
  791. err = request.SetJSONBody(parameters)
  792. if err != nil {
  793. return "", fmt.Errorf(errVaultReqParams, err)
  794. }
  795. resp, err := client.RawRequestWithContext(ctx, request)
  796. if err != nil {
  797. return "", fmt.Errorf(errVaultRequest, err)
  798. }
  799. defer resp.Body.Close()
  800. vaultResult := vault.Secret{}
  801. err = resp.DecodeJSON(&vaultResult)
  802. if err != nil {
  803. return "", fmt.Errorf(errVaultResponse, err)
  804. }
  805. token, err := vaultResult.TokenID()
  806. if err != nil {
  807. return "", fmt.Errorf(errVaultToken, err)
  808. }
  809. return token, nil
  810. }
  811. func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.VaultKubernetesAuth) (string, error) {
  812. if kubernetesAuth.ServiceAccountRef != nil {
  813. jwt, err := v.secretKeyRefForServiceAccount(ctx, kubernetesAuth.ServiceAccountRef)
  814. if err != nil {
  815. return "", err
  816. }
  817. return jwt, nil
  818. } else if kubernetesAuth.SecretRef != nil {
  819. tokenRef := kubernetesAuth.SecretRef
  820. if tokenRef.Key == "" {
  821. tokenRef = kubernetesAuth.SecretRef.DeepCopy()
  822. tokenRef.Key = "token"
  823. }
  824. jwt, err := v.secretKeyRef(ctx, tokenRef)
  825. if err != nil {
  826. return "", err
  827. }
  828. return jwt, nil
  829. } else {
  830. // Kubernetes authentication is specified, but without a referenced
  831. // Kubernetes secret. We check if the file path for in-cluster service account
  832. // exists and attempt to use the token for Vault Kubernetes auth.
  833. if _, err := os.Stat(serviceAccTokenPath); err != nil {
  834. return "", fmt.Errorf(errServiceAccount, err)
  835. }
  836. jwtByte, err := os.ReadFile(serviceAccTokenPath)
  837. if err != nil {
  838. return "", fmt.Errorf(errServiceAccount, err)
  839. }
  840. return string(jwtByte), nil
  841. }
  842. }
  843. func (v *client) requestTokenWithLdapAuth(ctx context.Context, client Client, ldapAuth *esv1beta1.VaultLdapAuth) (string, error) {
  844. username := strings.TrimSpace(ldapAuth.Username)
  845. password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
  846. if err != nil {
  847. return "", err
  848. }
  849. parameters := map[string]string{
  850. "password": password,
  851. }
  852. url := strings.Join([]string{"/v1", "auth", ldapAuth.Path, "login", username}, "/")
  853. request := client.NewRequest("POST", url)
  854. err = request.SetJSONBody(parameters)
  855. if err != nil {
  856. return "", fmt.Errorf(errVaultReqParams, err)
  857. }
  858. resp, err := client.RawRequestWithContext(ctx, request)
  859. if err != nil {
  860. return "", fmt.Errorf(errVaultRequest, err)
  861. }
  862. defer resp.Body.Close()
  863. vaultResult := vault.Secret{}
  864. if err = resp.DecodeJSON(&vaultResult); err != nil {
  865. return "", fmt.Errorf(errVaultResponse, err)
  866. }
  867. token, err := vaultResult.TokenID()
  868. if err != nil {
  869. return "", fmt.Errorf(errVaultToken, err)
  870. }
  871. return token, nil
  872. }
  873. func (v *client) requestTokenWithJwtAuth(ctx context.Context, client Client, jwtAuth *esv1beta1.VaultJwtAuth) (string, error) {
  874. role := strings.TrimSpace(jwtAuth.Role)
  875. jwt, err := v.secretKeyRef(ctx, &jwtAuth.SecretRef)
  876. if err != nil {
  877. return "", err
  878. }
  879. parameters := map[string]string{
  880. "role": role,
  881. "jwt": jwt,
  882. }
  883. url := strings.Join([]string{"/v1", "auth", jwtAuth.Path, "login"}, "/")
  884. request := client.NewRequest("POST", url)
  885. err = request.SetJSONBody(parameters)
  886. if err != nil {
  887. return "", fmt.Errorf(errVaultReqParams, err)
  888. }
  889. resp, err := client.RawRequestWithContext(ctx, request)
  890. if err != nil {
  891. return "", fmt.Errorf(errVaultRequest, err)
  892. }
  893. defer resp.Body.Close()
  894. vaultResult := vault.Secret{}
  895. if err = resp.DecodeJSON(&vaultResult); err != nil {
  896. return "", fmt.Errorf(errVaultResponse, err)
  897. }
  898. token, err := vaultResult.TokenID()
  899. if err != nil {
  900. return "", fmt.Errorf(errVaultToken, err)
  901. }
  902. return token, nil
  903. }
  904. func (v *client) requestTokenWithCertAuth(ctx context.Context, client Client, certAuth *esv1beta1.VaultCertAuth, cfg *vault.Config) (string, error) {
  905. clientKey, err := v.secretKeyRef(ctx, &certAuth.SecretRef)
  906. if err != nil {
  907. return "", err
  908. }
  909. clientCert, err := v.secretKeyRef(ctx, &certAuth.ClientCert)
  910. if err != nil {
  911. return "", err
  912. }
  913. cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
  914. if err != nil {
  915. return "", fmt.Errorf(errClientTLSAuth, err)
  916. }
  917. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  918. transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
  919. }
  920. url := strings.Join([]string{"/v1", "auth", "cert", "login"}, "/")
  921. request := client.NewRequest("POST", url)
  922. resp, err := client.RawRequestWithContext(ctx, request)
  923. if err != nil {
  924. return "", fmt.Errorf(errVaultRequest, err)
  925. }
  926. defer resp.Body.Close()
  927. vaultResult := vault.Secret{}
  928. if err = resp.DecodeJSON(&vaultResult); err != nil {
  929. return "", fmt.Errorf(errVaultResponse, err)
  930. }
  931. token, err := vaultResult.TokenID()
  932. if err != nil {
  933. return "", fmt.Errorf(errVaultToken, err)
  934. }
  935. return token, nil
  936. }