0

I have an http triggered azure function that starts an orchestrator function. In my dev tenant the code runs without a problem but when deploying to another tenant there has been nothing but trouble, in terms of security settings that affect the azure function.

Right now we are able to call the http trigger when connected to the company network via VPN, and the http triggered function runs without a problem. In the logs we can se that the orchestrator function starts, but immediately fails.

We have tested that we are able to connect to the storage account, and we have tried removing all the code inside the orchestrator besides a log-statement. But it still fails.

Is there some settings in the Azure portal that may have been made that only would affect the orchestrator, and not the Http-triggered function?

[FunctionName(nameof(PlannerOrchestrator))]
public async Task<string> PlannerOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log)
{
    log.LogInformation("Starting orchestration for Planner request");
    return string.Empty;
}
[FunctionName(nameof(PostPlannerTask))]
public async Task<IActionResult> PostPlannerTask(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
    [DurableClient] IDurableClient client,
    ILogger log)
{

    log.LogInformation("C# HTTP trigger function processed a request.");
    var incomingAccessToken = req.Headers.TryGetValue("Authorization", out var tokenHeaderValue) ? tokenHeaderValue.FirstOrDefault()?.Replace("Bearer ", string.Empty) : null;

    try
    {
        bool validToken = ValidateToken(incomingAccessToken);
        log.LogInformation("Valid token: {validToken}", validToken);
        if (!validToken)
        {
            return new UnauthorizedResult();
        }
    }
    catch (Exception ex)
    {
        log.LogError("Invalid token: {ex}", ex.Message);
        
        return new BadRequestResult();
    }


    var requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    var plannerRequest = JsonConvert.DeserializeObject<PlannerRequest>(requestBody);

    log.LogInformation("Request received: {request}", requestBody);

    var instanceId = nameof(PlannerOrchestrator) + "-" + Guid.NewGuid();

    instanceId = await client.StartNewAsync(nameof(PlannerOrchestrator), instanceId, plannerRequest);
    log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
    return await client.WaitForCompletionOrCreateCheckStatusResponseAsync(req, instanceId, TimeSpan.FromSeconds(60));
}
2
  • I guess you've looked at some logs in order to determine it's a security / permissions problem. Which log entry was it that you saw, and can you give us an extract so we can narrow down the problem? Commented Oct 4, 2024 at 19:04
  • Yes, the code ran perfectly in a dev tenant, but failed in prod when starting the orchestration from the http triggered function. The logs in the orchestration only said that it started, then failed. Commented Oct 12, 2024 at 10:52

2 Answers 2

0

Check the error logs in LogStream=>App Insights Logs:

enter image description here

Use the below query to check the error logs related to Durable function as mentioned in MSDOC:

let orchestrationInstanceID = "XXXXXX"; 
let start = datetime(XXXX-XX-XXTXX:XX:XX); 
traces  
| where timestamp > start and timestamp < start + 1h
| extend instanceId = iif(isnull(customDimensions["prop__InstanceId"] ) , customDimensions["prop__instanceId"], customDimensions["prop__InstanceId"] ) 
| extend logLevel = customDimensions["LogLevel"]
| extend functionName = customDimensions["prop__functionName"]
| extend status = customDimensions["prop__status"]
| extend details = customDimensions["prop__Details"] 
| extend reason = customDimensions["prop__reason"]
| where severityLevel > 1 // to see all logs of  severity level "Information" or greater.
| where instanceId == orchestrationInstanceID
| sort by timestamp asc

I have deployed your code to Azure function app and able to run the function as expected.

Code Snippet:

public static async Task<IActionResult> PostPlannerTask(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
[DurableClient] IDurableClient client,
ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");
        var incomingAccessToken = req.Headers.TryGetValue("Authorization", out var tokenHeaderValue) ? tokenHeaderValue.FirstOrDefault()?.Replace("Bearer ", string.Empty) : null;

        try
        {
            bool validToken = ValidateToken(incomingAccessToken);
            log.LogInformation("Valid token: {validToken}", validToken);
            if (!validToken)
            {
                return new UnauthorizedResult();
            }
        }
        catch (Exception ex)
        {
            log.LogError("Invalid token: {ex}", ex.Message);

            return new BadRequestResult();
        }
        var requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        var plannerRequest = JsonConvert.DeserializeObject<PlannerRequest>(requestBody);

        log.LogInformation("Request received: {request}", requestBody);

        var instanceId = nameof(Function1) + "-" + Guid.NewGuid();

        instanceId = await client.StartNewAsync(nameof(Function1), instanceId, plannerRequest);
        log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
        return await client.WaitForCompletionOrCreateCheckStatusResponseAsync(req, instanceId, TimeSpan.FromSeconds(60));
    }
    private static bool ValidateToken(string token)
    {
        return !string.IsNullOrEmpty(token);
    }

Durable function:

[FunctionName("Function1")]
public static async Task<List<string>> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var outputs = new List<string>();
    outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "Tokyo"));
    outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "Seattle"));
    outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "London"));
    return outputs;
}

[FunctionName(nameof(SayHello))]
public static string SayHello([ActivityTrigger] string name, ILogger log)
{
    log.LogInformation("Saying hello to {name}.", name);
    return $"Hello {name}!";
}

[FunctionName("Function1_HttpStart")]
public static async Task<HttpResponseMessage> HttpStart(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req,
    [DurableClient] IDurableOrchestrationClient starter,
    ILogger log)
{
    string instanceId = await starter.StartNewAsync("Function1", null);

    log.LogInformation("Started orchestration with ID = '{instanceId}'.", instanceId);

    return starter.CreateCheckStatusResponse(req, instanceId);
}

Deployed to Azure function App.

Portal:

enter image description here

Provide Bearer token in Auth section while running the function:

enter image description here

Response:

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

0

Figured out the problem. We had no control over creating the function and we found out that they had set it to .NET8 isolated worker, instead of .NET6 In-process.

Had to rewrite the code to .NET8 isolated, then it were able to run successfully.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.