6

I have created Azure CDN through ARM template from Azure DevOps by CI/CD, followed the below references -

https://github.com/Azure/azure-quickstart-templates/tree/master/201-cdn-with-storage-account

https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/2019-04-15/profiles/endpoints/customdomains

Azure CDN created and mapped the Custom Domain with Endpoint. But not sure how do I enable HTTPS (My Own certificate available in KeyVault) in custom domain through ARM (from Azure DevOps) template, options are not available in MS template reference.

Want to automate the whole creation of Azure CDN.

Is there a way to enable HTTPS for CustomDomain thorough DevOps?

Here is my script (not the final) -

#Enable Https in Custom Domain - Azure CDN

$cdnProfileName ='debtestcdnprofile'
$cdnEndpointName = 'debtestcdnendpoint'
$cdnCustomDomainName = 'mysubdomain-mydomain-com' # testing 
$keyVaultName = 'debkeyvault'
$certificateName = 'debasiscert'
$apiVersion = '2019-04-15'

$secretVersion = 'XXXXXXXXXXX'
$secretName = 'debasiscert'
$keyVaultResourceGroupName = 'rsgStgCDN'

$cdnProfile = Get-AzCdnProfile -ProfileName $cdnProfileName;
$resourceGroup = Get-AzResourceGroup -Name $cdnProfile.ResourceGroupName;
$resourceGroupName = $resourceGroup.ResourceGroupName;
$context = Get-AzContext;
$subscriptionId = $context.Subscription.Id;
$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile;

$profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azProfile);
$token = $profileClient.AcquireAccessToken($context.Subscription.TenantId);
$accessToken = $token.AccessToken;

write-verbose -verbose "[INF] Access token : $($accessToken)"

$StateUri = "https://management.azure.com/subscriptions/$($subscriptionId)/resourcegroups/$($resourceGroupName)/providers/Microsoft.Cdn/profiles/$($cdnProfileName)/endpoints/$($cdnEndpointName)/customdomains/$($cdnCustomDomainName)?api-version=$($apiVersion)"

$ProvisionUri = "https://management.azure.com/subscriptions/$($subscriptionId)/resourcegroups/$($resourceGroupName)/providers/Microsoft.Cdn/profiles/$($cdnProfileName)/endpoints/$($cdnEndpointName)/customdomains/$($cdnCustomDomainName)/enableCustomHttps?api-version=$($apiVersion)"

$body = $ExecutionContext.InvokeCommand.ExpandString('{"certificateSource":"AzureKeyVault","protocolType":"ServerNameIndication","certificateSourceParameters":{"@odata.type":"#Microsoft.Azure.Cdn.Models.KeyVaultCertificateSourceParameters","subscriptionId":"$subscriptionId","resourceGroupName":"$keyVaultResourceGroupName","vaultName":"$keyVaultName","SecretName":"$secretName","SecretVersion":"$secretVersion","updateRule":"NoAction","deleteRule":"NoAction"}}')

$headers = @{ }

$headers.Add('Authorization', "Bearer $accessToken") 

$headers.Add('Content-Type', 'application/json')


$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'

