Skip to content

Commit 2b05a73

Browse files
committed
Automate e2e test for Azure DNS01 Service Principal explicit auth with CCO
1 parent 0881811 commit 2b05a73

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

test/e2e/issuer_acme_dns01_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,39 @@ var _ = Describe("ACME Issuer DNS01 solver", Ordered, func() {
477477
return subscriptionID, resourceGroupName, hostedZoneName
478478
}
479479

480+
// setupCCOAzureCredentials creates a CredentialsRequest for Azure with fine-grained
481+
// DNS Zone Contributor permissions and returns the CCO-provisioned credentials.
482+
// Note: Unlike setupAmbientAWSCredentials/setupAmbientGCPCredentials, this does NOT patch
483+
// the subscription with 'CLOUD_CREDENTIALS_SECRET_NAME' because the operator does not yet
484+
// support mounting Azure credentials into the cert-manager pod. Once Azure support is added to
485+
// 'withCloudCredentials' in credentials_request.go, it can be adapted to follow the AWS/GCP pattern.
486+
setupCCOAzureCredentials := func(ctx context.Context) (clientID, clientSecret, tenantID []byte) {
487+
By("creating CredentialsRequest object for Azure")
488+
loader.CreateFromFile(testassets.ReadFile, filepath.Join("testdata", "credentials", "credentialsrequest_azure.yaml"), "")
489+
DeferCleanup(func() {
490+
loader.DeleteFromFile(testassets.ReadFile, filepath.Join("testdata", "credentials", "credentialsrequest_azure.yaml"), "")
491+
})
492+
493+
By("waiting for cloud secret to be available")
494+
var ccoSecret *corev1.Secret
495+
err := wait.PollUntilContextTimeout(context.TODO(), slowPollInterval, highTimeout, true, func(context.Context) (bool, error) {
496+
var getErr error
497+
ccoSecret, getErr = loader.KubeClient.CoreV1().Secrets("cert-manager").Get(ctx, "azure-credentials", metav1.GetOptions{})
498+
return getErr == nil, nil
499+
})
500+
Expect(err).NotTo(HaveOccurred(), "timeout waiting for Azure credentials secret")
501+
502+
By("reading CCO-provisioned credentials")
503+
clientID = ccoSecret.Data["azure_client_id"]
504+
clientSecret = ccoSecret.Data["azure_client_secret"]
505+
tenantID = ccoSecret.Data["azure_tenant_id"]
506+
Expect(clientID).NotTo(BeEmpty(), "azure_client_id should not be empty")
507+
Expect(clientSecret).NotTo(BeEmpty(), "azure_client_secret should not be empty")
508+
Expect(tenantID).NotTo(BeEmpty(), "azure_tenant_id should not be empty")
509+
510+
return clientID, clientSecret, tenantID
511+
}
512+
480513
// copyAzureSecretToNamespace creates a secret in the test namespace with Azure client secret
481514
copyAzureSecretToNamespace := func(ctx context.Context, namespace, secretName, secretKey string, clientSecret []byte) {
482515
By(fmt.Sprintf("copying Azure client secret to namespace %s", namespace))
@@ -1305,6 +1338,52 @@ var _ = Describe("ACME Issuer DNS01 solver", Ordered, func() {
13051338
dnsName := fmt.Sprintf("adaze-%s.%s", randomStr(3), appsDomain) // acronym for "ACME DNS01 AzureDNS Explicit"
13061339
createAndVerifyACMECertificate(ctx, certName, ns.Name, dnsName, issuerName, "Issuer")
13071340
})
1341+
1342+
It("should obtain a valid certificate using CCO-provisioned credentials", func() {
1343+
1344+
// Setup CCO-provisioned credentials for Azure (fine-grained DNS Zone Contributor)
1345+
clientID, clientSecret, tenantID := setupCCOAzureCredentials(ctx)
1346+
1347+
// Get DNS zone subscription, resource group, and zone name from the DNS config object
1348+
subscriptionID, resourceGroupName, hostedZoneName := getAzureDNSZoneInfo(ctx)
1349+
1350+
// Copy client secret to test namespace for Issuer reference
1351+
secretName := "azure-client-secret"
1352+
secretKey := "client-secret"
1353+
copyAzureSecretToNamespace(ctx, ns.Name, secretName, secretKey, clientSecret)
1354+
1355+
By("creating ACME Issuer with AzureDNS DNS-01 solver using CCO-provisioned credentials")
1356+
issuerName := "letsencrypt-dns01-cco"
1357+
solver := acmev1.ACMEChallengeSolver{
1358+
DNS01: &acmev1.ACMEChallengeSolverDNS01{
1359+
AzureDNS: &acmev1.ACMEIssuerDNS01ProviderAzureDNS{
1360+
SubscriptionID: subscriptionID,
1361+
ResourceGroupName: resourceGroupName,
1362+
HostedZoneName: hostedZoneName,
1363+
TenantID: string(tenantID),
1364+
ClientID: string(clientID),
1365+
ClientSecret: &certmanagermetav1.SecretKeySelector{
1366+
LocalObjectReference: certmanagermetav1.LocalObjectReference{
1367+
Name: secretName,
1368+
},
1369+
Key: secretKey,
1370+
},
1371+
},
1372+
},
1373+
}
1374+
issuer := createACMEIssuer(issuerName, solver)
1375+
_, err := certmanagerClient.CertmanagerV1().Issuers(ns.Name).Create(ctx, issuer, metav1.CreateOptions{})
1376+
Expect(err).NotTo(HaveOccurred(), "failed to create Issuer")
1377+
1378+
By("waiting for Issuer to become ready")
1379+
err = waitForIssuerReadiness(ctx, issuerName, ns.Name)
1380+
Expect(err).NotTo(HaveOccurred(), "timeout waiting for Issuer to become Ready")
1381+
1382+
// Create and verify certificate
1383+
certName := "letsencrypt-cert"
1384+
dnsName := fmt.Sprintf("adazc-%s.%s", randomStr(3), appsDomain) // acronym for "ACME DNS01 AzureDNS CCO"
1385+
createAndVerifyACMECertificate(ctx, certName, ns.Name, dnsName, issuerName, "Issuer")
1386+
})
13081387
})
13091388

13101389
Context("with IBM Cloud Internet Service Webhook", Label("Platform:IBM"), func() {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: cloudcredential.openshift.io/v1
2+
kind: CredentialsRequest
3+
metadata:
4+
name: cert-manager-azure-dns
5+
namespace: openshift-cloud-credential-operator
6+
spec:
7+
providerSpec:
8+
apiVersion: cloudcredential.openshift.io/v1
9+
kind: AzureProviderSpec
10+
roleBindings:
11+
- role: "DNS Zone Contributor"
12+
secretRef:
13+
name: azure-credentials
14+
namespace: cert-manager
15+
serviceAccountNames:
16+
- cert-manager

0 commit comments

Comments
 (0)