keyvault.go 34 KB

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