[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols

$state = (Invoke-RestMethod -Method GET  -Uri $StateUri -Headers $headers).properties.customHttpsProvisioningState

Throwing same issue in CI/CD as well as while executing through PowerShell

Issue -

Invoke-RestMethod : {
  "error": {
  "code": "NotFound",
   "message": "The resource cannot be found."
  }

At line:51 char:11
+ $state = (Invoke-RestMethod -Method GET  -Uri $StateUri -Headers $hea ...
+           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], We 
   bException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Executing the "Get-AzCdnCustomDomain" command in PowerShell also throwing bad request -

PS C:\WINDOWS\system32> Get-AzCdnCustomDomain -ResourceGroupName 'XXXXX' -ProfileName 'XXXXX' -EndpointName 'XXXXX' -CustomDomainNa
me 'subdomain.domain.com'
Get-AzCdnCustomDomain : Operation returned an invalid status code 'BadRequest'
At line:1 char:1
+ Get-AzCdnCustomDomain -ResourceGroupName 'XXXXX' -Prof ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : CloseError: (:) [Get-AzCdnCustomDomain], ErrorResponseException
    + FullyQualifiedErrorId : Microsoft.Azure.Commands.Cdn.CustomDomain.GetAzureRmCdnCustomDomain
Debasis Ghosh
  • 263
  • 3
  • 21

2 Answers2

3

Enable HTTPS in CustomDomain in Azure CDN through ARM Template

If you want to achieve this by using ARM template, unfortunately, it haven't supported to add HTTPS for endpoint in the ARM template until now. So, even using Azure Devops, it also could not be make true by using ARM template.

But in the pipeline of VSTS, you can using a short Powershell script by calling below API to enable the HTTPS:

POST https://management.azure.com/subscriptions/{subscription id}/resourcegroups/{resourceGroup name}/providers/Microsoft.Cdn/profiles/{Cdnprofile name)/endpoints/{cdnEndpointName}/customdomains/customDomain/enableCustomHttps?api-version=2018-04-02" 

As you mentioned, you store the certificate in Key Vault, you need specify the key vault as certificateSource in this request body:

{
  "certificateSource": "AzureKeyVault",
  "protocolType": "ServerNameIndication",
  "certificateSourceParameters": {
    "@odata.type": "#Microsoft.Azure.Cdn.Models.KeyVaultCertificateSourceParameters",
    "subscriptionId": "$subId",
    "resourceGroupName": "$resourceGroupKv",
    "vaultName": "$kvName",
    "SecretName": "$secretName",
    "SecretVersion": "$version",
    "updateRule": "NoAction",
    "deleteRule": "NoAction"
  }
}

For details, please check this doc to configure your request body based on your actual need.

Also, there has someone describe the detailed steps and scripts for how to using Powershell to call this API. You can refer to that blog.


Want to automate the whole creation of Azure CDN.

Now, you should have got how to enable HTTPS. So the issue is how to create the the completed Azure CDN automatically in VSTS.

Step1: Add a agent job.

Step2: Add a first task Azure resource group deployment

Apply the ARM template by using Azure resource group deployment task in Build/Release pipeline. This task is available both in build and release pipeline.

Step3: Add a second task Powershell and input the above enable HTTPS powershell script into inline type.

After configure them, run this pipeline, then it can achieve automate the whole creation of Azure CDN.

You can apply these steps in CI or CD, anyone is available in VSTS.

Mengdi Liang
  • 17,577
  • 2
  • 28
  • 35
  • Thanks Merlin. did it through PowerShell, now I am facing the issue --- Property 'CustomDomainEntityKey.CustomDomainName' cannot be set to -(Domain Name), not sure why it is propagating? (API Version is - 2019-04-15) – Debasis Ghosh Dec 04 '19 at 15:54
  • @DebasisGhosh, Which difficulty are you facing now? Could not pass the exactly customdomain name to it? Or think it should not pass the domain here? – Mengdi Liang Dec 04 '19 at 16:08
  • passing the customDomain value in RestAPI. during execution of PowerShell script in Azure DevOps popping up this issue. – Debasis Ghosh Dec 04 '19 at 16:18
  • @DebasisGhosh Do you mind show me the detailed error log? Maybe I could find something from it. – Mengdi Liang Dec 04 '19 at 18:01
  • @DebasisGhosh, It's okay:-0 I have checked your script and the error, The `CustomDomainName` value you pass to the API is `mysubdomain.mydomain.com`? If yes, please try with changing it as `mysubdomain-mydomain-com`. – Mengdi Liang Dec 06 '19 at 11:11
  • Thanks. Error message changed to - "error": { "code": "NotFound", "message": "The resource cannot be found." }. Though I have changed the domain name as mysubdomain-mydomain-com – Debasis Ghosh Dec 06 '19 at 13:37
  • @DebasisGhosh, Could you try this [API](https://learn.microsoft.com/en-us/rest/api/cdn/customdomains/listbyendpoint) firstly? To list the exactly name. You can try that API locally. Then put the name you got from it into this [API](https://learn.microsoft.com/en-us/rest/api/cdn/customdomains/get) – Mengdi Liang Dec 06 '19 at 13:49
  • Tried -listbyendpoint API and Status is 200 with the Domain name, but when I am trying it with - Get API Status is 400 - ``` "error": { "code": "BadRequest", "message": "Property 'CustomDomainEntityKey.CustomDomainName' cannot be set to 'mysubdomain.mydomain.com'. " } With "mysubdomain-mydomain-com" domain name Status is 404. – Debasis Ghosh Dec 06 '19 at 14:26
  • @DebasisGhosh. Odd. Could you try with the powershell command? **Get-AzCdnCustomDomain -ResourceGroupName ResourceGroupName -ProfileName cdnProfileName -EndpointName cdnEndpointName -CustomDomainName cdnCustomDomainName**.(You can try in powershell command line). Now, I need to confirm is it be a issue for this value. I saw this is a hard code value you specified in the parameter. – Mengdi Liang Dec 06 '19 at 15:41
  • Liang - PowerShell command is throwing 'Bad Request', updated the post with Error. – Debasis Ghosh Dec 06 '19 at 16:18
  • @DebasisGhosh Okay. Now I sure the value of your hardcode domain name is not available. I work in Azure devops team not very professional on Azure, and unfortunately, I just out of office and now not very convenient to talk with you in chat.(I am using phone) Do you mind let’s chat in next Monday or in this Sunday? I have four work hours in this Sunday. Just I am in UTC +8, do not know is it convenient for you. So, better is chat in next Monday. Is that okay? I will talk with my colleague to together help you analyze this error. – Mengdi Liang Dec 06 '19 at 16:46
  • @@MerlinLiang - Thank you. Sure, we will discuss next Monday. My time zone is UTC +5:30. Appreciate your help – Debasis Ghosh Dec 06 '19 at 17:56
  • @@MerlinLiang - through "Get-AzCdnCustomDomain" command getting custom domain. e.g. $val = Get-AzCdnCustomDomain -EndpointName "XXXXX" -ProfileName "XXXX" -ResourceGroupName "XXXX" Write-Host $val.HostName – Debasis Ghosh Dec 08 '19 at 20:50
3

Enabling HTTPS of the custom domain achieved through PowerShell script and invoking the Rest API. At least now; I am unable to do through "az cdn custom-domain enable-https", did not get proper sample for --custom-domain-https-parameters.

Due to bad mistake always I'm receiving HTTP status 400 from Rest API. Reason is I am passing domain name (host name) instead of friendly name mapping to the endpoint. (e.g. - my domain name or host name is : mysubdomain.domainname.com and friendly name is MyDevDomain; then Rest API is expecting MyDevDomain)

We can follow @Merlin Liang - MSFT steps to automate the process.

Steps I followed -

ref - https://learn.microsoft.com/en-us/azure/cdn/cdn-custom-ssl?tabs=option-2-enable-https-with-your-own-certificate#ssl-certificates

  1. Register Azure CDN in Azure Active Directory.
  2. Grant Azure CDN access to key vault.
  3. PowerShell script -

https://www.nlymbery.com.au/posts/azure-cdn-automate-provisioning-custom-certificate/

https://gist.github.com/HQJaTu/c5695626ba51c6194845fa60913e911b

$cdnProfile = Get-AzCdnProfile -ProfileName $cdnProfileName;
$resourceGroup = Get-AzResourceGroup -Name $cdnProfile.ResourceGroupName;
$resourceGroupName = $resourceGroup.ResourceGroupName;

# Get Access Token to invoke in Rest API
$context = Get-AzContext;
$subscriptionId = $context.Subscription.Id;
$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile;
if (-not $azProfile.Accounts.Count) {
    Write-Error "Error occured!"
    Exit 1
}

$profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azProfile);
$token = $profileClient.AcquireAccessToken($context.Subscription.TenantId) ;
$accessToken = $token.AccessToken;
if (-not $accessToken) {
    Write-Error "Error occured!";
    Exit 1
}

# Update certificate values
# ref - https://learn.microsoft.com/en-us/rest/api/cdn/customdomains/enablecustomhttps

$ProvisionUri = "https://management.azure.com/subscriptions/$($subscriptionId)/resourcegroups/$($resourceGroupName)/providers/Microsoft.Cdn/profiles/$($cdnProfileName)/endpoints/$($cdnEndpointName)/customdomains/$($cdnCustomDomainName)/enableCustomHttps?api-version=$($apiVersion)"

$body = $ExecutionContext.InvokeCommand.ExpandString('{"certificateSource":"AzureKeyVault","protocolType":"ServerNameIndication","certificateSourceParameters":{"@odata.type":"#Microsoft.Azure.Cdn.Models.KeyVaultCertificateSourceParameters","subscriptionId":"$subscriptionId","resourceGroupName":"$keyVaultResourceGroupName","vaultName":"$keyVaultName","SecretName":"$secretName","SecretVersion":"$secretVersion","updateRule":"NoAction","deleteRule":"NoAction"}}')

$headers = @{ }  
$headers.Add('Authorization', "Bearer $accessToken")  
$headers.Add('Content-Type', 'application/json')

write-verbose -verbose "[INF] Provision Uri: $($ProvisionUri)"
write-verbose -verbose "[INF] Headers: $($headers)"  
write-verbose -verbose "[INF] Body: $($body)"

Write-Verbose -Verbose "Applying custom certificate to $($cdnProfileName):$($cdnEndpointName)"

Invoke-RestMethod -Method Post -Uri $ProvisionUri -Headers $headers -Body $body
write-verbose -verbose "[INF] Script executed successfully!"

before invoking check the provisioning state as per the blog.

Stringfellow
  • 2,788
  • 2
  • 21
  • 36
Debasis Ghosh
  • 263
  • 3
  • 21