vault.go 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626
  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. "bytes"
  15. "context"
  16. "crypto/tls"
  17. "crypto/x509"
  18. "encoding/json"
  19. "errors"
  20. "fmt"
  21. "net/http"
  22. "os"
  23. "reflect"
  24. "strconv"
  25. "strings"
  26. "github.com/aws/aws-sdk-go/aws"
  27. "github.com/aws/aws-sdk-go/aws/credentials"
  28. "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
  29. "github.com/go-logr/logr"
  30. "github.com/golang-jwt/jwt/v5"
  31. vault "github.com/hashicorp/vault/api"
  32. approle "github.com/hashicorp/vault/api/auth/approle"
  33. authaws "github.com/hashicorp/vault/api/auth/aws"
  34. authkubernetes "github.com/hashicorp/vault/api/auth/kubernetes"
  35. authldap "github.com/hashicorp/vault/api/auth/ldap"
  36. "github.com/spf13/pflag"
  37. "github.com/tidwall/gjson"
  38. authenticationv1 "k8s.io/api/authentication/v1"
  39. corev1 "k8s.io/api/core/v1"
  40. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  41. "k8s.io/apimachinery/pkg/types"
  42. "k8s.io/client-go/kubernetes"
  43. typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  44. ctrl "sigs.k8s.io/controller-runtime"
  45. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  46. ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
  47. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  48. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  49. "github.com/external-secrets/external-secrets/pkg/cache"
  50. "github.com/external-secrets/external-secrets/pkg/feature"
  51. "github.com/external-secrets/external-secrets/pkg/find"
  52. "github.com/external-secrets/external-secrets/pkg/provider/metrics"
  53. vaultiamauth "github.com/external-secrets/external-secrets/pkg/provider/vault/iamauth"
  54. "github.com/external-secrets/external-secrets/pkg/provider/vault/util"
  55. "github.com/external-secrets/external-secrets/pkg/utils"
  56. )
  57. var (
  58. _ esv1beta1.Provider = &Connector{}
  59. _ esv1beta1.SecretsClient = &client{}
  60. enableCache bool
  61. logger = ctrl.Log.WithName("provider").WithName("vault")
  62. clientCache *cache.Cache[util.Client]
  63. )
  64. const (
  65. serviceAccTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
  66. defaultAWSRegion = "us-east-1"
  67. defaultAWSAuthMountPath = "aws"
  68. errVaultStore = "received invalid Vault SecretStore resource: %w"
  69. errVaultCacheCreate = "cannot create Vault client cache: %s"
  70. errVaultCacheRemove = "error removing item from Vault client cache: %w"
  71. errVaultCacheEviction = "unexpected eviction from Vault client cache"
  72. errVaultClient = "cannot setup new vault client: %w"
  73. errVaultCert = "cannot set Vault CA certificate: %w"
  74. errReadSecret = "cannot read secret data from Vault: %w"
  75. errAuthFormat = "cannot initialize Vault client: no valid auth method specified"
  76. errInvalidCredentials = "invalid vault credentials: %w"
  77. errDataField = "failed to find data field"
  78. errJSONUnmarshall = "failed to unmarshall JSON"
  79. errPathInvalid = "provided Path isn't a valid kv v2 path"
  80. errSecretFormat = "secret data for property %s not in expected format: %s"
  81. errUnexpectedKey = "unexpected key in data: %s"
  82. errVaultToken = "cannot parse Vault authentication token: %w"
  83. errVaultRequest = "error from Vault request: %w"
  84. errServiceAccount = "cannot read Kubernetes service account token from file system: %w"
  85. errJwtNoTokenSource = "neither `secretRef` nor `kubernetesServiceAccountToken` was supplied as token source for jwt authentication"
  86. errUnsupportedKvVersion = "cannot perform find operations with kv version v1"
  87. errUnsupportedMetadataKvVersion = "cannot perform metadata fetch operations with kv version v1"
  88. errNotFound = "secret not found"
  89. errIrsaTokenEnvVarNotFoundOnPod = "expected env variable: %s not found on controller's pod"
  90. errIrsaTokenFileNotFoundOnPod = "web ddentity token file not found at %s location: %w"
  91. errIrsaTokenFileNotReadable = "could not read the web identity token from the file %s: %w"
  92. errIrsaTokenNotValidJWT = "could not parse web identity token available at %s. not a valid jwt?: %w"
  93. errPodInfoNotFoundOnToken = "could not find pod identity info on token %s: %w"
  94. errGetKubeSA = "cannot get Kubernetes service account %q: %w"
  95. errGetKubeSASecrets = "cannot find secrets bound to service account: %q"
  96. errGetKubeSANoToken = "cannot find token in secrets bound to service account: %q"
  97. errGetKubeSATokenRequest = "cannot request Kubernetes service account token for service account %q: %w"
  98. errGetKubeSecret = "cannot get Kubernetes secret %q: %w"
  99. errSecretKeyFmt = "cannot find secret data for key: %q"
  100. errConfigMapFmt = "cannot find config map data for key: %q"
  101. errClientTLSAuth = "error from Client TLS Auth: %q"
  102. errVaultRevokeToken = "error while revoking token: %w"
  103. errUnknownCAProvider = "unknown caProvider type given"
  104. errCANamespace = "cannot read secret for CAProvider due to missing namespace on kind ClusterSecretStore"
  105. errInvalidStore = "invalid store"
  106. errInvalidStoreSpec = "invalid store spec"
  107. errInvalidStoreProv = "invalid store provider"
  108. errInvalidVaultProv = "invalid vault provider"
  109. errInvalidAppRoleSec = "invalid Auth.AppRole.SecretRef: %w"
  110. errInvalidClientCert = "invalid Auth.Cert.ClientCert: %w"
  111. errInvalidCertSec = "invalid Auth.Cert.SecretRef: %w"
  112. errInvalidJwtSec = "invalid Auth.Jwt.SecretRef: %w"
  113. errInvalidJwtK8sSA = "invalid Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef: %w"
  114. errInvalidKubeSA = "invalid Auth.Kubernetes.ServiceAccountRef: %w"
  115. errInvalidKubeSec = "invalid Auth.Kubernetes.SecretRef: %w"
  116. errInvalidLdapSec = "invalid Auth.Ldap.SecretRef: %w"
  117. errInvalidTokenRef = "invalid Auth.TokenSecretRef: %w"
  118. )
  119. // https://github.com/external-secrets/external-secrets/issues/644
  120. var _ esv1beta1.SecretsClient = &client{}
  121. var _ esv1beta1.Provider = &Connector{}
  122. type client struct {
  123. kube kclient.Client
  124. store *esv1beta1.VaultProvider
  125. log logr.Logger
  126. corev1 typedcorev1.CoreV1Interface
  127. client util.Client
  128. auth util.Auth
  129. logical util.Logical
  130. token util.Token
  131. namespace string
  132. storeKind string
  133. }
  134. func NewVaultClient(c *vault.Config) (util.Client, error) {
  135. cl, err := vault.NewClient(c)
  136. if err != nil {
  137. return nil, err
  138. }
  139. auth := cl.Auth()
  140. logical := cl.Logical()
  141. token := cl.Auth().Token()
  142. out := util.VClient{
  143. SetTokenFunc: cl.SetToken,
  144. TokenFunc: cl.Token,
  145. ClearTokenFunc: cl.ClearToken,
  146. AuthField: auth,
  147. AuthTokenField: token,
  148. LogicalField: logical,
  149. SetNamespaceFunc: cl.SetNamespace,
  150. AddHeaderFunc: cl.AddHeader,
  151. }
  152. return &out, nil
  153. }
  154. func getVaultClient(c *Connector, store esv1beta1.GenericStore, cfg *vault.Config) (util.Client, error) {
  155. isStaticToken := store.GetSpec().Provider.Vault.Auth.TokenSecretRef != nil
  156. useCache := enableCache && !isStaticToken
  157. key := cache.Key{
  158. Name: store.GetObjectMeta().Name,
  159. Namespace: store.GetObjectMeta().Namespace,
  160. Kind: store.GetTypeMeta().Kind,
  161. }
  162. if useCache {
  163. client, ok := clientCache.Get(store.GetObjectMeta().ResourceVersion, key)
  164. if ok {
  165. return client, nil
  166. }
  167. }
  168. client, err := c.NewVaultClient(cfg)
  169. if err != nil {
  170. return nil, fmt.Errorf(errVaultClient, err)
  171. }
  172. if useCache && !clientCache.Contains(key) {
  173. clientCache.Add(store.GetObjectMeta().ResourceVersion, key, client)
  174. }
  175. return client, nil
  176. }
  177. type Connector struct {
  178. NewVaultClient func(c *vault.Config) (util.Client, error)
  179. }
  180. // Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
  181. func (c *Connector) Capabilities() esv1beta1.SecretStoreCapabilities {
  182. return esv1beta1.SecretStoreReadWrite
  183. }
  184. func (c *Connector) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
  185. // controller-runtime/client does not support TokenRequest or other subresource APIs
  186. // so we need to construct our own client and use it to fetch tokens
  187. // (for Kubernetes service account token auth)
  188. restCfg, err := ctrlcfg.GetConfig()
  189. if err != nil {
  190. return nil, err
  191. }
  192. clientset, err := kubernetes.NewForConfig(restCfg)
  193. if err != nil {
  194. return nil, err
  195. }
  196. return c.newClient(ctx, store, kube, clientset.CoreV1(), namespace)
  197. }
  198. func (c *Connector) newClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, corev1 typedcorev1.CoreV1Interface, namespace string) (esv1beta1.SecretsClient, error) {
  199. storeSpec := store.GetSpec()
  200. if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.Vault == nil {
  201. return nil, errors.New(errVaultStore)
  202. }
  203. vaultSpec := storeSpec.Provider.Vault
  204. vStore, cfg, err := c.prepareConfig(kube, corev1, vaultSpec, namespace, store.GetObjectKind().GroupVersionKind().Kind)
  205. if err != nil {
  206. return nil, err
  207. }
  208. client, err := getVaultClient(c, store, cfg)
  209. if err != nil {
  210. return nil, fmt.Errorf(errVaultClient, err)
  211. }
  212. return c.initClient(ctx, vStore, client, cfg, vaultSpec)
  213. }
  214. func (c *Connector) NewGeneratorClient(ctx context.Context, kube kclient.Client, corev1 typedcorev1.CoreV1Interface, vaultSpec *esv1beta1.VaultProvider, namespace string) (util.Client, error) {
  215. vStore, cfg, err := c.prepareConfig(kube, corev1, vaultSpec, namespace, "Generator")
  216. if err != nil {
  217. return nil, err
  218. }
  219. client, err := c.NewVaultClient(cfg)
  220. if err != nil {
  221. return nil, err
  222. }
  223. _, err = c.initClient(ctx, vStore, client, cfg, vaultSpec)
  224. if err != nil {
  225. return nil, err
  226. }
  227. return client, nil
  228. }
  229. func (c *Connector) prepareConfig(kube kclient.Client, corev1 typedcorev1.CoreV1Interface, vaultSpec *esv1beta1.VaultProvider, namespace, storeKind string) (*client, *vault.Config, error) {
  230. vStore := &client{
  231. kube: kube,
  232. corev1: corev1,
  233. store: vaultSpec,
  234. log: logger,
  235. namespace: namespace,
  236. storeKind: storeKind,
  237. }
  238. cfg, err := vStore.newConfig()
  239. if err != nil {
  240. return nil, nil, err
  241. }
  242. return vStore, cfg, nil
  243. }
  244. func (c *Connector) initClient(ctx context.Context, vStore *client, client util.Client, cfg *vault.Config, vaultSpec *esv1beta1.VaultProvider) (esv1beta1.SecretsClient, error) {
  245. if vaultSpec.Namespace != nil {
  246. client.SetNamespace(*vaultSpec.Namespace)
  247. }
  248. if vaultSpec.ReadYourWrites && vaultSpec.ForwardInconsistent {
  249. client.AddHeader("X-Vault-Inconsistent", "forward-active-node")
  250. }
  251. vStore.client = client
  252. vStore.auth = client.Auth()
  253. vStore.logical = client.Logical()
  254. vStore.token = client.AuthToken()
  255. // allow SecretStore controller validation to pass
  256. // when using referent namespace.
  257. if vStore.storeKind == esv1beta1.ClusterSecretStoreKind && vStore.namespace == "" && isReferentSpec(vaultSpec) {
  258. return vStore, nil
  259. }
  260. if err := vStore.setAuth(ctx, cfg); err != nil {
  261. return nil, err
  262. }
  263. return vStore, nil
  264. }
  265. func (c *Connector) ValidateStore(store esv1beta1.GenericStore) error {
  266. if store == nil {
  267. return fmt.Errorf(errInvalidStore)
  268. }
  269. spc := store.GetSpec()
  270. if spc == nil {
  271. return fmt.Errorf(errInvalidStoreSpec)
  272. }
  273. if spc.Provider == nil {
  274. return fmt.Errorf(errInvalidStoreProv)
  275. }
  276. p := spc.Provider.Vault
  277. if p == nil {
  278. return fmt.Errorf(errInvalidVaultProv)
  279. }
  280. if p.Auth.AppRole != nil {
  281. if err := utils.ValidateReferentSecretSelector(store, p.Auth.AppRole.SecretRef); err != nil {
  282. return fmt.Errorf(errInvalidAppRoleSec, err)
  283. }
  284. }
  285. if p.Auth.Cert != nil {
  286. if err := utils.ValidateReferentSecretSelector(store, p.Auth.Cert.ClientCert); err != nil {
  287. return fmt.Errorf(errInvalidClientCert, err)
  288. }
  289. if err := utils.ValidateReferentSecretSelector(store, p.Auth.Cert.SecretRef); err != nil {
  290. return fmt.Errorf(errInvalidCertSec, err)
  291. }
  292. }
  293. if p.Auth.Jwt != nil {
  294. if p.Auth.Jwt.SecretRef != nil {
  295. if err := utils.ValidateReferentSecretSelector(store, *p.Auth.Jwt.SecretRef); err != nil {
  296. return fmt.Errorf(errInvalidJwtSec, err)
  297. }
  298. } else if p.Auth.Jwt.KubernetesServiceAccountToken != nil {
  299. if err := utils.ValidateReferentServiceAccountSelector(store, p.Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef); err != nil {
  300. return fmt.Errorf(errInvalidJwtK8sSA, err)
  301. }
  302. } else {
  303. return fmt.Errorf(errJwtNoTokenSource)
  304. }
  305. }
  306. if p.Auth.Kubernetes != nil {
  307. if p.Auth.Kubernetes.ServiceAccountRef != nil {
  308. if err := utils.ValidateReferentServiceAccountSelector(store, *p.Auth.Kubernetes.ServiceAccountRef); err != nil {
  309. return fmt.Errorf(errInvalidKubeSA, err)
  310. }
  311. }
  312. if p.Auth.Kubernetes.SecretRef != nil {
  313. if err := utils.ValidateReferentSecretSelector(store, *p.Auth.Kubernetes.SecretRef); err != nil {
  314. return fmt.Errorf(errInvalidKubeSec, err)
  315. }
  316. }
  317. }
  318. if p.Auth.Ldap != nil {
  319. if err := utils.ValidateReferentSecretSelector(store, p.Auth.Ldap.SecretRef); err != nil {
  320. return fmt.Errorf(errInvalidLdapSec, err)
  321. }
  322. }
  323. if p.Auth.TokenSecretRef != nil {
  324. if err := utils.ValidateReferentSecretSelector(store, *p.Auth.TokenSecretRef); err != nil {
  325. return fmt.Errorf(errInvalidTokenRef, err)
  326. }
  327. }
  328. if p.Auth.Iam != nil {
  329. if p.Auth.Iam.JWTAuth != nil {
  330. if p.Auth.Iam.JWTAuth.ServiceAccountRef != nil {
  331. if err := utils.ValidateReferentServiceAccountSelector(store, *p.Auth.Iam.JWTAuth.ServiceAccountRef); err != nil {
  332. return fmt.Errorf(errInvalidTokenRef, err)
  333. }
  334. }
  335. }
  336. if p.Auth.Iam.SecretRef != nil {
  337. if err := utils.ValidateReferentSecretSelector(store, p.Auth.Iam.SecretRef.AccessKeyID); err != nil {
  338. return fmt.Errorf(errInvalidTokenRef, err)
  339. }
  340. if err := utils.ValidateReferentSecretSelector(store, p.Auth.Iam.SecretRef.SecretAccessKey); err != nil {
  341. return fmt.Errorf(errInvalidTokenRef, err)
  342. }
  343. if p.Auth.Iam.SecretRef.SessionToken != nil {
  344. if err := utils.ValidateReferentSecretSelector(store, *p.Auth.Iam.SecretRef.SessionToken); err != nil {
  345. return fmt.Errorf(errInvalidTokenRef, err)
  346. }
  347. }
  348. }
  349. }
  350. return nil
  351. }
  352. func (v *client) DeleteSecret(ctx context.Context, remoteRef esv1beta1.PushRemoteRef) error {
  353. path := v.buildPath(remoteRef.GetRemoteKey())
  354. metaPath, err := v.buildMetadataPath(remoteRef.GetRemoteKey())
  355. if err != nil {
  356. return err
  357. }
  358. // Retrieve the secret map from vault and convert the secret value in string form.
  359. _, err = v.readSecret(ctx, path, "")
  360. // If error is not of type secret not found, we should error
  361. if err != nil && errors.Is(err, esv1beta1.NoSecretError{}) {
  362. return nil
  363. }
  364. if err != nil {
  365. return err
  366. }
  367. metadata, err := v.readSecretMetadata(ctx, remoteRef.GetRemoteKey())
  368. if err != nil {
  369. return err
  370. }
  371. manager, ok := metadata["managed-by"]
  372. if !ok || manager != "external-secrets" {
  373. return nil
  374. }
  375. _, err = v.logical.DeleteWithContext(ctx, path)
  376. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultDeleteSecret, err)
  377. if err != nil {
  378. return fmt.Errorf("could not delete secret %v: %w", remoteRef.GetRemoteKey(), err)
  379. }
  380. _, err = v.logical.DeleteWithContext(ctx, metaPath)
  381. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultDeleteSecret, err)
  382. if err != nil {
  383. return fmt.Errorf("could not delete secret metadata %v: %w", remoteRef.GetRemoteKey(), err)
  384. }
  385. return nil
  386. }
  387. func (v *client) PushSecret(ctx context.Context, value []byte, remoteRef esv1beta1.PushRemoteRef) error {
  388. label := map[string]interface{}{
  389. "custom_metadata": map[string]string{
  390. "managed-by": "external-secrets",
  391. },
  392. }
  393. secretVal := make(map[string]interface{})
  394. err := json.Unmarshal(value, &secretVal)
  395. if err != nil {
  396. return fmt.Errorf("failed to convert value to a valid JSON: %w", err)
  397. }
  398. secretToPush := map[string]interface{}{
  399. "data": secretVal,
  400. }
  401. path := v.buildPath(remoteRef.GetRemoteKey())
  402. metaPath, err := v.buildMetadataPath(remoteRef.GetRemoteKey())
  403. if err != nil {
  404. return err
  405. }
  406. // Retrieve the secret map from vault and convert the secret value in string form.
  407. vaultSecret, err := v.readSecret(ctx, path, "")
  408. // If error is not of type secret not found, we should error
  409. if err != nil && !errors.Is(err, esv1beta1.NoSecretError{}) {
  410. return err
  411. }
  412. // If the secret exists (err == nil), we should check if it is managed by external-secrets
  413. if err == nil {
  414. metadata, err := v.readSecretMetadata(ctx, remoteRef.GetRemoteKey())
  415. if err != nil {
  416. return err
  417. }
  418. manager, ok := metadata["managed-by"]
  419. if !ok || manager != "external-secrets" {
  420. return fmt.Errorf("secret not managed by external-secrets")
  421. }
  422. }
  423. vaultSecretValue, err := json.Marshal(vaultSecret)
  424. if err != nil {
  425. return fmt.Errorf("error marshaling vault secret: %w", err)
  426. }
  427. if bytes.Equal(vaultSecretValue, value) {
  428. return nil
  429. }
  430. _, err = v.logical.WriteWithContext(ctx, metaPath, label)
  431. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultWriteSecretData, err)
  432. if err != nil {
  433. return err
  434. }
  435. // Otherwise, create or update the version.
  436. _, err = v.logical.WriteWithContext(ctx, path, secretToPush)
  437. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultWriteSecretData, err)
  438. return err
  439. }
  440. // GetAllSecrets gets multiple secrets from the provider and loads into a kubernetes secret.
  441. // First load all secrets from secretStore path configuration
  442. // Then, gets secrets from a matching name or matching custom_metadata.
  443. func (v *client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  444. if v.store.Version == esv1beta1.VaultKVStoreV1 {
  445. return nil, errors.New(errUnsupportedKvVersion)
  446. }
  447. searchPath := ""
  448. if ref.Path != nil {
  449. searchPath = *ref.Path + "/"
  450. }
  451. potentialSecrets, err := v.listSecrets(ctx, searchPath)
  452. if err != nil {
  453. return nil, err
  454. }
  455. if ref.Name != nil {
  456. return v.findSecretsFromName(ctx, potentialSecrets, *ref.Name)
  457. }
  458. return v.findSecretsFromTags(ctx, potentialSecrets, ref.Tags)
  459. }
  460. func (v *client) findSecretsFromTags(ctx context.Context, candidates []string, tags map[string]string) (map[string][]byte, error) {
  461. secrets := make(map[string][]byte)
  462. for _, name := range candidates {
  463. match := true
  464. metadata, err := v.readSecretMetadata(ctx, name)
  465. if err != nil {
  466. return nil, err
  467. }
  468. for tk, tv := range tags {
  469. p, ok := metadata[tk]
  470. if !ok || p != tv {
  471. match = false
  472. break
  473. }
  474. }
  475. if match {
  476. secret, err := v.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: name})
  477. if errors.Is(err, esv1beta1.NoSecretError{}) {
  478. continue
  479. }
  480. if err != nil {
  481. return nil, err
  482. }
  483. if secret != nil {
  484. secrets[name] = secret
  485. }
  486. }
  487. }
  488. return secrets, nil
  489. }
  490. func (v *client) findSecretsFromName(ctx context.Context, candidates []string, ref esv1beta1.FindName) (map[string][]byte, error) {
  491. secrets := make(map[string][]byte)
  492. matcher, err := find.New(ref)
  493. if err != nil {
  494. return nil, err
  495. }
  496. for _, name := range candidates {
  497. ok := matcher.MatchName(name)
  498. if ok {
  499. secret, err := v.GetSecret(ctx, esv1beta1.ExternalSecretDataRemoteRef{Key: name})
  500. if errors.Is(err, esv1beta1.NoSecretError{}) {
  501. continue
  502. }
  503. if err != nil {
  504. return nil, err
  505. }
  506. if secret != nil {
  507. secrets[name] = secret
  508. }
  509. }
  510. }
  511. return secrets, nil
  512. }
  513. func (v *client) listSecrets(ctx context.Context, path string) ([]string, error) {
  514. secrets := make([]string, 0)
  515. url, err := v.buildMetadataPath(path)
  516. if err != nil {
  517. return nil, err
  518. }
  519. secret, err := v.logical.ListWithContext(ctx, url)
  520. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultListSecrets, err)
  521. if err != nil {
  522. return nil, fmt.Errorf(errReadSecret, err)
  523. }
  524. if secret == nil {
  525. return nil, fmt.Errorf("provided path %v does not contain any secrets", url)
  526. }
  527. t, ok := secret.Data["keys"]
  528. if !ok {
  529. return nil, nil
  530. }
  531. paths := t.([]interface{})
  532. for _, p := range paths {
  533. strPath := p.(string)
  534. fullPath := path + strPath // because path always ends with a /
  535. if path == "" {
  536. fullPath = strPath
  537. }
  538. // Recurrently find secrets
  539. if !strings.HasSuffix(p.(string), "/") {
  540. secrets = append(secrets, fullPath)
  541. } else {
  542. partial, err := v.listSecrets(ctx, fullPath)
  543. if err != nil {
  544. return nil, err
  545. }
  546. secrets = append(secrets, partial...)
  547. }
  548. }
  549. return secrets, nil
  550. }
  551. func (v *client) readSecretMetadata(ctx context.Context, path string) (map[string]string, error) {
  552. metadata := make(map[string]string)
  553. url, err := v.buildMetadataPath(path)
  554. if err != nil {
  555. return nil, err
  556. }
  557. secret, err := v.logical.ReadWithDataWithContext(ctx, url, nil)
  558. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultReadSecretData, err)
  559. if err != nil {
  560. return nil, fmt.Errorf(errReadSecret, err)
  561. }
  562. if secret == nil {
  563. return nil, errors.New(errNotFound)
  564. }
  565. t, ok := secret.Data["custom_metadata"]
  566. if !ok {
  567. return nil, nil
  568. }
  569. d, ok := t.(map[string]interface{})
  570. if !ok {
  571. return metadata, nil
  572. }
  573. for k, v := range d {
  574. metadata[k] = v.(string)
  575. }
  576. return metadata, nil
  577. }
  578. // GetSecret supports two types:
  579. // 1. get the full secret as json-encoded value
  580. // by leaving the ref.Property empty.
  581. // 2. get a key from the secret.
  582. // Nested values are supported by specifying a gjson expression
  583. func (v *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  584. var data map[string]interface{}
  585. var err error
  586. if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
  587. if v.store.Version == esv1beta1.VaultKVStoreV1 {
  588. return nil, errors.New(errUnsupportedMetadataKvVersion)
  589. }
  590. metadata, err := v.readSecretMetadata(ctx, ref.Key)
  591. if err != nil {
  592. return nil, err
  593. }
  594. if len(metadata) == 0 {
  595. return nil, nil
  596. }
  597. data = make(map[string]interface{}, len(metadata))
  598. for k, v := range metadata {
  599. data[k] = v
  600. }
  601. } else {
  602. data, err = v.readSecret(ctx, ref.Key, ref.Version)
  603. if err != nil {
  604. return nil, err
  605. }
  606. }
  607. // Return nil if secret value is null
  608. if data == nil {
  609. return nil, nil
  610. }
  611. jsonStr, err := json.Marshal(data)
  612. if err != nil {
  613. return nil, err
  614. }
  615. // (1): return raw json if no property is defined
  616. if ref.Property == "" {
  617. return jsonStr, nil
  618. }
  619. // For backwards compatibility we want the
  620. // actual keys to take precedence over gjson syntax
  621. // (2): extract key from secret with property
  622. if _, ok := data[ref.Property]; ok {
  623. return GetTypedKey(data, ref.Property)
  624. }
  625. // (3): extract key from secret using gjson
  626. val := gjson.Get(string(jsonStr), ref.Property)
  627. if !val.Exists() {
  628. return nil, fmt.Errorf(errSecretKeyFmt, ref.Property)
  629. }
  630. return []byte(val.String()), nil
  631. }
  632. // GetSecretMap supports two modes of operation:
  633. // 1. get the full secret from the vault data payload (by leaving .property empty).
  634. // 2. extract key/value pairs from a (nested) object.
  635. func (v *client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  636. data, err := v.GetSecret(ctx, ref)
  637. if err != nil {
  638. return nil, err
  639. }
  640. var secretData map[string]interface{}
  641. err = json.Unmarshal(data, &secretData)
  642. if err != nil {
  643. return nil, err
  644. }
  645. byteMap := make(map[string][]byte, len(secretData))
  646. for k := range secretData {
  647. byteMap[k], err = GetTypedKey(secretData, k)
  648. if err != nil {
  649. return nil, err
  650. }
  651. }
  652. return byteMap, nil
  653. }
  654. func GetTypedKey(data map[string]interface{}, key string) ([]byte, error) {
  655. v, ok := data[key]
  656. if !ok {
  657. return nil, fmt.Errorf(errUnexpectedKey, key)
  658. }
  659. switch t := v.(type) {
  660. case string:
  661. return []byte(t), nil
  662. case map[string]interface{}:
  663. return json.Marshal(t)
  664. case []string:
  665. return []byte(strings.Join(t, "\n")), nil
  666. case []byte:
  667. return t, nil
  668. // also covers int and float32 due to json.Marshal
  669. case float64:
  670. return []byte(strconv.FormatFloat(t, 'f', -1, 64)), nil
  671. case json.Number:
  672. return []byte(t.String()), nil
  673. case []interface{}:
  674. return json.Marshal(t)
  675. case bool:
  676. return []byte(strconv.FormatBool(t)), nil
  677. case nil:
  678. return []byte(nil), nil
  679. default:
  680. return nil, fmt.Errorf(errSecretFormat, key, reflect.TypeOf(t))
  681. }
  682. }
  683. func (v *client) Close(ctx context.Context) error {
  684. // Revoke the token if we have one set, it wasn't sourced from a TokenSecretRef,
  685. // and token caching isn't enabled
  686. if !enableCache && v.client.Token() != "" && v.store.Auth.TokenSecretRef == nil {
  687. err := revokeTokenIfValid(ctx, v.client)
  688. if err != nil {
  689. return err
  690. }
  691. }
  692. return nil
  693. }
  694. func isReferentSpec(prov *esv1beta1.VaultProvider) bool {
  695. if prov.Auth.TokenSecretRef != nil && prov.Auth.TokenSecretRef.Namespace == nil {
  696. return true
  697. }
  698. if prov.Auth.AppRole != nil && prov.Auth.AppRole.SecretRef.Namespace == nil {
  699. return true
  700. }
  701. if prov.Auth.Kubernetes != nil && prov.Auth.Kubernetes.SecretRef != nil && prov.Auth.Kubernetes.SecretRef.Namespace == nil {
  702. return true
  703. }
  704. if prov.Auth.Kubernetes != nil && prov.Auth.Kubernetes.ServiceAccountRef != nil && prov.Auth.Kubernetes.ServiceAccountRef.Namespace == nil {
  705. return true
  706. }
  707. if prov.Auth.Ldap != nil && prov.Auth.Ldap.SecretRef.Namespace == nil {
  708. return true
  709. }
  710. if prov.Auth.Jwt != nil && prov.Auth.Jwt.SecretRef != nil && prov.Auth.Jwt.SecretRef.Namespace == nil {
  711. return true
  712. }
  713. if prov.Auth.Jwt != nil && prov.Auth.Jwt.KubernetesServiceAccountToken != nil && prov.Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef.Namespace == nil {
  714. return true
  715. }
  716. if prov.Auth.Cert != nil && prov.Auth.Cert.SecretRef.Namespace == nil {
  717. return true
  718. }
  719. if prov.Auth.Iam != nil && prov.Auth.Iam.JWTAuth != nil && prov.Auth.Iam.JWTAuth.ServiceAccountRef != nil && prov.Auth.Iam.JWTAuth.ServiceAccountRef.Namespace == nil {
  720. return true
  721. }
  722. if prov.Auth.Iam != nil && prov.Auth.Iam.SecretRef != nil &&
  723. (prov.Auth.Iam.SecretRef.AccessKeyID.Namespace == nil ||
  724. prov.Auth.Iam.SecretRef.SecretAccessKey.Namespace == nil ||
  725. (prov.Auth.Iam.SecretRef.SessionToken != nil && prov.Auth.Iam.SecretRef.SessionToken.Namespace == nil)) {
  726. return true
  727. }
  728. return false
  729. }
  730. func (v *client) Validate() (esv1beta1.ValidationResult, error) {
  731. // when using referent namespace we can not validate the token
  732. // because the namespace is not known yet when Validate() is called
  733. // from the SecretStore controller.
  734. if v.storeKind == esv1beta1.ClusterSecretStoreKind && isReferentSpec(v.store) {
  735. return esv1beta1.ValidationResultUnknown, nil
  736. }
  737. _, err := checkToken(context.Background(), v.token)
  738. if err != nil {
  739. return esv1beta1.ValidationResultError, fmt.Errorf(errInvalidCredentials, err)
  740. }
  741. return esv1beta1.ValidationResultReady, nil
  742. }
  743. func (v *client) buildMetadataPath(path string) (string, error) {
  744. var url string
  745. if v.store.Path == nil && !strings.Contains(path, "data") {
  746. return "", fmt.Errorf(errPathInvalid)
  747. }
  748. if v.store.Path == nil {
  749. path = strings.Replace(path, "data", "metadata", 1)
  750. url = path
  751. } else {
  752. url = fmt.Sprintf("%s/metadata/%s", *v.store.Path, path)
  753. }
  754. return url, nil
  755. }
  756. /*
  757. buildPath is a helper method to build the vault equivalent path
  758. from ExternalSecrets and SecretStore manifests. the path build logic
  759. varies depending on the SecretStore KV version:
  760. Example inputs/outputs:
  761. # simple build:
  762. kv version == "v2":
  763. provider_path: "secret/path"
  764. input: "foo"
  765. output: "secret/path/data/foo" # provider_path and data are prepended
  766. kv version == "v1":
  767. provider_path: "secret/path"
  768. input: "foo"
  769. output: "secret/path/foo" # provider_path is prepended
  770. # inheriting paths:
  771. kv version == "v2":
  772. provider_path: "secret/path"
  773. input: "secret/path/foo"
  774. output: "secret/path/data/foo" #data is prepended
  775. kv version == "v2":
  776. provider_path: "secret/path"
  777. input: "secret/path/data/foo"
  778. output: "secret/path/data/foo" #noop
  779. kv version == "v1":
  780. provider_path: "secret/path"
  781. input: "secret/path/foo"
  782. output: "secret/path/foo" #noop
  783. # provider path not defined:
  784. kv version == "v2":
  785. provider_path: nil
  786. input: "secret/path/foo"
  787. output: "secret/data/path/foo" # data is prepended to secret/
  788. kv version == "v2":
  789. provider_path: nil
  790. input: "secret/path/data/foo"
  791. output: "secret/path/data/foo" #noop
  792. kv version == "v1":
  793. provider_path: nil
  794. input: "secret/path/foo"
  795. output: "secret/path/foo" #noop
  796. */
  797. func (v *client) buildPath(path string) string {
  798. optionalMount := v.store.Path
  799. out := path
  800. // if optionalMount is Set, remove it from path if its there
  801. if optionalMount != nil {
  802. cut := *optionalMount + "/"
  803. if strings.HasPrefix(out, cut) {
  804. // This current logic induces a bug when the actual secret resides on same path names as the mount path.
  805. _, out, _ = strings.Cut(out, cut)
  806. // if data succeeds optionalMount on v2 store, we should remove it as well
  807. if strings.HasPrefix(out, "data/") && v.store.Version == esv1beta1.VaultKVStoreV2 {
  808. _, out, _ = strings.Cut(out, "data/")
  809. }
  810. }
  811. buildPath := strings.Split(out, "/")
  812. buildMount := strings.Split(*optionalMount, "/")
  813. if v.store.Version == esv1beta1.VaultKVStoreV2 {
  814. buildMount = append(buildMount, "data")
  815. }
  816. buildMount = append(buildMount, buildPath...)
  817. out = strings.Join(buildMount, "/")
  818. return out
  819. }
  820. if !strings.Contains(out, "/data/") && v.store.Version == esv1beta1.VaultKVStoreV2 {
  821. buildPath := strings.Split(out, "/")
  822. buildMount := []string{buildPath[0], "data"}
  823. buildMount = append(buildMount, buildPath[1:]...)
  824. out = strings.Join(buildMount, "/")
  825. return out
  826. }
  827. return out
  828. }
  829. func (v *client) readSecret(ctx context.Context, path, version string) (map[string]interface{}, error) {
  830. dataPath := v.buildPath(path)
  831. // path formated according to vault docs for v1 and v2 API
  832. // v1: https://www.vaultproject.io/api-docs/secret/kv/kv-v1#read-secret
  833. // v2: https://www.vaultproject.io/api/secret/kv/kv-v2#read-secret-version
  834. var params map[string][]string
  835. if version != "" {
  836. params = make(map[string][]string)
  837. params["version"] = []string{version}
  838. }
  839. vaultSecret, err := v.logical.ReadWithDataWithContext(ctx, dataPath, params)
  840. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultReadSecretData, err)
  841. if err != nil {
  842. return nil, fmt.Errorf(errReadSecret, err)
  843. }
  844. if vaultSecret == nil {
  845. return nil, esv1beta1.NoSecretError{}
  846. }
  847. secretData := vaultSecret.Data
  848. if v.store.Version == esv1beta1.VaultKVStoreV2 {
  849. // Vault KV2 has data embedded within sub-field
  850. // reference - https://www.vaultproject.io/api/secret/kv/kv-v2#read-secret-version
  851. dataInt, ok := vaultSecret.Data["data"]
  852. if !ok {
  853. return nil, errors.New(errDataField)
  854. }
  855. if dataInt == nil {
  856. return nil, esv1beta1.NoSecretError{}
  857. }
  858. secretData, ok = dataInt.(map[string]interface{})
  859. if !ok {
  860. return nil, errors.New(errJSONUnmarshall)
  861. }
  862. }
  863. return secretData, nil
  864. }
  865. func (v *client) newConfig() (*vault.Config, error) {
  866. cfg := vault.DefaultConfig()
  867. cfg.Address = v.store.Server
  868. // In a controller-runtime context, we rely on the reconciliation process for retrying
  869. cfg.MaxRetries = 0
  870. if len(v.store.CABundle) == 0 && v.store.CAProvider == nil {
  871. return cfg, nil
  872. }
  873. caCertPool := x509.NewCertPool()
  874. if len(v.store.CABundle) > 0 {
  875. ok := caCertPool.AppendCertsFromPEM(v.store.CABundle)
  876. if !ok {
  877. return nil, errors.New(errVaultCert)
  878. }
  879. }
  880. if v.store.CAProvider != nil && v.storeKind == esv1beta1.ClusterSecretStoreKind && v.store.CAProvider.Namespace == nil {
  881. return nil, errors.New(errCANamespace)
  882. }
  883. if v.store.CAProvider != nil {
  884. var cert []byte
  885. var err error
  886. switch v.store.CAProvider.Type {
  887. case esv1beta1.CAProviderTypeSecret:
  888. cert, err = getCertFromSecret(v)
  889. case esv1beta1.CAProviderTypeConfigMap:
  890. cert, err = getCertFromConfigMap(v)
  891. default:
  892. return nil, errors.New(errUnknownCAProvider)
  893. }
  894. if err != nil {
  895. return nil, err
  896. }
  897. ok := caCertPool.AppendCertsFromPEM(cert)
  898. if !ok {
  899. return nil, errors.New(errVaultCert)
  900. }
  901. }
  902. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  903. transport.TLSClientConfig.RootCAs = caCertPool
  904. }
  905. // If either read-after-write consistency feature is enabled, enable ReadYourWrites
  906. cfg.ReadYourWrites = v.store.ReadYourWrites || v.store.ForwardInconsistent
  907. return cfg, nil
  908. }
  909. func getCertFromSecret(v *client) ([]byte, error) {
  910. secretRef := esmeta.SecretKeySelector{
  911. Name: v.store.CAProvider.Name,
  912. Key: v.store.CAProvider.Key,
  913. }
  914. if v.store.CAProvider.Namespace != nil {
  915. secretRef.Namespace = v.store.CAProvider.Namespace
  916. }
  917. ctx := context.Background()
  918. res, err := v.secretKeyRef(ctx, &secretRef)
  919. if err != nil {
  920. return nil, fmt.Errorf(errVaultCert, err)
  921. }
  922. return []byte(res), nil
  923. }
  924. func getCertFromConfigMap(v *client) ([]byte, error) {
  925. objKey := types.NamespacedName{
  926. Name: v.store.CAProvider.Name,
  927. }
  928. if v.store.CAProvider.Namespace != nil {
  929. objKey.Namespace = *v.store.CAProvider.Namespace
  930. }
  931. configMapRef := &corev1.ConfigMap{}
  932. ctx := context.Background()
  933. err := v.kube.Get(ctx, objKey, configMapRef)
  934. if err != nil {
  935. return nil, fmt.Errorf(errVaultCert, err)
  936. }
  937. val, ok := configMapRef.Data[v.store.CAProvider.Key]
  938. if !ok {
  939. return nil, fmt.Errorf(errConfigMapFmt, v.store.CAProvider.Key)
  940. }
  941. return []byte(val), nil
  942. }
  943. /*
  944. setAuth gets a new token using the configured mechanism.
  945. If there's already a valid token, does nothing.
  946. */
  947. func (v *client) setAuth(ctx context.Context, cfg *vault.Config) error {
  948. tokenExists := false
  949. var err error
  950. if v.client.Token() != "" {
  951. tokenExists, err = checkToken(ctx, v.token)
  952. }
  953. if tokenExists {
  954. v.log.V(1).Info("Re-using existing token")
  955. return err
  956. }
  957. tokenExists, err = setSecretKeyToken(ctx, v)
  958. if tokenExists {
  959. v.log.V(1).Info("Set token from secret")
  960. return err
  961. }
  962. tokenExists, err = setAppRoleToken(ctx, v)
  963. if tokenExists {
  964. v.log.V(1).Info("Retrieved new token using AppRole auth")
  965. return err
  966. }
  967. tokenExists, err = setKubernetesAuthToken(ctx, v)
  968. if tokenExists {
  969. v.log.V(1).Info("Retrieved new token using Kubernetes auth")
  970. return err
  971. }
  972. tokenExists, err = setLdapAuthToken(ctx, v)
  973. if tokenExists {
  974. v.log.V(1).Info("Retrieved new token using LDAP auth")
  975. return err
  976. }
  977. tokenExists, err = setJwtAuthToken(ctx, v)
  978. if tokenExists {
  979. v.log.V(1).Info("Retrieved new token using JWT auth")
  980. return err
  981. }
  982. tokenExists, err = setCertAuthToken(ctx, v, cfg)
  983. if tokenExists {
  984. v.log.V(1).Info("Retrieved new token using certificate auth")
  985. return err
  986. }
  987. tokenExists, err = setIamAuthToken(ctx, v, vaultiamauth.DefaultJWTProvider, vaultiamauth.DefaultSTSProvider)
  988. if tokenExists {
  989. v.log.V(1).Info("Retrieved new token using IAM auth")
  990. return err
  991. }
  992. return errors.New(errAuthFormat)
  993. }
  994. func setSecretKeyToken(ctx context.Context, v *client) (bool, error) {
  995. tokenRef := v.store.Auth.TokenSecretRef
  996. if tokenRef != nil {
  997. token, err := v.secretKeyRef(ctx, tokenRef)
  998. if err != nil {
  999. return true, err
  1000. }
  1001. v.client.SetToken(token)
  1002. return true, nil
  1003. }
  1004. return false, nil
  1005. }
  1006. func setAppRoleToken(ctx context.Context, v *client) (bool, error) {
  1007. appRole := v.store.Auth.AppRole
  1008. if appRole != nil {
  1009. err := v.requestTokenWithAppRoleRef(ctx, appRole)
  1010. if err != nil {
  1011. return true, err
  1012. }
  1013. return true, nil
  1014. }
  1015. return false, nil
  1016. }
  1017. func setKubernetesAuthToken(ctx context.Context, v *client) (bool, error) {
  1018. kubernetesAuth := v.store.Auth.Kubernetes
  1019. if kubernetesAuth != nil {
  1020. err := v.requestTokenWithKubernetesAuth(ctx, kubernetesAuth)
  1021. if err != nil {
  1022. return true, err
  1023. }
  1024. return true, nil
  1025. }
  1026. return false, nil
  1027. }
  1028. func setLdapAuthToken(ctx context.Context, v *client) (bool, error) {
  1029. ldapAuth := v.store.Auth.Ldap
  1030. if ldapAuth != nil {
  1031. err := v.requestTokenWithLdapAuth(ctx, ldapAuth)
  1032. if err != nil {
  1033. return true, err
  1034. }
  1035. return true, nil
  1036. }
  1037. return false, nil
  1038. }
  1039. func setJwtAuthToken(ctx context.Context, v *client) (bool, error) {
  1040. jwtAuth := v.store.Auth.Jwt
  1041. if jwtAuth != nil {
  1042. err := v.requestTokenWithJwtAuth(ctx, jwtAuth)
  1043. if err != nil {
  1044. return true, err
  1045. }
  1046. return true, nil
  1047. }
  1048. return false, nil
  1049. }
  1050. func setCertAuthToken(ctx context.Context, v *client, cfg *vault.Config) (bool, error) {
  1051. certAuth := v.store.Auth.Cert
  1052. if certAuth != nil {
  1053. err := v.requestTokenWithCertAuth(ctx, certAuth, cfg)
  1054. if err != nil {
  1055. return true, err
  1056. }
  1057. return true, nil
  1058. }
  1059. return false, nil
  1060. }
  1061. func setIamAuthToken(ctx context.Context, v *client, jwtProvider util.JwtProviderFactory, assumeRoler vaultiamauth.STSProvider) (bool, error) {
  1062. iamAuth := v.store.Auth.Iam
  1063. isClusterKind := v.storeKind == esv1beta1.ClusterSecretStoreKind
  1064. if iamAuth != nil {
  1065. err := v.requestTokenWithIamAuth(ctx, iamAuth, isClusterKind, v.kube, v.namespace, jwtProvider, assumeRoler)
  1066. if err != nil {
  1067. return true, err
  1068. }
  1069. return true, nil
  1070. }
  1071. return false, nil
  1072. }
  1073. func (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccountRef *esmeta.ServiceAccountSelector) (string, error) {
  1074. serviceAccount := &corev1.ServiceAccount{}
  1075. ref := types.NamespacedName{
  1076. Namespace: v.namespace,
  1077. Name: serviceAccountRef.Name,
  1078. }
  1079. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  1080. (serviceAccountRef.Namespace != nil) {
  1081. ref.Namespace = *serviceAccountRef.Namespace
  1082. }
  1083. err := v.kube.Get(ctx, ref, serviceAccount)
  1084. if err != nil {
  1085. return "", fmt.Errorf(errGetKubeSA, ref.Name, err)
  1086. }
  1087. if len(serviceAccount.Secrets) == 0 {
  1088. return "", fmt.Errorf(errGetKubeSASecrets, ref.Name)
  1089. }
  1090. for _, tokenRef := range serviceAccount.Secrets {
  1091. retval, err := v.secretKeyRef(ctx, &esmeta.SecretKeySelector{
  1092. Name: tokenRef.Name,
  1093. Namespace: &ref.Namespace,
  1094. Key: "token",
  1095. })
  1096. if err != nil {
  1097. continue
  1098. }
  1099. return retval, nil
  1100. }
  1101. return "", fmt.Errorf(errGetKubeSANoToken, ref.Name)
  1102. }
  1103. func (v *client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySelector) (string, error) {
  1104. secret := &corev1.Secret{}
  1105. ref := types.NamespacedName{
  1106. Namespace: v.namespace,
  1107. Name: secretRef.Name,
  1108. }
  1109. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  1110. (secretRef.Namespace != nil) {
  1111. ref.Namespace = *secretRef.Namespace
  1112. }
  1113. err := v.kube.Get(ctx, ref, secret)
  1114. if err != nil {
  1115. return "", fmt.Errorf(errGetKubeSecret, ref.Name, err)
  1116. }
  1117. keyBytes, ok := secret.Data[secretRef.Key]
  1118. if !ok {
  1119. return "", fmt.Errorf(errSecretKeyFmt, secretRef.Key)
  1120. }
  1121. value := string(keyBytes)
  1122. valueStr := strings.TrimSpace(value)
  1123. return valueStr, nil
  1124. }
  1125. func (v *client) serviceAccountToken(ctx context.Context, serviceAccountRef esmeta.ServiceAccountSelector, additionalAud []string, expirationSeconds int64) (string, error) {
  1126. audiences := serviceAccountRef.Audiences
  1127. if len(additionalAud) > 0 {
  1128. audiences = append(audiences, additionalAud...)
  1129. }
  1130. tokenRequest := &authenticationv1.TokenRequest{
  1131. ObjectMeta: metav1.ObjectMeta{
  1132. Namespace: v.namespace,
  1133. },
  1134. Spec: authenticationv1.TokenRequestSpec{
  1135. Audiences: audiences,
  1136. ExpirationSeconds: &expirationSeconds,
  1137. },
  1138. }
  1139. if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
  1140. (serviceAccountRef.Namespace != nil) {
  1141. tokenRequest.Namespace = *serviceAccountRef.Namespace
  1142. }
  1143. tokenResponse, err := v.corev1.ServiceAccounts(tokenRequest.Namespace).CreateToken(ctx, serviceAccountRef.Name, tokenRequest, metav1.CreateOptions{})
  1144. if err != nil {
  1145. return "", fmt.Errorf(errGetKubeSATokenRequest, serviceAccountRef.Name, err)
  1146. }
  1147. return tokenResponse.Status.Token, nil
  1148. }
  1149. // checkToken does a lookup and checks if the provided token exists.
  1150. func checkToken(ctx context.Context, token util.Token) (bool, error) {
  1151. // https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
  1152. resp, err := token.LookupSelfWithContext(ctx)
  1153. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLookupSelf, err)
  1154. if err != nil {
  1155. return false, err
  1156. }
  1157. t, ok := resp.Data["type"]
  1158. if !ok {
  1159. return false, fmt.Errorf("could not assert token type")
  1160. }
  1161. tokenType := t.(string)
  1162. if tokenType == "batch" {
  1163. return false, nil
  1164. }
  1165. return true, nil
  1166. }
  1167. func revokeTokenIfValid(ctx context.Context, client util.Client) error {
  1168. valid, err := checkToken(ctx, client.AuthToken())
  1169. if err != nil {
  1170. return fmt.Errorf(errVaultRevokeToken, err)
  1171. }
  1172. if valid {
  1173. err = client.AuthToken().RevokeSelfWithContext(ctx, client.Token())
  1174. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultRevokeSelf, err)
  1175. if err != nil {
  1176. return fmt.Errorf(errVaultRevokeToken, err)
  1177. }
  1178. client.ClearToken()
  1179. }
  1180. return nil
  1181. }
  1182. func (v *client) requestTokenWithAppRoleRef(ctx context.Context, appRole *esv1beta1.VaultAppRole) error {
  1183. roleID := strings.TrimSpace(appRole.RoleID)
  1184. secretID, err := v.secretKeyRef(ctx, &appRole.SecretRef)
  1185. if err != nil {
  1186. return err
  1187. }
  1188. secret := approle.SecretID{FromString: secretID}
  1189. appRoleClient, err := approle.NewAppRoleAuth(roleID, &secret, approle.WithMountPath(appRole.Path))
  1190. if err != nil {
  1191. return err
  1192. }
  1193. _, err = v.auth.Login(ctx, appRoleClient)
  1194. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLogin, err)
  1195. if err != nil {
  1196. return err
  1197. }
  1198. return nil
  1199. }
  1200. func (v *client) requestTokenWithKubernetesAuth(ctx context.Context, kubernetesAuth *esv1beta1.VaultKubernetesAuth) error {
  1201. jwtString, err := getJwtString(ctx, v, kubernetesAuth)
  1202. if err != nil {
  1203. return err
  1204. }
  1205. k, err := authkubernetes.NewKubernetesAuth(kubernetesAuth.Role, authkubernetes.WithServiceAccountToken(jwtString), authkubernetes.WithMountPath(kubernetesAuth.Path))
  1206. if err != nil {
  1207. return err
  1208. }
  1209. _, err = v.auth.Login(ctx, k)
  1210. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLogin, err)
  1211. if err != nil {
  1212. return err
  1213. }
  1214. return nil
  1215. }
  1216. func getJwtString(ctx context.Context, v *client, kubernetesAuth *esv1beta1.VaultKubernetesAuth) (string, error) {
  1217. if kubernetesAuth.ServiceAccountRef != nil {
  1218. // Kubernetes <v1.24 fetch token via ServiceAccount.Secrets[]
  1219. // this behavior was removed in v1.24 and we must use TokenRequest API (see below)
  1220. jwt, err := v.secretKeyRefForServiceAccount(ctx, kubernetesAuth.ServiceAccountRef)
  1221. if jwt != "" {
  1222. return jwt, err
  1223. }
  1224. if err != nil {
  1225. v.log.V(1).Info("unable to fetch jwt from service account secret, trying service account token next")
  1226. }
  1227. // Kubernetes >=v1.24: fetch token via TokenRequest API
  1228. // note: this is a massive change from vault perspective: the `iss` claim will very likely change.
  1229. // Vault 1.9 deprecated issuer validation by default, and authentication with Vault clusters <1.9 will likely fail.
  1230. jwt, err = v.serviceAccountToken(ctx, *kubernetesAuth.ServiceAccountRef, nil, 600)
  1231. if err != nil {
  1232. return "", err
  1233. }
  1234. return jwt, nil
  1235. } else if kubernetesAuth.SecretRef != nil {
  1236. tokenRef := kubernetesAuth.SecretRef
  1237. if tokenRef.Key == "" {
  1238. tokenRef = kubernetesAuth.SecretRef.DeepCopy()
  1239. tokenRef.Key = "token"
  1240. }
  1241. jwt, err := v.secretKeyRef(ctx, tokenRef)
  1242. if err != nil {
  1243. return "", err
  1244. }
  1245. return jwt, nil
  1246. } else {
  1247. // Kubernetes authentication is specified, but without a referenced
  1248. // Kubernetes secret. We check if the file path for in-cluster service account
  1249. // exists and attempt to use the token for Vault Kubernetes auth.
  1250. if _, err := os.Stat(serviceAccTokenPath); err != nil {
  1251. return "", fmt.Errorf(errServiceAccount, err)
  1252. }
  1253. jwtByte, err := os.ReadFile(serviceAccTokenPath)
  1254. if err != nil {
  1255. return "", fmt.Errorf(errServiceAccount, err)
  1256. }
  1257. return string(jwtByte), nil
  1258. }
  1259. }
  1260. func (v *client) requestTokenWithLdapAuth(ctx context.Context, ldapAuth *esv1beta1.VaultLdapAuth) error {
  1261. username := strings.TrimSpace(ldapAuth.Username)
  1262. password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
  1263. if err != nil {
  1264. return err
  1265. }
  1266. pass := authldap.Password{FromString: password}
  1267. l, err := authldap.NewLDAPAuth(username, &pass, authldap.WithMountPath(ldapAuth.Path))
  1268. if err != nil {
  1269. return err
  1270. }
  1271. _, err = v.auth.Login(ctx, l)
  1272. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLogin, err)
  1273. if err != nil {
  1274. return err
  1275. }
  1276. return nil
  1277. }
  1278. func (v *client) requestTokenWithJwtAuth(ctx context.Context, jwtAuth *esv1beta1.VaultJwtAuth) error {
  1279. role := strings.TrimSpace(jwtAuth.Role)
  1280. var jwt string
  1281. var err error
  1282. if jwtAuth.SecretRef != nil {
  1283. jwt, err = v.secretKeyRef(ctx, jwtAuth.SecretRef)
  1284. } else if k8sServiceAccountToken := jwtAuth.KubernetesServiceAccountToken; k8sServiceAccountToken != nil {
  1285. audiences := k8sServiceAccountToken.Audiences
  1286. if audiences == nil {
  1287. audiences = &[]string{"vault"}
  1288. }
  1289. expirationSeconds := k8sServiceAccountToken.ExpirationSeconds
  1290. if expirationSeconds == nil {
  1291. tmp := int64(600)
  1292. expirationSeconds = &tmp
  1293. }
  1294. jwt, err = v.serviceAccountToken(ctx, k8sServiceAccountToken.ServiceAccountRef, *audiences, *expirationSeconds)
  1295. } else {
  1296. err = fmt.Errorf(errJwtNoTokenSource)
  1297. }
  1298. if err != nil {
  1299. return err
  1300. }
  1301. parameters := map[string]interface{}{
  1302. "role": role,
  1303. "jwt": jwt,
  1304. }
  1305. url := strings.Join([]string{"auth", jwtAuth.Path, "login"}, "/")
  1306. vaultResult, err := v.logical.WriteWithContext(ctx, url, parameters)
  1307. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultWriteSecretData, err)
  1308. if err != nil {
  1309. return err
  1310. }
  1311. token, err := vaultResult.TokenID()
  1312. if err != nil {
  1313. return fmt.Errorf(errVaultToken, err)
  1314. }
  1315. v.client.SetToken(token)
  1316. return nil
  1317. }
  1318. func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1beta1.VaultCertAuth, cfg *vault.Config) error {
  1319. clientKey, err := v.secretKeyRef(ctx, &certAuth.SecretRef)
  1320. if err != nil {
  1321. return err
  1322. }
  1323. clientCert, err := v.secretKeyRef(ctx, &certAuth.ClientCert)
  1324. if err != nil {
  1325. return err
  1326. }
  1327. cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
  1328. if err != nil {
  1329. return fmt.Errorf(errClientTLSAuth, err)
  1330. }
  1331. if transport, ok := cfg.HttpClient.Transport.(*http.Transport); ok {
  1332. transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
  1333. }
  1334. url := strings.Join([]string{"auth", "cert", "login"}, "/")
  1335. vaultResult, err := v.logical.WriteWithContext(ctx, url, nil)
  1336. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultWriteSecretData, err)
  1337. if err != nil {
  1338. return fmt.Errorf(errVaultRequest, err)
  1339. }
  1340. token, err := vaultResult.TokenID()
  1341. if err != nil {
  1342. return fmt.Errorf(errVaultToken, err)
  1343. }
  1344. v.client.SetToken(token)
  1345. return nil
  1346. }
  1347. func (v *client) requestTokenWithIamAuth(ctx context.Context, iamAuth *esv1beta1.VaultIamAuth, ick bool, k kclient.Client, n string, jwtProvider util.JwtProviderFactory, assumeRoler vaultiamauth.STSProvider) error {
  1348. jwtAuth := iamAuth.JWTAuth
  1349. secretRefAuth := iamAuth.SecretRef
  1350. regionAWS := defaultAWSRegion
  1351. awsAuthMountPath := defaultAWSAuthMountPath
  1352. if iamAuth.Region != "" {
  1353. regionAWS = iamAuth.Region
  1354. }
  1355. if iamAuth.Path != "" {
  1356. awsAuthMountPath = iamAuth.Path
  1357. }
  1358. var creds *credentials.Credentials
  1359. var err error
  1360. if jwtAuth != nil { // use credentials from a sa explicitly defined and referenced. Highest preference is given to this method/configuration.
  1361. creds, err = vaultiamauth.CredsFromServiceAccount(ctx, *iamAuth, regionAWS, ick, k, n, jwtProvider)
  1362. if err != nil {
  1363. return err
  1364. }
  1365. } else if secretRefAuth != nil { // if jwtAuth is not defined, check if secretRef is defined. Second preference.
  1366. logger.V(1).Info("using credentials from secretRef")
  1367. creds, err = vaultiamauth.CredsFromSecretRef(ctx, *iamAuth, ick, k, n)
  1368. if err != nil {
  1369. return err
  1370. }
  1371. }
  1372. // Neither of jwtAuth or secretRefAuth defined. Last preference.
  1373. // Default to controller pod's identity
  1374. if jwtAuth == nil && secretRefAuth == nil {
  1375. // Checking if controller pod's service account is IRSA enabled and Web Identity token is available on pod
  1376. tknFile, tknFileEnvVarPresent := os.LookupEnv(vaultiamauth.AWSWebIdentityTokenFileEnvVar)
  1377. if !tknFileEnvVarPresent {
  1378. return fmt.Errorf(errIrsaTokenEnvVarNotFoundOnPod, vaultiamauth.AWSWebIdentityTokenFileEnvVar) // No Web Identity(IRSA) token found on pod
  1379. }
  1380. // IRSA enabled service account, let's check that the jwt token filemount and file exists
  1381. if _, err := os.Stat(tknFile); err != nil {
  1382. return fmt.Errorf(errIrsaTokenFileNotFoundOnPod, tknFile, err)
  1383. }
  1384. // everything looks good so far, let's fetch the jwt token from AWS_WEB_IDENTITY_TOKEN_FILE
  1385. jwtByte, err := os.ReadFile(tknFile)
  1386. if err != nil {
  1387. return fmt.Errorf(errIrsaTokenFileNotReadable, tknFile, err)
  1388. }
  1389. // let's parse the jwt token
  1390. parser := jwt.NewParser(jwt.WithoutClaimsValidation())
  1391. token, _, err := parser.ParseUnverified(string(jwtByte), jwt.MapClaims{})
  1392. if err != nil {
  1393. return fmt.Errorf(errIrsaTokenNotValidJWT, tknFile, err) // JWT token parser error
  1394. }
  1395. var ns string
  1396. var sa string
  1397. // let's fetch the namespace and serviceaccount from parsed jwt token
  1398. if claims, ok := token.Claims.(jwt.MapClaims); ok {
  1399. ns = claims["kubernetes.io"].(map[string]interface{})["namespace"].(string)
  1400. sa = claims["kubernetes.io"].(map[string]interface{})["serviceaccount"].(map[string]interface{})["name"].(string)
  1401. } else {
  1402. return fmt.Errorf(errPodInfoNotFoundOnToken, tknFile, err)
  1403. }
  1404. creds, err = vaultiamauth.CredsFromControllerServiceAccount(ctx, sa, ns, regionAWS, k, jwtProvider)
  1405. if err != nil {
  1406. return err
  1407. }
  1408. }
  1409. config := aws.NewConfig().WithEndpointResolver(vaultiamauth.ResolveEndpoint())
  1410. if creds != nil {
  1411. config.WithCredentials(creds)
  1412. }
  1413. if regionAWS != "" {
  1414. config.WithRegion(regionAWS)
  1415. }
  1416. sess, err := vaultiamauth.GetAWSSession(config)
  1417. if err != nil {
  1418. return err
  1419. }
  1420. if iamAuth.AWSIAMRole != "" {
  1421. stsclient := assumeRoler(sess)
  1422. if iamAuth.ExternalID != "" {
  1423. var setExternalID = func(p *stscreds.AssumeRoleProvider) {
  1424. p.ExternalID = aws.String(iamAuth.ExternalID)
  1425. }
  1426. sess.Config.WithCredentials(stscreds.NewCredentialsWithClient(stsclient, iamAuth.AWSIAMRole, setExternalID))
  1427. } else {
  1428. sess.Config.WithCredentials(stscreds.NewCredentialsWithClient(stsclient, iamAuth.AWSIAMRole))
  1429. }
  1430. }
  1431. getCreds, err := sess.Config.Credentials.Get()
  1432. if err != nil {
  1433. return err
  1434. }
  1435. // Set environment variables. These would be fetched by Login
  1436. os.Setenv("AWS_ACCESS_KEY_ID", getCreds.AccessKeyID)
  1437. os.Setenv("AWS_SECRET_ACCESS_KEY", getCreds.SecretAccessKey)
  1438. os.Setenv("AWS_SESSION_TOKEN", getCreds.SessionToken)
  1439. var awsAuthClient *authaws.AWSAuth
  1440. if iamAuth.VaultAWSIAMServerID != "" {
  1441. awsAuthClient, err = authaws.NewAWSAuth(authaws.WithRegion(regionAWS), authaws.WithIAMAuth(), authaws.WithRole(iamAuth.Role), authaws.WithMountPath(awsAuthMountPath), authaws.WithIAMServerIDHeader(iamAuth.VaultAWSIAMServerID))
  1442. if err != nil {
  1443. return err
  1444. }
  1445. } else {
  1446. awsAuthClient, err = authaws.NewAWSAuth(authaws.WithRegion(regionAWS), authaws.WithIAMAuth(), authaws.WithRole(iamAuth.Role), authaws.WithMountPath(awsAuthMountPath))
  1447. if err != nil {
  1448. return err
  1449. }
  1450. }
  1451. _, err = v.auth.Login(ctx, awsAuthClient)
  1452. metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLogin, err)
  1453. if err != nil {
  1454. return err
  1455. }
  1456. return nil
  1457. }
  1458. func init() {
  1459. var vaultTokenCacheSize int
  1460. fs := pflag.NewFlagSet("vault", pflag.ExitOnError)
  1461. fs.BoolVar(&enableCache, "experimental-enable-vault-token-cache", false, "Enable experimental Vault token cache. External secrets will reuse the Vault token without creating a new one on each request.")
  1462. // max. 265k vault leases with 30bytes each ~= 7MB
  1463. fs.IntVar(&vaultTokenCacheSize, "experimental-vault-token-cache-size", 2<<17, "Maximum size of Vault token cache. When more tokens than Only used if --experimental-enable-vault-token-cache is set.")
  1464. lateInit := func() {
  1465. logger.Info("initializing vault cache", "size", vaultTokenCacheSize)
  1466. clientCache = cache.Must(vaultTokenCacheSize, func(client util.Client) {
  1467. err := revokeTokenIfValid(context.Background(), client)
  1468. if err != nil {
  1469. logger.Error(err, "unable to revoke cached token on eviction")
  1470. }
  1471. })
  1472. }
  1473. feature.Register(feature.Feature{
  1474. Flags: fs,
  1475. Initialize: lateInit,
  1476. })
  1477. esv1beta1.Register(&Connector{
  1478. NewVaultClient: NewVaultClient,
  1479. }, &esv1beta1.SecretStoreProvider{
  1480. Vault: &esv1beta1.VaultProvider{},
  1481. })
  1482. }