provider.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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. limitations under the License.
  10. */
  11. package azure
  12. import (
  13. "context"
  14. "os"
  15. "sync"
  16. "time"
  17. "github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
  18. kvauth "github.com/Azure/go-autorest/autorest/azure/auth"
  19. // nolint
  20. . "github.com/onsi/ginkgo/v2"
  21. // nolint
  22. . "github.com/onsi/gomega"
  23. v1 "k8s.io/api/core/v1"
  24. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  25. utilpointer "k8s.io/utils/pointer"
  26. "github.com/external-secrets/external-secrets-e2e/framework"
  27. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  28. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  29. )
  30. type azureProvider struct {
  31. clientID string
  32. clientSecret string
  33. tenantID string
  34. vaultURL string
  35. client *keyvault.BaseClient
  36. framework *framework.Framework
  37. }
  38. func newazureProvider(f *framework.Framework, clientID, clientSecret, tenantID, vaultURL string) *azureProvider {
  39. clientCredentialsConfig := kvauth.NewClientCredentialsConfig(clientID, clientSecret, tenantID)
  40. clientCredentialsConfig.Resource = "https://vault.azure.net"
  41. basicClient := keyvault.New()
  42. prov := &azureProvider{
  43. framework: f,
  44. client: &basicClient,
  45. clientID: clientID,
  46. clientSecret: clientSecret,
  47. tenantID: tenantID,
  48. vaultURL: vaultURL,
  49. }
  50. o := &sync.Once{}
  51. BeforeEach(func() {
  52. // run authorizor only if this spec is called
  53. o.Do(func() {
  54. authorizer, err := clientCredentialsConfig.Authorizer()
  55. if err != nil {
  56. Fail(err.Error())
  57. }
  58. prov.client.Authorizer = authorizer
  59. })
  60. prov.CreateSecretStoreWithWI()
  61. prov.CreateSecretStore()
  62. prov.CreateReferentSecretStore()
  63. })
  64. return prov
  65. }
  66. func newFromEnv(f *framework.Framework) *azureProvider {
  67. vaultURL := os.Getenv("VAULT_URL")
  68. tenantID := os.Getenv("TENANT_ID")
  69. clientID := os.Getenv("AZURE_CLIENT_ID")
  70. clientSecret := os.Getenv("AZURE_CLIENT_SECRET")
  71. return newazureProvider(f, clientID, clientSecret, tenantID, vaultURL)
  72. }
  73. func (s *azureProvider) CreateSecret(key string, val framework.SecretEntry) {
  74. _, err := s.client.SetSecret(
  75. context.Background(),
  76. s.vaultURL,
  77. key,
  78. keyvault.SecretSetParameters{
  79. Value: &val.Value,
  80. SecretAttributes: &keyvault.SecretAttributes{
  81. RecoveryLevel: keyvault.Purgeable,
  82. Enabled: utilpointer.Bool(true),
  83. },
  84. })
  85. Expect(err).ToNot(HaveOccurred())
  86. }
  87. func (s *azureProvider) DeleteSecret(key string) {
  88. _, err := s.client.DeleteSecret(
  89. context.Background(),
  90. s.vaultURL,
  91. key)
  92. Expect(err).ToNot(HaveOccurred())
  93. }
  94. func (s *azureProvider) CreateKey(key string) *keyvault.JSONWebKey {
  95. out, err := s.client.CreateKey(
  96. context.Background(),
  97. s.vaultURL,
  98. key,
  99. keyvault.KeyCreateParameters{
  100. Kty: keyvault.RSA,
  101. KeyAttributes: &keyvault.KeyAttributes{
  102. RecoveryLevel: keyvault.Purgeable,
  103. Enabled: utilpointer.Bool(true),
  104. },
  105. },
  106. )
  107. Expect(err).ToNot(HaveOccurred())
  108. return out.Key
  109. }
  110. func (s *azureProvider) DeleteKey(key string) {
  111. _, err := s.client.DeleteKey(context.Background(), s.vaultURL, key)
  112. Expect(err).ToNot(HaveOccurred())
  113. }
  114. func (s *azureProvider) CreateCertificate(key string) {
  115. _, err := s.client.CreateCertificate(
  116. context.Background(),
  117. s.vaultURL,
  118. key,
  119. keyvault.CertificateCreateParameters{
  120. CertificatePolicy: &keyvault.CertificatePolicy{
  121. X509CertificateProperties: &keyvault.X509CertificateProperties{
  122. Subject: utilpointer.String("CN=e2e.test"),
  123. ValidityInMonths: utilpointer.Int32(42),
  124. },
  125. IssuerParameters: &keyvault.IssuerParameters{
  126. Name: utilpointer.String("Self"),
  127. },
  128. Attributes: &keyvault.CertificateAttributes{
  129. RecoveryLevel: keyvault.Purgeable,
  130. Enabled: utilpointer.Bool(true),
  131. },
  132. },
  133. CertificateAttributes: &keyvault.CertificateAttributes{
  134. RecoveryLevel: keyvault.Purgeable,
  135. Enabled: utilpointer.Bool(true),
  136. },
  137. },
  138. )
  139. Expect(err).ToNot(HaveOccurred())
  140. }
  141. func (s *azureProvider) GetCertificate(key string) []byte {
  142. attempts := 60
  143. for {
  144. out, err := s.client.GetCertificate(
  145. context.Background(),
  146. s.vaultURL,
  147. key,
  148. "",
  149. )
  150. Expect(err).ToNot(HaveOccurred())
  151. if out.Cer != nil {
  152. return *out.Cer
  153. }
  154. attempts--
  155. if attempts <= 0 {
  156. Fail("failed fetching azkv certificate")
  157. }
  158. <-time.After(time.Second * 5)
  159. }
  160. }
  161. func (s *azureProvider) DeleteCertificate(key string) {
  162. _, err := s.client.DeleteCertificate(context.Background(), s.vaultURL, key)
  163. Expect(err).ToNot(HaveOccurred())
  164. }
  165. const (
  166. staticSecretName = "provider-secret"
  167. referentSecretName = "referent-secret"
  168. workloadIdentityServiceAccountNme = "external-secrets-operator"
  169. credentialKeyClientID = "client-id"
  170. credentialKeyClientSecret = "client-secret"
  171. )
  172. func newProviderWithStaticCredentials(tenantID, vaultURL, secretName string) *esv1beta1.AzureKVProvider {
  173. return &esv1beta1.AzureKVProvider{
  174. TenantID: &tenantID,
  175. VaultURL: &vaultURL,
  176. AuthSecretRef: &esv1beta1.AzureKVAuth{
  177. ClientID: &esmeta.SecretKeySelector{
  178. Name: staticSecretName,
  179. Key: credentialKeyClientID,
  180. },
  181. ClientSecret: &esmeta.SecretKeySelector{
  182. Name: staticSecretName,
  183. Key: credentialKeyClientSecret,
  184. },
  185. },
  186. }
  187. }
  188. func newProviderWithServiceAccount(tenantID, vaultURL string, authType esv1beta1.AzureAuthType, serviceAccountName string, serviceAccountNamespace *string) *esv1beta1.AzureKVProvider {
  189. return &esv1beta1.AzureKVProvider{
  190. TenantID: &tenantID,
  191. VaultURL: &vaultURL,
  192. AuthType: &authType,
  193. ServiceAccountRef: &esmeta.ServiceAccountSelector{
  194. Name: serviceAccountName,
  195. Namespace: serviceAccountNamespace,
  196. },
  197. }
  198. }
  199. func (s *azureProvider) CreateSecretStore() {
  200. azureCreds := &v1.Secret{
  201. ObjectMeta: metav1.ObjectMeta{
  202. Name: staticSecretName,
  203. Namespace: s.framework.Namespace.Name,
  204. },
  205. StringData: map[string]string{
  206. credentialKeyClientID: s.clientID,
  207. credentialKeyClientSecret: s.clientSecret,
  208. },
  209. }
  210. err := s.framework.CRClient.Create(context.Background(), azureCreds)
  211. Expect(err).ToNot(HaveOccurred())
  212. secretStore := &esv1beta1.SecretStore{
  213. ObjectMeta: metav1.ObjectMeta{
  214. Name: s.framework.Namespace.Name,
  215. Namespace: s.framework.Namespace.Name,
  216. },
  217. Spec: esv1beta1.SecretStoreSpec{
  218. Provider: &esv1beta1.SecretStoreProvider{
  219. AzureKV: newProviderWithStaticCredentials(s.tenantID, s.vaultURL, staticSecretName),
  220. },
  221. },
  222. }
  223. err = s.framework.CRClient.Create(context.Background(), secretStore)
  224. Expect(err).ToNot(HaveOccurred())
  225. }
  226. func (s *azureProvider) CreateReferentSecretStore() {
  227. azureCreds := &v1.Secret{
  228. ObjectMeta: metav1.ObjectMeta{
  229. Name: referentSecretName,
  230. Namespace: s.framework.Namespace.Name,
  231. },
  232. StringData: map[string]string{
  233. credentialKeyClientID: s.clientID,
  234. credentialKeyClientSecret: s.clientSecret,
  235. },
  236. }
  237. err := s.framework.CRClient.Create(context.Background(), azureCreds)
  238. Expect(err).ToNot(HaveOccurred())
  239. secretStore := &esv1beta1.ClusterSecretStore{
  240. ObjectMeta: metav1.ObjectMeta{
  241. Name: referentAuthName(s.framework),
  242. Namespace: s.framework.Namespace.Name,
  243. },
  244. Spec: esv1beta1.SecretStoreSpec{
  245. Provider: &esv1beta1.SecretStoreProvider{
  246. AzureKV: newProviderWithStaticCredentials(s.tenantID, s.vaultURL, referentSecretName),
  247. },
  248. },
  249. }
  250. err = s.framework.CRClient.Create(context.Background(), secretStore)
  251. Expect(err).ToNot(HaveOccurred())
  252. }
  253. func referentAuthName(f *framework.Framework) string {
  254. return "referent-auth-" + f.Namespace.Name
  255. }
  256. func (s *azureProvider) CreateSecretStoreWithWI() {
  257. authType := esv1beta1.AzureWorkloadIdentity
  258. namespace := "external-secrets-operator"
  259. ClusterSecretStore := &esv1beta1.ClusterSecretStore{
  260. ObjectMeta: metav1.ObjectMeta{
  261. Name: s.framework.Namespace.Name,
  262. },
  263. Spec: esv1beta1.SecretStoreSpec{
  264. Provider: &esv1beta1.SecretStoreProvider{
  265. AzureKV: newProviderWithServiceAccount(s.tenantID, s.vaultURL, authType, workloadIdentityServiceAccountNme, &namespace),
  266. },
  267. },
  268. }
  269. err := s.framework.CRClient.Create(context.Background(), ClusterSecretStore)
  270. Expect(err).ToNot(HaveOccurred())
  271. }
  272. func (s *azureProvider) CreateReferentSecretStoreWithWI() {
  273. authType := esv1beta1.AzureWorkloadIdentity
  274. ClusterSecretStore := &esv1beta1.ClusterSecretStore{
  275. ObjectMeta: metav1.ObjectMeta{
  276. Name: referentAuthName(s.framework),
  277. },
  278. Spec: esv1beta1.SecretStoreSpec{
  279. Provider: &esv1beta1.SecretStoreProvider{
  280. AzureKV: newProviderWithServiceAccount(s.tenantID, s.vaultURL, authType, workloadIdentityServiceAccountNme, nil),
  281. },
  282. },
  283. }
  284. err := s.framework.CRClient.Create(context.Background(), ClusterSecretStore)
  285. Expect(err).ToNot(HaveOccurred())
  286. }