keyvault.go 41 KB

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