Azure Application Insights - availability testing with basic auth?

Viewed 3864

I am trying to setup availability testing (URL Ping Test) with Azure Application Insights on an endpoint that requires basic authentication. It seems that the standard approach with https://username:password@myendpoint.com isn't accepted by Azure (error message says that the URL is malformed and maybe I am missing https/http at the beginning).

Is there any other way to achieve this except of using multi-step web test or Azure Functions, assuming I want to stay in Azure ecosystem? :)

3 Answers

Ping test should be relatively simple, there are currently several possibilities to prevent such url from anonymous access, like policies or action filters.

Policy-based authorization

Let's create a simple policy that requires a Secret key in the query string.

First, create the requirement with handler e.g.:

public class HasSecretKeyRequirement : IAuthorizationRequirement
{
}

public class HasSecretKeyRequirementHandler : AuthorizationHandler<HasSecretKeyRequirement>
{
   private readonly IHttpContextAccessor _httpContextAccessor;
   private readonly IConfiguration _configuration;

   public HasSecretKeyRequirementHandler(IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
   {
       _httpContextAccessor = httpContextAccessor;
       _configuration = configuration;
   }

   protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasApiKeyRequirement requirement)
   {
       var httpContext = _httpContextAccessor.HttpContext;
            
       if (httpContext == null)
       {
           context.Fail();
           return Task.CompletedTask;
       }
            
       if (httpContext.Request.Query.TryGetValue("SecretKey", out extractedSecretKey))
       {
           var secretKey= _configuration.GetValue<string>("SecretKey");
 
           if (secretKey.Equals(extractedSecretKey))
           {
               context.Succeed(requirement);
               return Task.CompletedTask;
           }
        }
            
        httpContext.Response.ContentType = "text/plain";
        httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                    
        context.Fail();
        return Task.CompletedTask;  
    }
}

Then create a new policy with requirement and register requirement handler:

services.AddAuthorization(options =>
{
   options.AddPolicy("HasSecretKey", policy =>
      policy.Requirements.Add(new HasSecretKeyRequirement()));
);

services.AddSingleton<IAuthorizationHandler, HasSecretKeyRequirementHandler>();

Apply policy to your ping endpoint:

[Authorize(Policy = "HasSecretKey")]
[HttpGet("api/ping")]
public IActionResult Ping()
{
   return Ok();
}

Finallddd configure your availability test:

https://yourapi.com/api/ping?SecretKey=yoursecretkey

This is just an example, you can create your own requirement and handling logic. You can reuse these policies in your application, e.g. in the healthcheck endpoint:

endpoints.MapHealthChecks("/health")
    .RequireAuthorization("HasSecretKey");

This form of authorization may be sufficient in such a simple case, but definitely should not be used in more advanced scenarios.

For reference: Based on the snippet in the answer of @kaushal above, I was able to extend the Basic URL Ping test :) I use the XML in Terraform but you can also submit this via the REST API directly. In my case I needed to add an arbitrary header

<WebTest Name="appinsights-webtest" Id="ABD48585-0831-40CB-9069-682EA6BB3583" Enabled="True" CssProjectStructure="" CssIteration="" Timeout="30" WorkItemIds="" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010" Description="" CredentialUserName="" CredentialPassword="" PreAuthenticate="True" Proxy="default" StopOnError="False" RecordedResultFile="" ResultsLocale="">
  <Items>
    <Request Method="GET" Guid="a5f10126-e4cd-570d-961c-cea43999a200" Version="1.1" Url="https://example.com/health/stamp" ThinkTime="0" Timeout="30" ParseDependentRequests="False" FollowRedirects="False" RecordResult="True" Cache="False" ResponseTimeGoal="0" Encoding="utf-8" ExpectedHttpStatusCode="200" ExpectedResponseUrl="" ReportingName="" IgnoreHttpStatusCode="False">
      <Headers>
        <Header Name="X-Azure-FDID" Value="xxxxxxxxxxxx-xxxxxxxx-xxx" />
      </Headers>
  </Request>
  </Items>
</WebTest>

I didn't find this documented anywhere but works just as expected for me.

Related