vault.go 32 KB

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