0

I am currently looking to write a C# function that will query my Azure Web App Service and Check Custom Domains are valid.

As part of this, I am using the newer Azure.ResourceManager libraries that query the ARM API. So far I have.

internal async Task<List<AppServiceCustomDomainResult>> CreateOrUpdateCustomDomains(string? appServiceName, List<AppServiceCustomDomains> activeDomains)
{
    var result = new List<AppServiceCustomDomainResult>();

    _log.LogInformation("Connecting to Azure");

    var azure = GetAzureSubscription();
    await foreach (var site in azure.GetWebSitesAsync())
    {
        if (site.HasData && site.Data.Name == appServiceName)
        {
            var hostNameBindings = site.GetSiteHostNameBindings();

            foreach (var binding in hostNameBindings)
            {
                if (activeDomains.Any(c => c.SniName != null && c.SniName.EndsWith(checkName)))
                {
                    // Check SSL
                    if (binding.Data.SslState == HostNameBindingSslState.SniEnabled)
                    {
                        
                    }
                }
                else
                {
                    // Add SSL

                    // Add Binding
                }
            }

            break;
        }
    }

    return result;
}

What I'm looking for next is a way to check the SSL Certificate on the binding to see if it's expired and needs updating/removing. I also need to add one too, but I've not quite got to that stage yet. I can't seem to find anyway to get the SSL to check it's expiry however, has anyone been able to find out? I am referencing https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/get-host-name-binding, but there's very little in the way of examples.

I also tried site.GetSitePublicCertificates() but I think that is related to something else as nothing is returned, although I think I only have managed certs on my test at the moment..

Max Power
  • 350
  • 4
  • 15
  • Use Powershell : https://learn.microsoft.com/en-us/answers/questions/892628/display-ssl-certificate-expiration-dates-via-power – jdweng Aug 21 '23 at 12:04
  • I want to use C# only as there are other operations undertaken on the app service before and after this method. – Max Power Aug 21 '23 at 12:23
  • Use Powershell Class : https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.powershell?view=powershellsdk-7.3.0 – jdweng Aug 21 '23 at 12:30
  • Working around a problem and relying on the OS to have Powershell. – Max Power Aug 24 '23 at 13:29

1 Answers1

0

You can make use of Rest API to list all your custom domains and use another API's related to creating and updating Custom domains with host binding in and call it with GET, PUT or POST request in your C# code like below:-

My C# Http Trigger function code:-

Rest API reference:-

Reference :- My SO thread answer

using Azure.Core;
using Azure.Identity;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using System.Net.Http.Json;

namespace FunctionApp1
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            var token = await GetAccessToken("83331f4e-7f45-4ce4-99ed-af9038592395", "c0c952e9-5254-45b5-b838-6d26a31435cb", "Cnd8Q~Ro6wHqvMGQUyvqrEgguL0nl-gYmTYkDcPI");
            var results = await GetResults(token);

            return new OkObjectResult(results);
        }

        private static async Task<string> GetAccessToken(string tenantId, string clientId, string clientKey)
        {
            var credentials = new ClientSecretCredential(tenantId, clientId, clientKey);
            var result = await credentials.GetTokenAsync(new TokenRequestContext(new[] { "https://management.azure.com/.default"
}), default);
            return result.Token;
        }

        private static async Task<string> GetResults(string token)
        {
            var httpClient = new HttpClient
            {
                BaseAddress = new Uri("https://management.azure.com/subscriptions/")
            };

            string URI = $"0151c365-f598-44d6-b4fd-e2b6e97cb2a7/providers/Microsoft.DomainRegistration/domains?api-version=2022-03-01";

            httpClient.DefaultRequestHeaders.Remove("Authorization");
            httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
            HttpResponseMessage response = await httpClient.GetAsync(URI);

            var HttpsResponse = await response.Content.ReadAsStringAsync();
            //var JSONObject = JsonConvert.DeserializeObject<object>(HttpsResponse);

            //return response.StatusCode.ToString();
            return HttpsResponse;
        }
    }
}

Output:-

enter image description here

enter image description here

Similar you can use this API to Web Apps - Create Or Update Host Name Binding - REST API (Azure App Service) | Microsoft Learn

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace FunctionApp1
{
    public static class Function1
    {
        [FunctionName("UpdateHostNameBindingFunction")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            var requestParams = JsonConvert.DeserializeObject<HostNameBindingRequest>(requestBody);

            var token = await GetAccessToken("<tenant-id>", "<client-id>", "<client-secret>");
            var response = await UpdateHostNameBinding(token, requestParams);

            return new OkObjectResult(response);
        }

        private static async Task<string> GetAccessToken(string tenantId, string clientId, string clientSecret)
        {
            var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret);
            var result = await credentials.GetTokenAsync(new TokenRequestContext(new[] { "https://management.azure.com/.default" }), default);
            return result.Token;
        }

        private static async Task<string> UpdateHostNameBinding(string token, HostNameBindingRequest requestParams)
        {
            var httpClient = new HttpClient();
            string endpoint = $"https://management.azure.com/subscriptions/{requestParams.SubscriptionId}/resourceGroups/{requestParams.ResourceGroupName}/providers/Microsoft.Web/sites/{requestParams.AppName}/slots/{requestParams.Slot}/hostNameBindings/{requestParams.HostName}?api-version=2022-03-01";

            var requestBody = new
            {
                kind = requestParams.Kind,
                properties = new
                {
                    azureResourceName = requestParams.AzureResourceName,
                    azureResourceType = requestParams.AzureResourceType,
                    customHostNameDnsRecordType = requestParams.CustomHostNameDnsRecordType,
                    domainId = requestParams.DomainId,
                    hostNameType = requestParams.HostNameType,
                    siteName = requestParams.SiteName,
                    sslState = requestParams.SslState,
                    thumbprint = requestParams.Thumbprint
                }
            };

            var content = new StringContent(JsonConvert.SerializeObject(requestBody), Encoding.UTF8, "application/json");
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            HttpResponseMessage response = await httpClient.PutAsync(endpoint, content);

            if (response.IsSuccessStatusCode)
            {
                string responseContent = await response.Content.ReadAsStringAsync();
                return responseContent;
            }
            else
            {
                return $"Error: {response.StatusCode}";
            }
        }
    }

    public class HostNameBindingRequest
    {
        public string Kind { get; set; }
        public string AzureResourceName { get; set; }
        public string AzureResourceType { get; set; }
        public string CustomHostNameDnsRecordType { get; set; }
        public string DomainId { get; set; }
        public string HostNameType { get; set; }
        public string SiteName { get; set; }
        public string SslState { get; set; }
        public string Thumbprint { get; set; }
        public string SubscriptionId { get; set; }
        public string ResourceGroupName { get; set; }
        public string AppName { get; set; }
        public string Slot { get; set; }
        public string HostName { get; set; }
    }
}

SiddheshDesai
  • 3,668
  • 1
  • 2
  • 11