keyvault.go 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058
  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 keyvault
  13. import (
  14. "context"
  15. "crypto/x509"
  16. b64 "encoding/base64"
  17. "encoding/json"
  18. "encoding/pem"
  19. "errors"
  20. "fmt"
  21. "os"
  22. "path"
  23. "regexp"
  24. "strings"
  25. "github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
  26. "github.com/Azure/go-autorest/autorest"
  27. "github.com/Azure/go-autorest/autorest/adal"
  28. "github.com/Azure/go-autorest/autorest/azure"
  29. kvauth "github.com/Azure/go-autorest/autorest/azure/auth"
  30. "github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
  31. "github.com/lestrrat-go/jwx/v2/jwk"
  32. "github.com/tidwall/gjson"
  33. "golang.org/x/crypto/pkcs12"
  34. "golang.org/x/crypto/sha3"
  35. authv1 "k8s.io/api/authentication/v1"
  36. corev1 "k8s.io/api/core/v1"
  37. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  38. "k8s.io/apimachinery/pkg/types"
  39. "k8s.io/client-go/kubernetes"
  40. kcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
  41. pointer "k8s.io/utils/ptr"
  42. "sigs.k8s.io/controller-runtime/pkg/client"
  43. ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
  44. "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
  45. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  46. "github.com/external-secrets/external-secrets/pkg/constants"
  47. "github.com/external-secrets/external-secrets/pkg/metrics"
  48. "github.com/external-secrets/external-secrets/pkg/utils"
  49. "github.com/external-secrets/external-secrets/pkg/utils/resolvers"
  50. )
  51. const (
  52. defaultObjType = "secret"
  53. objectTypeCert = "cert"
  54. objectTypeKey = "key"
  55. AzureDefaultAudience = "api://AzureADTokenExchange"
  56. AnnotationClientID = "azure.workload.identity/client-id"
  57. AnnotationTenantID = "azure.workload.identity/tenant-id"
  58. managerLabel = "external-secrets"
  59. errUnexpectedStoreSpec = "unexpected store spec"
  60. errMissingAuthType = "cannot initialize Azure Client: no valid authType was specified"
  61. errPropNotExist = "property %s does not exist in key %s"
  62. errTagNotExist = "tag %s does not exist"
  63. errUnknownObjectType = "unknown Azure Keyvault object Type for %s"
  64. errUnmarshalJSONData = "error unmarshalling json data: %w"
  65. errDataFromCert = "cannot get use dataFrom to get certificate secret"
  66. errDataFromKey = "cannot get use dataFrom to get key secret"
  67. errMissingTenant = "missing tenantID in store config"
  68. errMissingSecretRef = "missing secretRef in provider config"
  69. errMissingClientIDSecret = "missing accessKeyID/secretAccessKey in store config"
  70. errFindSecret = "could not find secret %s/%s: %w"
  71. errFindDataKey = "no data for %q in secret '%s/%s'"
  72. errInvalidStore = "invalid store"
  73. errInvalidStoreSpec = "invalid store spec"
  74. errInvalidStoreProv = "invalid store provider"
  75. errInvalidAzureProv = "invalid azure keyvault provider"
  76. errInvalidSecRefClientID = "invalid AuthSecretRef.ClientID: %w"
  77. errInvalidSecRefClientSecret = "invalid AuthSecretRef.ClientSecret: %w"
  78. errInvalidSARef = "invalid ServiceAccountRef: %w"
  79. errMissingWorkloadEnvVars = "missing environment variables. AZURE_CLIENT_ID, AZURE_TENANT_ID and AZURE_FEDERATED_TOKEN_FILE must be set"
  80. errReadTokenFile = "unable to read token file %s: %w"
  81. errMissingSAAnnotation = "missing service account annotation: %s"
  82. )
  83. // https://github.com/external-secrets/external-secrets/issues/644
  84. var _ esv1beta1.SecretsClient = &Azure{}
  85. var _ esv1beta1.Provider = &Azure{}
  86. // interface to keyvault.BaseClient.
  87. type SecretClient interface {
  88. GetKey(ctx context.Context, vaultBaseURL string, keyName string, keyVersion string) (result keyvault.KeyBundle, err error)
  89. GetSecret(ctx context.Context, vaultBaseURL string, secretName string, secretVersion string) (result keyvault.SecretBundle, err error)
  90. GetSecretsComplete(ctx context.Context, vaultBaseURL string, maxresults *int32) (result keyvault.SecretListResultIterator, err error)
  91. GetCertificate(ctx context.Context, vaultBaseURL string, certificateName string, certificateVersion string) (result keyvault.CertificateBundle, err error)
  92. SetSecret(ctx context.Context, vaultBaseURL string, secretName string, parameters keyvault.SecretSetParameters) (result keyvault.SecretBundle, err error)
  93. ImportKey(ctx context.Context, vaultBaseURL string, keyName string, parameters keyvault.KeyImportParameters) (result keyvault.KeyBundle, err error)
  94. ImportCertificate(ctx context.Context, vaultBaseURL string, certificateName string, parameters keyvault.CertificateImportParameters) (result keyvault.CertificateBundle, err error)
  95. DeleteCertificate(ctx context.Context, vaultBaseURL string, certificateName string) (result keyvault.DeletedCertificateBundle, err error)
  96. DeleteKey(ctx context.Context, vaultBaseURL string, keyName string) (result keyvault.DeletedKeyBundle, err error)
  97. DeleteSecret(ctx context.Context, vaultBaseURL string, secretName string) (result keyvault.DeletedSecretBundle, err error)
  98. }
  99. type Azure struct {
  100. crClient client.Client
  101. kubeClient kcorev1.CoreV1Interface
  102. store esv1beta1.GenericStore
  103. provider *esv1beta1.AzureKVProvider
  104. baseClient SecretClient
  105. namespace string
  106. }
  107. func init() {
  108. esv1beta1.Register(&Azure{}, &esv1beta1.SecretStoreProvider{
  109. AzureKV: &esv1beta1.AzureKVProvider{},
  110. })
  111. }
  112. // Capabilities return the provider supported capabilities (ReadOnly, WriteOnly, ReadWrite).
  113. func (a *Azure) Capabilities() esv1beta1.SecretStoreCapabilities {
  114. return esv1beta1.SecretStoreReadWrite
  115. }
  116. // NewClient constructs a new secrets client based on the provided store.
  117. func (a *Azure) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
  118. return newClient(ctx, store, kube, namespace)
  119. }
  120. func newClient(ctx context.Context, store esv1beta1.GenericStore, kube client.Client, namespace string) (esv1beta1.SecretsClient, error) {
  121. provider, err := getProvider(store)
  122. if err != nil {
  123. return nil, err
  124. }
  125. cfg, err := ctrlcfg.GetConfig()
  126. if err != nil {
  127. return nil, err
  128. }
  129. kubeClient, err := kubernetes.NewForConfig(cfg)
  130. if err != nil {
  131. return nil, err
  132. }
  133. az := &Azure{
  134. crClient: kube,
  135. kubeClient: kubeClient.CoreV1(),
  136. store: store,
  137. namespace: namespace,
  138. provider: provider,
  139. }
  140. // allow SecretStore controller validation to pass
  141. // when using referent namespace.
  142. if store.GetKind() == esv1beta1.ClusterSecretStoreKind &&
  143. namespace == "" &&
  144. isReferentSpec(provider) {
  145. return az, nil
  146. }
  147. var authorizer autorest.Authorizer
  148. switch *provider.AuthType {
  149. case esv1beta1.AzureManagedIdentity:
  150. authorizer, err = az.authorizerForManagedIdentity()
  151. case esv1beta1.AzureServicePrincipal:
  152. authorizer, err = az.authorizerForServicePrincipal(ctx)
  153. case esv1beta1.AzureWorkloadIdentity:
  154. authorizer, err = az.authorizerForWorkloadIdentity(ctx, NewTokenProvider)
  155. default:
  156. err = fmt.Errorf(errMissingAuthType)
  157. }
  158. cl := keyvault.New()
  159. cl.Authorizer = authorizer
  160. az.baseClient = &cl
  161. return az, err
  162. }
  163. func getProvider(store esv1beta1.GenericStore) (*esv1beta1.AzureKVProvider, error) {
  164. spc := store.GetSpec()
  165. if spc == nil || spc.Provider.AzureKV == nil {
  166. return nil, errors.New(errUnexpectedStoreSpec)
  167. }
  168. return spc.Provider.AzureKV, nil
  169. }
  170. func (a *Azure) ValidateStore(store esv1beta1.GenericStore) (admission.Warnings, error) {
  171. if store == nil {
  172. return nil, fmt.Errorf(errInvalidStore)
  173. }
  174. spc := store.GetSpec()
  175. if spc == nil {
  176. return nil, fmt.Errorf(errInvalidStoreSpec)
  177. }
  178. if spc.Provider == nil {
  179. return nil, fmt.Errorf(errInvalidStoreProv)
  180. }
  181. p := spc.Provider.AzureKV
  182. if p == nil {
  183. return nil, fmt.Errorf(errInvalidAzureProv)
  184. }
  185. if p.AuthSecretRef != nil {
  186. if p.AuthSecretRef.ClientID != nil {
  187. if err := utils.ValidateReferentSecretSelector(store, *p.AuthSecretRef.ClientID); err != nil {
  188. return nil, fmt.Errorf(errInvalidSecRefClientID, err)
  189. }
  190. }
  191. if p.AuthSecretRef.ClientSecret != nil {
  192. if err := utils.ValidateReferentSecretSelector(store, *p.AuthSecretRef.ClientSecret); err != nil {
  193. return nil, fmt.Errorf(errInvalidSecRefClientSecret, err)
  194. }
  195. }
  196. }
  197. if p.ServiceAccountRef != nil {
  198. if err := utils.ValidateReferentServiceAccountSelector(store, *p.ServiceAccountRef); err != nil {
  199. return nil, fmt.Errorf(errInvalidSARef, err)
  200. }
  201. }
  202. return nil, nil
  203. }
  204. func canDelete(tags map[string]*string, err error) (bool, error) {
  205. aerr := &autorest.DetailedError{}
  206. conv := errors.As(err, aerr)
  207. if err != nil && !conv {
  208. return false, fmt.Errorf("could not parse error: %w", err)
  209. }
  210. if conv && aerr.StatusCode != 404 { // Secret is already deleted, nothing to do.
  211. return false, fmt.Errorf("unexpected api error: %w", err)
  212. }
  213. if aerr.StatusCode == 404 {
  214. return false, nil
  215. }
  216. manager, ok := tags["managed-by"]
  217. if !ok || manager == nil || *manager != managerLabel {
  218. return false, fmt.Errorf("not managed by external-secrets")
  219. }
  220. return true, nil
  221. }
  222. func (a *Azure) deleteKeyVaultKey(ctx context.Context, keyName string) error {
  223. value, err := a.baseClient.GetKey(ctx, *a.provider.VaultURL, keyName, "")
  224. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetKey, err)
  225. ok, err := canDelete(value.Tags, err)
  226. if err != nil {
  227. return fmt.Errorf("error getting key %v: %w", keyName, err)
  228. }
  229. if ok {
  230. _, err = a.baseClient.DeleteKey(ctx, *a.provider.VaultURL, keyName)
  231. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVDeleteKey, err)
  232. if err != nil {
  233. return fmt.Errorf("error deleting key %v: %w", keyName, err)
  234. }
  235. }
  236. return nil
  237. }
  238. func (a *Azure) deleteKeyVaultSecret(ctx context.Context, secretName string) error {
  239. value, err := a.baseClient.GetSecret(ctx, *a.provider.VaultURL, secretName, "")
  240. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetSecret, err)
  241. ok, err := canDelete(value.Tags, err)
  242. if err != nil {
  243. return fmt.Errorf("error getting secret %v: %w", secretName, err)
  244. }
  245. if ok {
  246. _, err = a.baseClient.DeleteSecret(ctx, *a.provider.VaultURL, secretName)
  247. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVDeleteSecret, err)
  248. if err != nil {
  249. return fmt.Errorf("error deleting secret %v: %w", secretName, err)
  250. }
  251. }
  252. return nil
  253. }
  254. func (a *Azure) deleteKeyVaultCertificate(ctx context.Context, certName string) error {
  255. value, err := a.baseClient.GetCertificate(ctx, *a.provider.VaultURL, certName, "")
  256. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetCertificate, err)
  257. ok, err := canDelete(value.Tags, err)
  258. if err != nil {
  259. return fmt.Errorf("error getting certificate %v: %w", certName, err)
  260. }
  261. if ok {
  262. _, err = a.baseClient.DeleteCertificate(ctx, *a.provider.VaultURL, certName)
  263. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVDeleteCertificate, err)
  264. if err != nil {
  265. return fmt.Errorf("error deleting certificate %v: %w", certName, err)
  266. }
  267. }
  268. return nil
  269. }
  270. func (a *Azure) DeleteSecret(ctx context.Context, remoteRef esv1beta1.PushSecretRemoteRef) error {
  271. objectType, secretName := getObjType(esv1beta1.ExternalSecretDataRemoteRef{Key: remoteRef.GetRemoteKey()})
  272. switch objectType {
  273. case defaultObjType:
  274. return a.deleteKeyVaultSecret(ctx, secretName)
  275. case objectTypeCert:
  276. return a.deleteKeyVaultCertificate(ctx, secretName)
  277. case objectTypeKey:
  278. return a.deleteKeyVaultKey(ctx, secretName)
  279. default:
  280. return fmt.Errorf("secret type '%v' is not supported", objectType)
  281. }
  282. }
  283. func (a *Azure) SecretExists(ctx context.Context, remoteRef esv1beta1.PushSecretRemoteRef) (bool, error) {
  284. objectType, secretName := getObjType(esv1beta1.ExternalSecretDataRemoteRef{Key: remoteRef.GetRemoteKey()})
  285. var err error
  286. switch objectType {
  287. case defaultObjType:
  288. _, err = a.baseClient.GetSecret(ctx, *a.provider.VaultURL, secretName, "")
  289. case objectTypeCert:
  290. _, err = a.baseClient.GetCertificate(ctx, *a.provider.VaultURL, secretName, "")
  291. case objectTypeKey:
  292. _, err = a.baseClient.GetKey(ctx, *a.provider.VaultURL, secretName, "")
  293. default:
  294. errMsg := fmt.Sprintf("secret type '%v' is not supported", objectType)
  295. return false, errors.New(errMsg)
  296. }
  297. err = parseError(err)
  298. if err != nil {
  299. var noSecretErr esv1beta1.NoSecretError
  300. if errors.As(err, &noSecretErr) {
  301. return false, nil
  302. }
  303. return false, err
  304. }
  305. return true, nil
  306. }
  307. func getCertificateFromValue(value []byte) (*x509.Certificate, error) {
  308. // 1st: try decode pkcs12
  309. _, localCert, err := pkcs12.Decode(value, "")
  310. if err == nil {
  311. return localCert, nil
  312. }
  313. // 2nd: try DER
  314. localCert, err = x509.ParseCertificate(value)
  315. if err == nil {
  316. return localCert, nil
  317. }
  318. // 3nd: parse PEM blocks
  319. for {
  320. block, rest := pem.Decode(value)
  321. value = rest
  322. if block == nil {
  323. break
  324. }
  325. cert, err := x509.ParseCertificate(block.Bytes)
  326. if err == nil {
  327. return cert, nil
  328. }
  329. }
  330. return nil, fmt.Errorf("could not parse certificate value as PKCS#12, DER or PEM")
  331. }
  332. func getKeyFromValue(value []byte) (interface{}, error) {
  333. val := value
  334. pemBlock, _ := pem.Decode(value)
  335. // if a private key regular expression doesn't match, we should consider this key to be symmetric
  336. if pemBlock == nil {
  337. return val, nil
  338. }
  339. val = pemBlock.Bytes
  340. switch pemBlock.Type {
  341. case "PRIVATE KEY":
  342. return x509.ParsePKCS8PrivateKey(val)
  343. case "RSA PRIVATE KEY":
  344. return x509.ParsePKCS1PrivateKey(val)
  345. case "EC PRIVATE KEY":
  346. return x509.ParseECPrivateKey(val)
  347. default:
  348. return nil, fmt.Errorf("key type %v is not supported", pemBlock.Type)
  349. }
  350. }
  351. func canCreate(tags map[string]*string, err error) (bool, error) {
  352. aerr := &autorest.DetailedError{}
  353. conv := errors.As(err, aerr)
  354. if err != nil && !conv {
  355. return false, fmt.Errorf("could not parse error: %w", err)
  356. }
  357. if conv && aerr.StatusCode != 404 {
  358. return false, fmt.Errorf("unexpected api error: %w", err)
  359. }
  360. if err == nil {
  361. manager, ok := tags["managed-by"]
  362. if !ok || manager == nil || *manager != managerLabel {
  363. return false, fmt.Errorf("not managed by external-secrets")
  364. }
  365. }
  366. return true, nil
  367. }
  368. func (a *Azure) setKeyVaultSecret(ctx context.Context, secretName string, value []byte) error {
  369. secret, err := a.baseClient.GetSecret(ctx, *a.provider.VaultURL, secretName, "")
  370. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetSecret, err)
  371. ok, err := canCreate(secret.Tags, err)
  372. if err != nil {
  373. return fmt.Errorf("cannot get secret %v: %w", secretName, err)
  374. }
  375. if !ok {
  376. return nil
  377. }
  378. val := string(value)
  379. if secret.Value != nil && val == *secret.Value {
  380. return nil
  381. }
  382. secretParams := keyvault.SecretSetParameters{
  383. Value: &val,
  384. Tags: map[string]*string{
  385. "managed-by": pointer.To(managerLabel),
  386. },
  387. SecretAttributes: &keyvault.SecretAttributes{
  388. Enabled: pointer.To(true),
  389. },
  390. }
  391. _, err = a.baseClient.SetSecret(ctx, *a.provider.VaultURL, secretName, secretParams)
  392. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetSecret, err)
  393. if err != nil {
  394. return fmt.Errorf("could not set secret %v: %w", secretName, err)
  395. }
  396. return nil
  397. }
  398. func (a *Azure) setKeyVaultCertificate(ctx context.Context, secretName string, value []byte) error {
  399. val := b64.StdEncoding.EncodeToString(value)
  400. localCert, err := getCertificateFromValue(value)
  401. if err != nil {
  402. return fmt.Errorf("value from secret is not a valid certificate: %w", err)
  403. }
  404. cert, err := a.baseClient.GetCertificate(ctx, *a.provider.VaultURL, secretName, "")
  405. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetCertificate, err)
  406. ok, err := canCreate(cert.Tags, err)
  407. if err != nil {
  408. return fmt.Errorf("cannot get certificate %v: %w", secretName, err)
  409. }
  410. if !ok {
  411. return nil
  412. }
  413. b512 := sha3.Sum512(localCert.Raw)
  414. if cert.Cer != nil && b512 == sha3.Sum512(*cert.Cer) {
  415. return nil
  416. }
  417. params := keyvault.CertificateImportParameters{
  418. Base64EncodedCertificate: &val,
  419. Tags: map[string]*string{
  420. "managed-by": pointer.To(managerLabel),
  421. },
  422. }
  423. _, err = a.baseClient.ImportCertificate(ctx, *a.provider.VaultURL, secretName, params)
  424. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVImportCertificate, err)
  425. if err != nil {
  426. return fmt.Errorf("could not import certificate %v: %w", secretName, err)
  427. }
  428. return nil
  429. }
  430. func equalKeys(newKey, oldKey keyvault.JSONWebKey) bool {
  431. // checks for everything except KeyID and KeyOps
  432. rsaCheck := newKey.E != nil && oldKey.E != nil && *newKey.E == *oldKey.E &&
  433. newKey.N != nil && oldKey.N != nil && *newKey.N == *oldKey.N
  434. symmetricCheck := newKey.Crv == oldKey.Crv &&
  435. newKey.T != nil && oldKey.T != nil && *newKey.T == *oldKey.T &&
  436. newKey.X != nil && oldKey.X != nil && *newKey.X == *oldKey.X &&
  437. newKey.Y != nil && oldKey.Y != nil && *newKey.Y == *oldKey.Y
  438. return newKey.Kty == oldKey.Kty && (rsaCheck || symmetricCheck)
  439. }
  440. func (a *Azure) setKeyVaultKey(ctx context.Context, secretName string, value []byte) error {
  441. key, err := getKeyFromValue(value)
  442. if err != nil {
  443. return fmt.Errorf("could not load private key %v: %w", secretName, err)
  444. }
  445. jwKey, err := jwk.FromRaw(key)
  446. if err != nil {
  447. return fmt.Errorf("failed to generate a JWK from secret %v content: %w", secretName, err)
  448. }
  449. buf, err := json.Marshal(jwKey)
  450. if err != nil {
  451. return fmt.Errorf("error parsing key: %w", err)
  452. }
  453. azkey := keyvault.JSONWebKey{}
  454. err = json.Unmarshal(buf, &azkey)
  455. if err != nil {
  456. return fmt.Errorf("error unmarshalling key: %w", err)
  457. }
  458. keyFromVault, err := a.baseClient.GetKey(ctx, *a.provider.VaultURL, secretName, "")
  459. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetKey, err)
  460. ok, err := canCreate(keyFromVault.Tags, err)
  461. if err != nil {
  462. return fmt.Errorf("cannot get key %v: %w", secretName, err)
  463. }
  464. if !ok {
  465. return nil
  466. }
  467. if keyFromVault.Key != nil && equalKeys(azkey, *keyFromVault.Key) {
  468. return nil
  469. }
  470. params := keyvault.KeyImportParameters{
  471. Key: &azkey,
  472. KeyAttributes: &keyvault.KeyAttributes{},
  473. Tags: map[string]*string{
  474. "managed-by": pointer.To(managerLabel),
  475. },
  476. }
  477. _, err = a.baseClient.ImportKey(ctx, *a.provider.VaultURL, secretName, params)
  478. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVImportKey, err)
  479. if err != nil {
  480. return fmt.Errorf("could not import key %v: %w", secretName, err)
  481. }
  482. return nil
  483. }
  484. // PushSecret stores secrets into a Key vault instance.
  485. func (a *Azure) PushSecret(ctx context.Context, secret *corev1.Secret, data esv1beta1.PushSecretData) error {
  486. if data.GetSecretKey() == "" {
  487. return fmt.Errorf("pushing the whole secret is not yet implemented")
  488. }
  489. objectType, secretName := getObjType(esv1beta1.ExternalSecretDataRemoteRef{Key: data.GetRemoteKey()})
  490. value := secret.Data[data.GetSecretKey()]
  491. switch objectType {
  492. case defaultObjType:
  493. return a.setKeyVaultSecret(ctx, secretName, value)
  494. case objectTypeCert:
  495. return a.setKeyVaultCertificate(ctx, secretName, value)
  496. case objectTypeKey:
  497. return a.setKeyVaultKey(ctx, secretName, value)
  498. default:
  499. return fmt.Errorf("secret type %v not supported", objectType)
  500. }
  501. }
  502. // Implements store.Client.GetAllSecrets Interface.
  503. // Retrieves a map[string][]byte with the secret names as key and the secret itself as the calue.
  504. func (a *Azure) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
  505. basicClient := a.baseClient
  506. secretsMap := make(map[string][]byte)
  507. checkTags := len(ref.Tags) > 0
  508. checkName := ref.Name != nil && len(ref.Name.RegExp) > 0
  509. secretListIter, err := basicClient.GetSecretsComplete(ctx, *a.provider.VaultURL, nil)
  510. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetSecrets, err)
  511. err = parseError(err)
  512. if err != nil {
  513. return nil, err
  514. }
  515. for secretListIter.NotDone() {
  516. secret := secretListIter.Value()
  517. ok, secretName := isValidSecret(checkTags, checkName, ref, secret)
  518. if !ok {
  519. err = secretListIter.Next()
  520. if err != nil {
  521. return nil, err
  522. }
  523. continue
  524. }
  525. secretResp, err := basicClient.GetSecret(ctx, *a.provider.VaultURL, secretName, "")
  526. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetSecret, err)
  527. err = parseError(err)
  528. if err != nil {
  529. return nil, err
  530. }
  531. secretValue := *secretResp.Value
  532. secretsMap[secretName] = []byte(secretValue)
  533. err = secretListIter.Next()
  534. if err != nil {
  535. return nil, err
  536. }
  537. }
  538. return secretsMap, nil
  539. }
  540. // Retrieves a tag value if specified and all tags in JSON format if not.
  541. func getSecretTag(tags map[string]*string, property string) ([]byte, error) {
  542. if property == "" {
  543. secretTagsData := make(map[string]string)
  544. for k, v := range tags {
  545. secretTagsData[k] = *v
  546. }
  547. return json.Marshal(secretTagsData)
  548. }
  549. if val, exist := tags[property]; exist {
  550. return []byte(*val), nil
  551. }
  552. idx := strings.Index(property, ".")
  553. if idx < 0 {
  554. return nil, fmt.Errorf(errTagNotExist, property)
  555. }
  556. if idx > 0 {
  557. tagName := property[0:idx]
  558. if val, exist := tags[tagName]; exist {
  559. key := strings.Replace(property, tagName+".", "", 1)
  560. return getProperty(*val, key, property)
  561. }
  562. }
  563. return nil, fmt.Errorf(errTagNotExist, property)
  564. }
  565. // Retrieves a property value if specified and the secret value if not.
  566. func getProperty(secret, property, key string) ([]byte, error) {
  567. if property == "" {
  568. return []byte(secret), nil
  569. }
  570. res := gjson.Get(secret, property)
  571. if !res.Exists() {
  572. idx := strings.Index(property, ".")
  573. if idx < 0 {
  574. return nil, fmt.Errorf(errPropNotExist, property, key)
  575. }
  576. escaped := strings.ReplaceAll(property, ".", "\\.")
  577. jValue := gjson.Get(secret, escaped)
  578. if jValue.Exists() {
  579. return []byte(jValue.String()), nil
  580. }
  581. return nil, fmt.Errorf(errPropNotExist, property, key)
  582. }
  583. return []byte(res.String()), nil
  584. }
  585. func parseError(err error) error {
  586. aerr := autorest.DetailedError{}
  587. if errors.As(err, &aerr) && aerr.StatusCode == 404 {
  588. return esv1beta1.NoSecretError{}
  589. }
  590. return err
  591. }
  592. // Implements store.Client.GetSecret Interface.
  593. // Retrieves a secret/Key/Certificate/Tag with the secret name defined in ref.Name
  594. // The Object Type is defined as a prefix in the ref.Name , if no prefix is defined , we assume a secret is required.
  595. func (a *Azure) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
  596. objectType, secretName := getObjType(ref)
  597. switch objectType {
  598. case defaultObjType:
  599. // returns a SecretBundle with the secret value
  600. // https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault#SecretBundle
  601. secretResp, err := a.baseClient.GetSecret(ctx, *a.provider.VaultURL, secretName, ref.Version)
  602. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetSecret, err)
  603. err = parseError(err)
  604. if err != nil {
  605. return nil, err
  606. }
  607. if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
  608. return getSecretTag(secretResp.Tags, ref.Property)
  609. }
  610. return getProperty(*secretResp.Value, ref.Property, ref.Key)
  611. case objectTypeCert:
  612. // returns a CertBundle. We return CER contents of x509 certificate
  613. // see: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault#CertificateBundle
  614. certResp, err := a.baseClient.GetCertificate(ctx, *a.provider.VaultURL, secretName, ref.Version)
  615. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetCertificate, err)
  616. err = parseError(err)
  617. if err != nil {
  618. return nil, err
  619. }
  620. if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
  621. return getSecretTag(certResp.Tags, ref.Property)
  622. }
  623. return *certResp.Cer, nil
  624. case objectTypeKey:
  625. // returns a KeyBundle that contains a jwk
  626. // azure kv returns only public keys
  627. // see: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/services/keyvault/v7.0/keyvault#KeyBundle
  628. keyResp, err := a.baseClient.GetKey(ctx, *a.provider.VaultURL, secretName, ref.Version)
  629. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetKey, err)
  630. err = parseError(err)
  631. if err != nil {
  632. return nil, err
  633. }
  634. if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
  635. return getSecretTag(keyResp.Tags, ref.Property)
  636. }
  637. return json.Marshal(keyResp.Key)
  638. }
  639. return nil, fmt.Errorf(errUnknownObjectType, secretName)
  640. }
  641. // returns a SecretBundle with the tags values.
  642. func (a *Azure) getSecretTags(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string]*string, error) {
  643. _, secretName := getObjType(ref)
  644. secretResp, err := a.baseClient.GetSecret(ctx, *a.provider.VaultURL, secretName, ref.Version)
  645. metrics.ObserveAPICall(constants.ProviderAzureKV, constants.CallAzureKVGetSecret, err)
  646. err = parseError(err)
  647. if err != nil {
  648. return nil, err
  649. }
  650. secretTagsData := make(map[string]*string)
  651. for tagname, tagval := range secretResp.Tags {
  652. name := secretName + "_" + tagname
  653. kv := make(map[string]string)
  654. err = json.Unmarshal([]byte(*tagval), &kv)
  655. // if the tagvalue is not in JSON format then we added to secretTagsData we added as it is
  656. if err != nil {
  657. secretTagsData[name] = tagval
  658. } else {
  659. for k, v := range kv {
  660. value := v
  661. secretTagsData[name+"_"+k] = &value
  662. }
  663. }
  664. }
  665. return secretTagsData, nil
  666. }
  667. // Implements store.Client.GetSecretMap Interface.
  668. // New version of GetSecretMap.
  669. func (a *Azure) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
  670. objectType, secretName := getObjType(ref)
  671. switch objectType {
  672. case defaultObjType:
  673. data, err := a.GetSecret(ctx, ref)
  674. if err != nil {
  675. return nil, err
  676. }
  677. if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
  678. tags, _ := a.getSecretTags(ctx, ref)
  679. return getSecretMapProperties(tags, ref.Key, ref.Property), nil
  680. }
  681. return getSecretMapMap(data)
  682. case objectTypeCert:
  683. return nil, fmt.Errorf(errDataFromCert)
  684. case objectTypeKey:
  685. return nil, fmt.Errorf(errDataFromKey)
  686. }
  687. return nil, fmt.Errorf(errUnknownObjectType, secretName)
  688. }
  689. func getSecretMapMap(data []byte) (map[string][]byte, error) {
  690. kv := make(map[string]json.RawMessage)
  691. err := json.Unmarshal(data, &kv)
  692. if err != nil {
  693. return nil, fmt.Errorf(errUnmarshalJSONData, err)
  694. }
  695. secretData := make(map[string][]byte)
  696. for k, v := range kv {
  697. var strVal string
  698. err = json.Unmarshal(v, &strVal)
  699. if err == nil {
  700. secretData[k] = []byte(strVal)
  701. } else {
  702. secretData[k] = v
  703. }
  704. }
  705. return secretData, nil
  706. }
  707. func getSecretMapProperties(tags map[string]*string, key, property string) map[string][]byte {
  708. tagByteArray := make(map[string][]byte)
  709. if property != "" {
  710. keyPropertyName := key + "_" + property
  711. singleTag, _ := getSecretTag(tags, keyPropertyName)
  712. tagByteArray[keyPropertyName] = singleTag
  713. return tagByteArray
  714. }
  715. for k, v := range tags {
  716. tagByteArray[k] = []byte(*v)
  717. }
  718. return tagByteArray
  719. }
  720. func (a *Azure) authorizerForWorkloadIdentity(ctx context.Context, tokenProvider tokenProviderFunc) (autorest.Authorizer, error) {
  721. aadEndpoint := AadEndpointForType(a.provider.EnvironmentType)
  722. kvResource := kvResourceForProviderConfig(a.provider.EnvironmentType)
  723. // if no serviceAccountRef was provided
  724. // we expect certain env vars to be present.
  725. // They are set by the azure workload identity webhook.
  726. if a.provider.ServiceAccountRef == nil {
  727. clientID := os.Getenv("AZURE_CLIENT_ID")
  728. tenantID := os.Getenv("AZURE_TENANT_ID")
  729. tokenFilePath := os.Getenv("AZURE_FEDERATED_TOKEN_FILE")
  730. if clientID == "" || tenantID == "" || tokenFilePath == "" {
  731. return nil, errors.New(errMissingWorkloadEnvVars)
  732. }
  733. token, err := os.ReadFile(tokenFilePath)
  734. if err != nil {
  735. return nil, fmt.Errorf(errReadTokenFile, tokenFilePath, err)
  736. }
  737. tp, err := tokenProvider(ctx, string(token), clientID, tenantID, aadEndpoint, kvResource)
  738. if err != nil {
  739. return nil, err
  740. }
  741. return autorest.NewBearerAuthorizer(tp), nil
  742. }
  743. ns := a.namespace
  744. if a.store.GetKind() == esv1beta1.ClusterSecretStoreKind && a.provider.ServiceAccountRef.Namespace != nil {
  745. ns = *a.provider.ServiceAccountRef.Namespace
  746. }
  747. var sa corev1.ServiceAccount
  748. err := a.crClient.Get(ctx, types.NamespacedName{
  749. Name: a.provider.ServiceAccountRef.Name,
  750. Namespace: ns,
  751. }, &sa)
  752. if err != nil {
  753. return nil, err
  754. }
  755. clientID, ok := sa.ObjectMeta.Annotations[AnnotationClientID]
  756. if !ok {
  757. return nil, fmt.Errorf(errMissingSAAnnotation, AnnotationClientID)
  758. }
  759. tenantID, ok := sa.ObjectMeta.Annotations[AnnotationTenantID]
  760. if !ok {
  761. return nil, fmt.Errorf(errMissingSAAnnotation, AnnotationTenantID)
  762. }
  763. audiences := []string{AzureDefaultAudience}
  764. if len(a.provider.ServiceAccountRef.Audiences) > 0 {
  765. audiences = append(audiences, a.provider.ServiceAccountRef.Audiences...)
  766. }
  767. token, err := FetchSAToken(ctx, ns, a.provider.ServiceAccountRef.Name, audiences, a.kubeClient)
  768. if err != nil {
  769. return nil, err
  770. }
  771. tp, err := tokenProvider(ctx, token, clientID, tenantID, aadEndpoint, kvResource)
  772. if err != nil {
  773. return nil, err
  774. }
  775. return autorest.NewBearerAuthorizer(tp), nil
  776. }
  777. func FetchSAToken(ctx context.Context, ns, name string, audiences []string, kubeClient kcorev1.CoreV1Interface) (string, error) {
  778. token, err := kubeClient.ServiceAccounts(ns).CreateToken(ctx, name, &authv1.TokenRequest{
  779. Spec: authv1.TokenRequestSpec{
  780. Audiences: audiences,
  781. },
  782. }, metav1.CreateOptions{})
  783. if err != nil {
  784. return "", err
  785. }
  786. return token.Status.Token, nil
  787. }
  788. // tokenProvider satisfies the adal.OAuthTokenProvider interface.
  789. type tokenProvider struct {
  790. accessToken string
  791. }
  792. type tokenProviderFunc func(ctx context.Context, token, clientID, tenantID, aadEndpoint, kvResource string) (adal.OAuthTokenProvider, error)
  793. func NewTokenProvider(ctx context.Context, token, clientID, tenantID, aadEndpoint, kvResource string) (adal.OAuthTokenProvider, error) {
  794. // exchange token with Azure AccessToken
  795. cred := confidential.NewCredFromAssertionCallback(func(ctx context.Context, aro confidential.AssertionRequestOptions) (string, error) {
  796. return token, nil
  797. })
  798. cClient, err := confidential.New(fmt.Sprintf("%s%s/oauth2/token", aadEndpoint, tenantID), clientID, cred)
  799. if err != nil {
  800. return nil, err
  801. }
  802. scope := kvResource
  803. // .default needs to be added to the scope
  804. if !strings.Contains(kvResource, ".default") {
  805. scope = fmt.Sprintf("%s/.default", kvResource)
  806. }
  807. authRes, err := cClient.AcquireTokenByCredential(ctx, []string{
  808. scope,
  809. })
  810. if err != nil {
  811. return nil, err
  812. }
  813. return &tokenProvider{
  814. accessToken: authRes.AccessToken,
  815. }, nil
  816. }
  817. func (t *tokenProvider) OAuthToken() string {
  818. return t.accessToken
  819. }
  820. func (a *Azure) authorizerForManagedIdentity() (autorest.Authorizer, error) {
  821. msiConfig := kvauth.NewMSIConfig()
  822. msiConfig.Resource = kvResourceForProviderConfig(a.provider.EnvironmentType)
  823. if a.provider.IdentityID != nil {
  824. msiConfig.ClientID = *a.provider.IdentityID
  825. }
  826. return msiConfig.Authorizer()
  827. }
  828. func (a *Azure) authorizerForServicePrincipal(ctx context.Context) (autorest.Authorizer, error) {
  829. if a.provider.TenantID == nil {
  830. return nil, fmt.Errorf(errMissingTenant)
  831. }
  832. if a.provider.AuthSecretRef == nil {
  833. return nil, fmt.Errorf(errMissingSecretRef)
  834. }
  835. if a.provider.AuthSecretRef.ClientID == nil || a.provider.AuthSecretRef.ClientSecret == nil {
  836. return nil, fmt.Errorf(errMissingClientIDSecret)
  837. }
  838. clientID, err := resolvers.SecretKeyRef(
  839. ctx,
  840. a.crClient,
  841. a.store.GetKind(),
  842. a.namespace, a.provider.AuthSecretRef.ClientID)
  843. if err != nil {
  844. return nil, err
  845. }
  846. clientSecret, err := resolvers.SecretKeyRef(
  847. ctx,
  848. a.crClient,
  849. a.store.GetKind(),
  850. a.namespace, a.provider.AuthSecretRef.ClientSecret)
  851. if err != nil {
  852. return nil, err
  853. }
  854. clientCredentialsConfig := kvauth.NewClientCredentialsConfig(clientID, clientSecret, *a.provider.TenantID)
  855. clientCredentialsConfig.Resource = kvResourceForProviderConfig(a.provider.EnvironmentType)
  856. clientCredentialsConfig.AADEndpoint = AadEndpointForType(a.provider.EnvironmentType)
  857. return clientCredentialsConfig.Authorizer()
  858. }
  859. func (a *Azure) Close(_ context.Context) error {
  860. return nil
  861. }
  862. func (a *Azure) Validate() (esv1beta1.ValidationResult, error) {
  863. if a.store.GetKind() == esv1beta1.ClusterSecretStoreKind && isReferentSpec(a.provider) {
  864. return esv1beta1.ValidationResultUnknown, nil
  865. }
  866. return esv1beta1.ValidationResultReady, nil
  867. }
  868. func isReferentSpec(prov *esv1beta1.AzureKVProvider) bool {
  869. if prov.AuthSecretRef != nil &&
  870. ((prov.AuthSecretRef.ClientID != nil &&
  871. prov.AuthSecretRef.ClientID.Namespace == nil) ||
  872. (prov.AuthSecretRef.ClientSecret != nil &&
  873. prov.AuthSecretRef.ClientSecret.Namespace == nil)) {
  874. return true
  875. }
  876. if prov.ServiceAccountRef != nil &&
  877. prov.ServiceAccountRef.Namespace == nil {
  878. return true
  879. }
  880. return false
  881. }
  882. func AadEndpointForType(t esv1beta1.AzureEnvironmentType) string {
  883. switch t {
  884. case esv1beta1.AzureEnvironmentPublicCloud:
  885. return azure.PublicCloud.ActiveDirectoryEndpoint
  886. case esv1beta1.AzureEnvironmentChinaCloud:
  887. return azure.ChinaCloud.ActiveDirectoryEndpoint
  888. case esv1beta1.AzureEnvironmentUSGovernmentCloud:
  889. return azure.USGovernmentCloud.ActiveDirectoryEndpoint
  890. case esv1beta1.AzureEnvironmentGermanCloud:
  891. return azure.GermanCloud.ActiveDirectoryEndpoint
  892. default:
  893. return azure.PublicCloud.ActiveDirectoryEndpoint
  894. }
  895. }
  896. func ServiceManagementEndpointForType(t esv1beta1.AzureEnvironmentType) string {
  897. switch t {
  898. case esv1beta1.AzureEnvironmentPublicCloud:
  899. return azure.PublicCloud.ServiceManagementEndpoint
  900. case esv1beta1.AzureEnvironmentChinaCloud:
  901. return azure.ChinaCloud.ServiceManagementEndpoint
  902. case esv1beta1.AzureEnvironmentUSGovernmentCloud:
  903. return azure.USGovernmentCloud.ServiceManagementEndpoint
  904. case esv1beta1.AzureEnvironmentGermanCloud:
  905. return azure.GermanCloud.ServiceManagementEndpoint
  906. default:
  907. return azure.PublicCloud.ServiceManagementEndpoint
  908. }
  909. }
  910. func kvResourceForProviderConfig(t esv1beta1.AzureEnvironmentType) string {
  911. var res string
  912. switch t {
  913. case esv1beta1.AzureEnvironmentPublicCloud:
  914. res = azure.PublicCloud.KeyVaultEndpoint
  915. case esv1beta1.AzureEnvironmentChinaCloud:
  916. res = azure.ChinaCloud.KeyVaultEndpoint
  917. case esv1beta1.AzureEnvironmentUSGovernmentCloud:
  918. res = azure.USGovernmentCloud.KeyVaultEndpoint
  919. case esv1beta1.AzureEnvironmentGermanCloud:
  920. res = azure.GermanCloud.KeyVaultEndpoint
  921. default:
  922. res = azure.PublicCloud.KeyVaultEndpoint
  923. }
  924. return strings.TrimSuffix(res, "/")
  925. }
  926. func getObjType(ref esv1beta1.ExternalSecretDataRemoteRef) (string, string) {
  927. objectType := defaultObjType
  928. secretName := ref.Key
  929. nameSplitted := strings.Split(secretName, "/")
  930. if len(nameSplitted) > 1 {
  931. objectType = nameSplitted[0]
  932. secretName = nameSplitted[1]
  933. // TODO: later tokens can be used to read the secret tags
  934. }
  935. return objectType, secretName
  936. }
  937. func isValidSecret(checkTags, checkName bool, ref esv1beta1.ExternalSecretFind, secret keyvault.SecretItem) (bool, string) {
  938. if secret.ID == nil || !*secret.Attributes.Enabled {
  939. return false, ""
  940. }
  941. if checkTags && !okByTags(ref, secret) {
  942. return false, ""
  943. }
  944. secretName := path.Base(*secret.ID)
  945. if checkName && !okByName(ref, secretName) {
  946. return false, ""
  947. }
  948. return true, secretName
  949. }
  950. func okByName(ref esv1beta1.ExternalSecretFind, secretName string) bool {
  951. matches, _ := regexp.MatchString(ref.Name.RegExp, secretName)
  952. return matches
  953. }
  954. func okByTags(ref esv1beta1.ExternalSecretFind, secret keyvault.SecretItem) bool {
  955. tagsFound := true
  956. for k, v := range ref.Tags {
  957. if val, ok := secret.Tags[k]; !ok || *val != v {
  958. tagsFound = false
  959. break
  960. }
  961. }
  962. return tagsFound
  963. }