keyvault.go 38 KB

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