vault.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package vault
  13. import (
  14. "context"
  15. "crypto/tls"
  16. "crypto/x509"
  17. "encoding/json"
  18. "errors"
  19. "fmt"
  20. "io/ioutil"
  21. "net/http"
  22. "os"
  23. "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. esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  33. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  34. "github.com/external-secrets/external-secrets/pkg/provider"
  35. "github.com/external-secrets/external-secrets/pkg/provider/schema"
  36. )
  37. var (
  38. _ provider.Provider = &connector{}
  39. _ provider.SecretsClient = &client{}
  40. )
  41. const (
  42. serviceAccTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
  43. errVaultStore = "received invalid Vault SecretStore resource: %w"
  44. errVaultClient = "cannot setup new vault client: %w"
  45. errVaultCert = "cannot set Vault CA certificate: %w"
  46. errReadSecret = "cannot read secret data from Vault: %w"
  47. errAuthFormat = "cannot initialize Vault client: no valid auth method specified"
  48. errInvalidCredentials = "invalid vault credentials: %w"
  49. errDataField = "failed to find data field"
  50. errJSONUnmarshall = "failed to unmarshall JSON"
  51. 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. errGetKubeSA = "cannot get Kubernetes service account %q: %w"
  59. errGetKubeSASecrets = "cannot find secrets bound to service account: %q"
  60. errGetKubeSANoToken = "cannot find token in secrets bound to service account: %q"
  61. errGetKubeSecret = "cannot get Kubernetes secret %q: %w"
  62. errSecretKeyFmt = "cannot find secret data for key: %q"
  63. errConfigMapFmt = "cannot find config map data for key: %q"
  64. errClientTLSAuth = "error from Client TLS Auth: %q"
  65. errVaultRevokeToken = "error while revoking token: %w"
  66. errUnknownCAProvider = "unknown caProvider type given"
  67. errCANamespace = "cannot read secret for CAProvider due to missing namespace on kind ClusterSecretStore"
  68. )
  69. type Client interface {
  70. NewRequest(method, requestPath string) *vault.Request
  71. RawRequestWithContext(ctx context.Context, r *vault.Request) (*vault.Response, error)
  72. SetToken(v string)
  73. Token() string
  74. ClearToken()
  75. SetNamespace(namespace string)
  76. AddHeader(key, value string)
  77. }
  78. type client struct {
  79. kube kclient.Client
  80. store *esv1alpha1.VaultProvider
  81. log logr.Logger
  82. client Client
  83. namespace string
  84. storeKind string
  85. }
  86. func init() {
  87. schema.Register(&connector{
  88. newVaultClient: newVaultClient,
  89. }, &esv1alpha1.SecretStoreProvider{
  90. Vault: &esv1alpha1.VaultProvider{},
  91. })
  92. }
  93. func newVaultClient(c *vault.Config) (Client, error) {
  94. return vault.NewClient(c)
  95. }
  96. type connector struct {
  97. newVaultClient func(c *vault.Config) (Client, error)
  98. }
  99. func (c *connector) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube kclient.Client, namespace string) (provider.SecretsClient, error) {
  100. storeSpec := store.GetSpec()
  101. if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.Vault == nil {
  102. return nil, errors.New(errVaultStore)
  103. }
  104. vaultSpec := storeSpec.Provider.Vault
  105. vStore := &client{
  106. kube: kube,
  107. store: vaultSpec,
  108. log: ctrl.Log.WithName("provider").WithName("vault"),
  109. namespace: namespace,
  110. storeKind: store.GetObjectKind().GroupVersionKind().Kind,
  111. }
  112. cfg, err := vStore.newConfig()
  113. if err != nil {
  114. return nil, err
  115. }
  116. client, err := c.newVaultClient(cfg)
  117. if err != nil {
  118. return nil, fmt.Errorf(errVaultClient, err)
  119. }
  120. if vaultSpec.Namespace != nil {
  121. client.SetNamespace(*vaultSpec.Namespace)
  122. }
  123. if vaultSpec.ReadYourWrites && vaultSpec.ForwardInconsistent {
  124. client.AddHeader("X-Vault-Inconsistent", "forward-active-node")
  125. }
  126. if err := vStore.setAuth(ctx, client, cfg); err != nil {
  127. return nil, err
  128. }
  129. vStore.client = client
  130. return vStore, nil
  131. }
  132. // GetSecret supports two types:
  133. // 1. get the full secret as json-encoded value
  134. // by leaving the ref.Property empty.
  135. // 2. get a key from the secret.
  136. // Nested values are supported by specifying a gjson expression
  137. func (v *client) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
  138. data, err := v.readSecret(ctx, ref.Key, ref.Version)
  139. if err != nil {
  140. return nil, err
  141. }
  142. jsonStr, err := json.Marshal(data)
  143. if err != nil {
  144. return nil, err
  145. }
  146. // (1): return raw json if no property is defined
  147. if ref.Property == "" {
  148. return jsonStr, nil
  149. }
  150. // For backwards compatibility we want the
  151. // actual keys to take precedence over gjson syntax
  152. // (2): extract key from secret with property
  153. if _, ok := data[ref.Property]; ok {
  154. return getTypedKey(data, ref.Property)
  155. }
  156. // (2): extract key from secret using gjson
  157. val := gjson.Get(string(jsonStr), ref.Property)
  158. if !val.Exists() {
  159. return nil, fmt.Errorf(errSecretKeyFmt, ref.Property)
  160. }
  161. return []byte(val.String()), nil
  162. }
  163. // GetSecretMap supports two modes of operation:
  164. // 1. get the full secret from the vault data payload (by leaving .property empty).
  165. // 2. extract key/value pairs from a (nested) object.
  166. func (v *client) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  167. data, err := v.GetSecret(ctx, ref)
  168. if err != nil {
  169. return nil, err
  170. }
  171. var secretData map[string]interface{}
  172. err = json.Unmarshal(data, &secretData)
  173. if err != nil {
  174. return nil, err
  175. }
  176. byteMap := make(map[string][]byte, len(secretData))
  177. for k := range secretData {
  178. byteMap[k], err = getTypedKey(secretData, k)
  179. if err != nil {
  180. return nil, err
  181. }
  182. }
  183. return byteMap, nil
  184. }
  185. func getTypedKey(data map[string]interface{}, key string) ([]byte, error) {
  186. v, ok := data[key]
  187. if !ok {
  188. return nil, fmt.Errorf(errUnexpectedKey, key)
  189. }
  190. switch t := v.(type) {
  191. case string:
  192. return []byte(t), nil
  193. case map[string]interface{}:
  194. return json.Marshal(t)
  195. case []byte:
  196. return t, nil
  197. // also covers int and float32 due to json.Marshal
  198. case float64:
  199. return []byte(strconv.FormatFloat(t, 'f', -1, 64)), nil
  200. case bool:
  201. return []byte(strconv.FormatBool(t)), nil
  202. case nil:
  203. return []byte(nil), nil
  204. default:
  205. return nil, errors.New(errSecretFormat)
  206. }
  207. }
  208. func (v *client) Close(ctx context.Context) error {
  209. // Revoke the token if we have one set and it wasn't sourced from a TokenSecretRef
  210. if v.client.Token() != "" && v.store.Auth.TokenSecretRef == nil {
  211. req := v.client.NewRequest(http.MethodPost, "/v1/auth/token/revoke-self")
  212. _, err := v.client.RawRequestWithContext(ctx, req)
  213. if err != nil {
  214. return fmt.Errorf(errVaultRevokeToken, err)
  215. }
  216. v.client.ClearToken()
  217. }
  218. return nil
  219. }
  220. func (v *client) Validate() error {
  221. err := checkToken(context.Background(), v)
  222. if err != nil {
  223. return fmt.Errorf(errInvalidCredentials, err)
  224. }
  225. return nil
  226. }
  227. func (v *client) buildPath(path string) string {
  228. optionalMount := v.store.Path
  229. origPath := strings.Split(path, "/")
  230. newPath := make([]string, 0)
  231. cursor := 0
  232. if optionalMount != nil && origPath[0] != *optionalMount {
  233. // Default case before path was optional
  234. // Ensure that the requested path includes the SecretStores paths as prefix
  235. newPath = append(newPath, *optionalMount)
  236. } else {
  237. newPath = append(newPath, origPath[cursor])
  238. cursor++
  239. }
  240. if v.store.Version == esv1alpha1.VaultKVStoreV2 {
  241. // Add the required `data` part of the URL for the v2 API
  242. if len(origPath) < 2 || origPath[1] != "data" {
  243. newPath = append(newPath, "data")
  244. }
  245. }
  246. newPath = append(newPath, origPath[cursor:]...)
  247. returnPath := strings.Join(newPath, "/")
  248. return returnPath
  249. }
  250. func (v *client) readSecret(ctx context.Context, path, version string) (map[string]interface{}, error) {
  251. dataPath := v.buildPath(path)
  252. // path formated according to vault docs for v1 and v2 API
  253. // v1: https://www.vaultproject.io/api-docs/secret/kv/kv-v1#read-secret
  254. // v2: https://www.vaultproject.io/api/secret/kv/kv-v2#read-secret-version
  255. req := v.client.NewRequest(http.MethodGet, fmt.Sprintf("/v1/%s", dataPath))
  256. if version != "" {
  257. req.Params.Set("version", version)
  258. }
  259. resp, err := v.client.RawRequestWithContext(ctx, req)
  260. if err != nil {
  261. return nil, fmt.Errorf(errReadSecret, err)
  262. }
  263. vaultSecret, err := vault.ParseSecret(resp.Body)
  264. if err != nil {
  265. return nil, err
  266. }
  267. secretData := vaultSecret.Data
  268. if v.store.Version == esv1alpha1.VaultKVStoreV2 {
  269. // Vault KV2 has data embedded within sub-field
  270. // reference - https://www.vaultproject.io/api/secret/kv/kv-v2#read-secret-version
  271. dataInt, ok := vaultSecret.Data["data"]
  272. if !ok {
  273. return nil, errors.New(errDataField)
  274. }
  275. secretData, ok = dataInt.(map[string]interface{})
  276. if !ok {
  277. return nil, errors.New(errJSONUnmarshall)
  278. }
  279. }
  280. return secretData, nil
  281. }
  282. func (v *client) newConfig() (*vault.Config, error) {
  283. cfg := vault.DefaultConfig()
  284. cfg.Address = v.store.Server
  285. if len(v.store.CABundle) == 0 && v.store.CAProvider == nil {
  286. return cfg, nil
  287. }
  288. caCertPool := x509.NewCertPool()
  289. if len(v.store.CABundle) > 0 {
  290. ok := caCertPool.AppendCertsFromPEM(v.store.CABundle)
  291. if !ok {
  292. return nil, errors.New(errVaultCert)
  293. }
  294. }
  295. if v.store.CAProvider != nil && v.storeKind == esv1alpha1.ClusterSecretStoreKind && v.store.CAProvider.Namespace == nil {
  296. return nil, errors.New(errCANamespace)
  297. }
  298. if v.store.CAProvider != nil {
  299. var cert []byte
  300. var err error
  301. switch v.store.CAProvider.Type {
  302. case esv1alpha1.CAProviderTypeSecret:
  303. cert, err = getCertFromSecret(v)
  304. case esv1alpha1.CAProviderTypeConfigMap:
  305. cert, err = getCertFromConfigMap(v)
  306. default:
  307. return nil, errors.New(errUnknownCAProvider)
  308. }
  309. if err != nil {
  310. return nil, err
  311. }
  312. ok := caCertPool.AppendCertsFromPEM(cert)
  313. if !ok {
  314. return nil, errors.New(errVaultCert)
  315. }
  316. }
  317. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  318. transport.TLSClientConfig.RootCAs = caCertPool
  319. }
  320. // If either read-after-write consistency feature is enabled, enable ReadYourWrites
  321. cfg.ReadYourWrites = v.store.ReadYourWrites || v.store.ForwardInconsistent
  322. return cfg, nil
  323. }
  324. func getCertFromSecret(v *client) ([]byte, error) {
  325. secretRef := esmeta.SecretKeySelector{
  326. Name: v.store.CAProvider.Name,
  327. Key: v.store.CAProvider.Key,
  328. }
  329. if v.store.CAProvider.Namespace != nil {
  330. secretRef.Namespace = v.store.CAProvider.Namespace
  331. }
  332. ctx := context.Background()
  333. res, err := v.secretKeyRef(ctx, &secretRef)
  334. if err != nil {
  335. return nil, fmt.Errorf(errVaultCert, err)
  336. }
  337. return []byte(res), nil
  338. }
  339. func getCertFromConfigMap(v *client) ([]byte, error) {
  340. objKey := types.NamespacedName{
  341. Name: v.store.CAProvider.Name,
  342. }
  343. if v.store.CAProvider.Namespace != nil {
  344. objKey.Namespace = *v.store.CAProvider.Namespace
  345. }
  346. configMapRef := &corev1.ConfigMap{}
  347. ctx := context.Background()
  348. err := v.kube.Get(ctx, objKey, configMapRef)
  349. if err != nil {
  350. return nil, fmt.Errorf(errVaultCert, err)
  351. }
  352. val, ok := configMapRef.Data[v.store.CAProvider.Key]
  353. if !ok {
  354. return nil, fmt.Errorf(errConfigMapFmt, v.store.CAProvider.Key)
  355. }
  356. return []byte(val), nil
  357. }
  358. func (v *client) setAuth(ctx context.Context, client Client, cfg *vault.Config) error {
  359. tokenExists, err := setSecretKeyToken(ctx, v, client)
  360. if tokenExists {
  361. return err
  362. }
  363. tokenExists, err = setAppRoleToken(ctx, v, client)
  364. if tokenExists {
  365. return err
  366. }
  367. tokenExists, err = setKubernetesAuthToken(ctx, v, client)
  368. if tokenExists {
  369. return err
  370. }
  371. tokenExists, err = setLdapAuthToken(ctx, v, client)
  372. if tokenExists {
  373. return err
  374. }
  375. tokenExists, err = setJwtAuthToken(ctx, v, client)
  376. if tokenExists {
  377. return err
  378. }
  379. tokenExists, err = setCertAuthToken(ctx, v, client, cfg)
  380. if tokenExists {
  381. return err
  382. }
  383. return errors.New(errAuthFormat)
  384. }
  385. func setAppRoleToken(ctx context.Context, v *client, client Client) (bool, error) {
  386. tokenRef := v.store.Auth.TokenSecretRef
  387. if tokenRef != nil {
  388. token, err := v.secretKeyRef(ctx, tokenRef)
  389. if err != nil {
  390. return true, err
  391. }
  392. client.SetToken(token)
  393. return true, nil
  394. }
  395. return false, nil
  396. }
  397. func setSecretKeyToken(ctx context.Context, v *client, client Client) (bool, error) {
  398. appRole := v.store.Auth.AppRole
  399. if appRole != nil {
  400. token, err := v.requestTokenWithAppRoleRef(ctx, client, appRole)
  401. if err != nil {
  402. return true, err
  403. }
  404. client.SetToken(token)
  405. return true, nil
  406. }
  407. return false, nil
  408. }
  409. func setKubernetesAuthToken(ctx context.Context, v *client, client Client) (bool, error) {
  410. kubernetesAuth := v.store.Auth.Kubernetes
  411. if kubernetesAuth != nil {
  412. token, err := v.requestTokenWithKubernetesAuth(ctx, client, kubernetesAuth)
  413. if err != nil {
  414. return true, err
  415. }
  416. client.SetToken(token)
  417. return true, nil
  418. }
  419. return false, nil
  420. }
  421. func setLdapAuthToken(ctx context.Context, v *client, client Client) (bool, error) {
  422. ldapAuth := v.store.Auth.Ldap
  423. if ldapAuth != nil {
  424. token, err := v.requestTokenWithLdapAuth(ctx, client, ldapAuth)
  425. if err != nil {
  426. return true, err
  427. }
  428. client.SetToken(token)
  429. return true, nil
  430. }
  431. return false, nil
  432. }
  433. func setJwtAuthToken(ctx context.Context, v *client, client Client) (bool, error) {
  434. jwtAuth := v.store.Auth.Jwt
  435. if jwtAuth != nil {
  436. token, err := v.requestTokenWithJwtAuth(ctx, client, jwtAuth)
  437. if err != nil {
  438. return true, err
  439. }
  440. client.SetToken(token)
  441. return true, nil
  442. }
  443. return false, nil
  444. }
  445. func setCertAuthToken(ctx context.Context, v *client, client Client, cfg *vault.Config) (bool, error) {
  446. certAuth := v.store.Auth.Cert
  447. if certAuth != nil {
  448. token, err := v.requestTokenWithCertAuth(ctx, client, certAuth, cfg)
  449. if err != nil {
  450. return true, err
  451. }
  452. client.SetToken(token)
  453. return true, nil
  454. }
  455. return false, nil
  456. }
  457. func (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccountRef *esmeta.ServiceAccountSelector) (string, error) {
  458. serviceAccount := &corev1.ServiceAccount{}
  459. ref := types.NamespacedName{
  460. Namespace: v.namespace,
  461. Name: serviceAccountRef.Name,
  462. }
  463. if (v.storeKind == esv1alpha1.ClusterSecretStoreKind) &&
  464. (serviceAccountRef.Namespace != nil) {
  465. ref.Namespace = *serviceAccountRef.Namespace
  466. }
  467. err := v.kube.Get(ctx, ref, serviceAccount)
  468. if err != nil {
  469. return "", fmt.Errorf(errGetKubeSA, ref.Name, err)
  470. }
  471. if len(serviceAccount.Secrets) == 0 {
  472. return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
  473. }
  474. for _, tokenRef := range serviceAccount.Secrets {
  475. retval, err := v.secretKeyRef(ctx, &esmeta.SecretKeySelector{
  476. Name: tokenRef.Name,
  477. Namespace: &ref.Namespace,
  478. Key: "token",
  479. })
  480. if err != nil {
  481. continue
  482. }
  483. return retval, nil
  484. }
  485. return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
  486. }
  487. func (v *client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
  488. secret := &corev1.Secret{}
  489. ref := types.NamespacedName{
  490. Namespace: v.namespace,
  491. Name: secretRef.Name,
  492. }
  493. if (v.storeKind == esv1alpha1.ClusterSecretStoreKind) &&
  494. (secretRef.Namespace != nil) {
  495. ref.Namespace = *secretRef.Namespace
  496. }
  497. err := v.kube.Get(ctx, ref, secret)
  498. if err != nil {
  499. return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
  500. }
  501. keyBytes, ok := secret.Data[secretRef.Key]
  502. if !ok {
  503. return "", fmt.Errorf(errSecretKeyFmt, secretRef.Key)
  504. }
  505. value := string(keyBytes)
  506. valueStr := strings.TrimSpace(value)
  507. return valueStr, nil
  508. }
  509. // checkToken does a lookup and checks if the provided token exists.
  510. func checkToken(ctx context.Context, vStore *client) error {
  511. // https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
  512. req := vStore.client.NewRequest("GET", "/v1/auth/token/lookup-self")
  513. _, err := vStore.client.RawRequestWithContext(ctx, req)
  514. return err
  515. }
  516. // appRoleParameters creates the required body for Vault AppRole Auth.
  517. // Reference - https://www.vaultproject.io/api-docs/auth/approle#login-with-approle
  518. func appRoleParameters(role, secret string) map[string]string {
  519. return map[string]string{
  520. "role_id": role,
  521. "secret_id": secret,
  522. }
  523. }
  524. func (v *client) requestTokenWithAppRoleRef(ctx context.Context, client Client, appRole *esv1alpha1.VaultAppRole) (string, error) {
  525. roleID := strings.TrimSpace(appRole.RoleID)
  526. secretID, err := v.secretKeyRef(ctx, &appRole.SecretRef)
  527. if err != nil {
  528. return "", err
  529. }
  530. parameters := appRoleParameters(roleID, secretID)
  531. url := strings.Join([]string{"/v1", "auth", appRole.Path, "login"}, "/")
  532. request := client.NewRequest("POST", url)
  533. err = request.SetJSONBody(parameters)
  534. if err != nil {
  535. return "", fmt.Errorf(errVaultReqParams, err)
  536. }
  537. resp, err := client.RawRequestWithContext(ctx, request)
  538. if err != nil {
  539. return "", fmt.Errorf(errVaultRequest, err)
  540. }
  541. defer resp.Body.Close()
  542. vaultResult := vault.Secret{}
  543. if err = resp.DecodeJSON(&vaultResult); err != nil {
  544. return "", fmt.Errorf(errVaultResponse, err)
  545. }
  546. token, err := vaultResult.TokenID()
  547. if err != nil {
  548. return "", fmt.Errorf(errVaultToken, err)
  549. }
  550. return token, nil
  551. }
  552. // kubeParameters creates the required body for Vault Kubernetes auth.
  553. // Reference - https://www.vaultproject.io/api/auth/kubernetes#login
  554. func kubeParameters(role, jwt string) map[string]string {
  555. return map[string]string{
  556. "role": role,
  557. "jwt": jwt,
  558. }
  559. }
  560. func (v *client) requestTokenWithKubernetesAuth(ctx context.Context, client Client, kubernetesAuth *esv1alpha1.VaultKubernetesAuth) (string, error) {
  561. jwtString, err := getJwtString(ctx, v, kubernetesAuth)
  562. if err != nil {
  563. return "", err
  564. }
  565. parameters := kubeParameters(kubernetesAuth.Role, jwtString)
  566. url := strings.Join([]string{"/v1", "auth", kubernetesAuth.Path, "login"}, "/")
  567. request := client.NewRequest("POST", url)
  568. err = request.SetJSONBody(parameters)
  569. if err != nil {
  570. return "", fmt.Errorf(errVaultReqParams, err)
  571. }
  572. resp, err := client.RawRequestWithContext(ctx, request)
  573. if err != nil {
  574. return "", fmt.Errorf(errVaultRequest, err)
  575. }
  576. defer resp.Body.Close()
  577. vaultResult := vault.Secret{}
  578. err = resp.DecodeJSON(&vaultResult)
  579. if err != nil {
  580. return "", fmt.Errorf(errVaultResponse, err)
  581. }
  582. token, err := vaultResult.TokenID()
  583. if err != nil {
  584. return "", fmt.Errorf(errVaultToken, err)
  585. }
  586. return token, nil
  587. }
  588. func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1alpha1.VaultKubernetesAuth) (string, error) {
  589. if kubernetesAuth.ServiceAccountRef != nil {
  590. jwt, err := v.secretKeyRefForServiceAccount(ctx, kubernetesAuth.ServiceAccountRef)
  591. if err != nil {
  592. return "", err
  593. }
  594. return jwt, nil
  595. } else if kubernetesAuth.SecretRef != nil {
  596. tokenRef := kubernetesAuth.SecretRef
  597. if tokenRef.Key == "" {
  598. tokenRef = kubernetesAuth.SecretRef.DeepCopy()
  599. tokenRef.Key = "token"
  600. }
  601. jwt, err := v.secretKeyRef(ctx, tokenRef)
  602. if err != nil {
  603. return "", err
  604. }
  605. return jwt, nil
  606. } else {
  607. // Kubernetes authentication is specified, but without a referenced
  608. // Kubernetes secret. We check if the file path for in-cluster service account
  609. // exists and attempt to use the token for Vault Kubernetes auth.
  610. if _, err := os.Stat(serviceAccTokenPath); err != nil {
  611. return "", fmt.Errorf(errServiceAccount, err)
  612. }
  613. jwtByte, err := ioutil.ReadFile(serviceAccTokenPath)
  614. if err != nil {
  615. return "", fmt.Errorf(errServiceAccount, err)
  616. }
  617. return string(jwtByte), nil
  618. }
  619. }
  620. func (v *client) requestTokenWithLdapAuth(ctx context.Context, client Client, ldapAuth *esv1alpha1.VaultLdapAuth) (string, error) {
  621. username := strings.TrimSpace(ldapAuth.Username)
  622. password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
  623. if err != nil {
  624. return "", err
  625. }
  626. parameters := map[string]string{
  627. "password": password,
  628. }
  629. url := strings.Join([]string{"/v1", "auth", ldapAuth.Path, "login", username}, "/")
  630. request := client.NewRequest("POST", url)
  631. err = request.SetJSONBody(parameters)
  632. if err != nil {
  633. return "", fmt.Errorf(errVaultReqParams, err)
  634. }
  635. resp, err := client.RawRequestWithContext(ctx, request)
  636. if err != nil {
  637. return "", fmt.Errorf(errVaultRequest, err)
  638. }
  639. defer resp.Body.Close()
  640. vaultResult := vault.Secret{}
  641. if err = resp.DecodeJSON(&vaultResult); err != nil {
  642. return "", fmt.Errorf(errVaultResponse, err)
  643. }
  644. token, err := vaultResult.TokenID()
  645. if err != nil {
  646. return "", fmt.Errorf(errVaultToken, err)
  647. }
  648. return token, nil
  649. }
  650. func (v *client) requestTokenWithJwtAuth(ctx context.Context, client Client, jwtAuth *esv1alpha1.VaultJwtAuth) (string, error) {
  651. role := strings.TrimSpace(jwtAuth.Role)
  652. jwt, err := v.secretKeyRef(ctx, &jwtAuth.SecretRef)
  653. if err != nil {
  654. return "", err
  655. }
  656. parameters := map[string]string{
  657. "role": role,
  658. "jwt": jwt,
  659. }
  660. url := strings.Join([]string{"/v1", "auth", jwtAuth.Path, "login"}, "/")
  661. request := client.NewRequest("POST", url)
  662. err = request.SetJSONBody(parameters)
  663. if err != nil {
  664. return "", fmt.Errorf(errVaultReqParams, err)
  665. }
  666. resp, err := client.RawRequestWithContext(ctx, request)
  667. if err != nil {
  668. return "", fmt.Errorf(errVaultRequest, err)
  669. }
  670. defer resp.Body.Close()
  671. vaultResult := vault.Secret{}
  672. if err = resp.DecodeJSON(&vaultResult); err != nil {
  673. return "", fmt.Errorf(errVaultResponse, err)
  674. }
  675. token, err := vaultResult.TokenID()
  676. if err != nil {
  677. return "", fmt.Errorf(errVaultToken, err)
  678. }
  679. return token, nil
  680. }
  681. func (v *client) requestTokenWithCertAuth(ctx context.Context, client Client, certAuth *esv1alpha1.VaultCertAuth, cfg *vault.Config) (string, error) {
  682. clientKey, err := v.secretKeyRef(ctx, &certAuth.SecretRef)
  683. if err != nil {
  684. return "", err
  685. }
  686. clientCert, err := v.secretKeyRef(ctx, &certAuth.ClientCert)
  687. if err != nil {
  688. return "", err
  689. }
  690. cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
  691. if err != nil {
  692. return "", fmt.Errorf(errClientTLSAuth, err)
  693. }
  694. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  695. transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
  696. }
  697. url := strings.Join([]string{"/v1", "auth", "cert", "login"}, "/")
  698. request := client.NewRequest("POST", url)
  699. resp, err := client.RawRequestWithContext(ctx, request)
  700. if err != nil {
  701. return "", fmt.Errorf(errVaultRequest, err)
  702. }
  703. defer resp.Body.Close()
  704. vaultResult := vault.Secret{}
  705. if err = resp.DecodeJSON(&vaultResult); err != nil {
  706. return "", fmt.Errorf(errVaultResponse, err)
  707. }
  708. token, err := vaultResult.TokenID()
  709. if err != nil {
  710. return "", fmt.Errorf(errVaultToken, err)
  711. }
  712. return token, nil
  713. }