vault.go 23 KB

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