keyvault.go 50 KB

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