skip to Main Content

I’m new to using C# in Azure and I’m running an inline C# script in an Azure Logic Apps workflows to read a Key Vault secret into a variable from within a ‘CSharp Script Code’ object in an Azure Workflow. But nothing I’ve read on the internet appears to work. Should this be a simple one-line command as I’ve been told?

I have a secret named ‘HMAC’ connected to the HMACKey name in the workflow and was told to use the code string secretKey = await {Azure Key Vault Client}.GetSecretAsync({Azure Key Vault Url}, {Azure Secret}) to retrieve this.

I’m assuming {Key Vault Url} means the first part of the URI for the Secret Identifier, which in my test case is ‘https://hmactesting.vault.azure.net’, and the secret is the name of the secret ‘HMAC’ in this case.

But what is meant by {Azure Key Vault Client} in this instance? Is this a ‘new KeyVaultClient()’ type that I have to declare and authorise in the inline code, or does this already exist as an environment variable within the workflow that I can attach to and use?

I’ve searched the net but can’t find anything specifically relating to how to do this from within an inline ‘CSharp Script Code’ object in an Azure Workflow?

I believe the strings for ‘KeyVaultUrl’ and ‘secret’ are correct in the command, which leaves the {Azure Key Vault Client} object. Is this something still I have to create in the code? I’ve seen examples of C# code where this is created, but those were not using the Azure workflow and C# scripting object.

I can already see the secret I’m trying to read when I set it up as an object in the workflow, so can I connect to this from within the C# script?

My full test script is as follows:

// Add the required libraries
#r "Newtonsoft.Json"
#r "Microsoft.Azure.Workflows.Scripting"
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.Workflows.Scripting;
using Newtonsoft.Json.Linq;
using System;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

/// <summary>
/// Executes the inline csharp code.
/// </summary>
/// <param name="context">The workflow context.</param>
/// <remarks> This is the entry-point to your code. The function signature should remain unchanged.</remarks>
public static async Task<Results> Run(WorkflowContext context, ILogger log)
{
  //String Variables (for clarity)
  string KeyVaultUrl = "https://hmactesting.vault.azure.net";
  string secret = "HMAC";
  string compare = string.Empty;
  string _origonalMessage = string.Empty;
  string _origonalHmac = string.Empty;
  string _calculatedHmac = string.Empty;

  ////Define the trigger output.
  var triggerOutputs = (await context.GetTriggerResults().ConfigureAwait(false)).Outputs;
  //string kvSecret = await kVClient.GetSecretAsync(azureKeyVaultUrl, secret);

  ////Set the local HMAC key from the Azure Key Vault.
  string secretKey = "HMAC-TEST"; // <--Temporary for testing. 
  //I need to get the above value from the 'HMAC' secret in the 'HMACTesting' Key Vault
  //The example I was given was to use: string secretKey = await {Azure Key Vault Client}.GetSecretAsync({Azure Key Vault Url}, {Azure secret});
  //Assuming I have the correct {Key Vault Url} I need to know what is meant by {Key Vault Client} do I need to build this?
  //var key = await ((WHAT?)).GetSecretAsync(KeyVaultUrl, secret) // <-- Should this work? If yes, could it be a permissions thing? Although I can see the secret contents when using an object on the workflow.


  ////Set the whole JSON body text  from the trigger.
  var origonalMessage = triggerOutputs["body"].ToString();
  _origonalMessage = origonalMessage;

  ////Set the remote HMAC encripted text from the Azure header. (needs to be the input header)
  var receievedHmac = triggerOutputs?["headers"]?["HMACEncripted"]?.ToString();
  _origonalHmac = receievedHmac;

  ////Encript the body text with the local HMAC key and compaire with the remote Encripted text.
  //convert key and message to byte arrays
    byte[] keyBytes = Encoding.UTF8.GetBytes(secretKey);
    byte[] messageBytes = Encoding.UTF8.GetBytes(origonalMessage);

  //Create an HMAC SHA256 instance with the local key
    using (HMACSHA256 hmac = new HMACSHA256(keyBytes))
    {
        //Compute the HMAC and convert it to a string
        byte[] hashBytes = hmac.ComputeHash(messageBytes);
        var localHmac = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
    _calculatedHmac = localHmac;
  }

  //Compare the computed HMAC with the received HMAC
  string testString = "GAURAV";
  if (_calculatedHmac.Equals(receievedHmac, StringComparison.OrdinalIgnoreCase))
  {
    compare = "Match";
  }
  else
  {
    compare = "noMatch";
;
  }


  return new Results
  {
    Message = compare 
  };
}

public class Results
{
  public string Message {get; set;}
}

The rest of this works as expected apart from getting the key vault value. Is there a straightforward way to read the secret from the key vault?

I realise this is probably a very simple question but just can’t find anything relatable to the inline C# code when searching.
Any help would be appreciated.

2

Answers


    • Execute CSharp Script Code action in standard logic app is currently in preview and reference of some assemblies might not be supported at this moment.

    • I have used the Environment Variable approach to fetch the secret value from key vault.

    • In order to do so, first you need to grant the secret permissions to the logic app’s managed identity in key vault’s Access policies or you can grant RBAC role too.

    • Then, add the key vault reference in @Microsoft.KeyVault(SecretUri=https://{keyvaultName}.vault.azure.net/secrets/{secretName}) format as shown below.

    enter image description here

    enter image description here

    • Use the below given code in Execute CSharp Script Code action.
    #r "Newtonsoft.Json"
    #r "Microsoft.Azure.Workflows.Scripting"
    using Microsoft.Extensions.Logging;
    using Microsoft.Azure.Workflows.Scripting;
    using System;
    
    public static Results Run(WorkflowContext context, ILogger log)
    {
        string secretValue = GetEnvironmentVariable("HMACSecretKey");
    
        log.LogInformation($"Fetched Environment Variable: {secretValue}");
    
        return new Results
        {
            Message = $"The secret value is: {secretValue}"
        };
    }
    
    public static string GetEnvironmentVariable(string name)
    {
        return System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
    }
    
    public class Results
    {
        public string Message { get; set; }
    }
    
    • You will be able to get the secret value successfully.

    enter image description here

    Login or Signup to reply.
  1. Your approach is a very long winded way to get the secret value. LogicApps is a low code environment for a reason so why write code to do this?

    Firstly, use the first answer as a reference for how to setup the managed identity to have access to the keyvault and the secret, that’s number one.

    Now, rather than using the inline C# operation, you should just get the value directly via the appsetting function.

    https://techcommunity.microsoft.com/blog/integrationsonazureblog/programmatically-accessing-app-settings-from-logic-apps-expressions/3680407

    Literally just create the expression in a Compose or Initialize Variable operation.

    So for completion, create the environment variable using the reference notation as specified in the fourth point in the first answer and then you can use the appsetting function in an expression by simply passing in the name of that environment variable and it will give you the value.

    e.g. … appsetting('HMACKey')

    Additional reference … https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references?tabs=azure-cli

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search