• Microsoft,  Visual Studio 2017,  Visual Studio 2019

    Azure Logic App Development in Portal vs Visual Studio

    A funny thing happens when you move away from doing Prototype Azure Logic App all in the Portal to doing them in Visual Studio (where you are supposed to do Production develop). What’s funny… or is it annoying? Well, development life turns out is not the same.

    In the next few days I will be adding a small trip thought some things I notice between the two modes of development.

  • Microsoft

    The Azure Vault, PGP, and other matters Part 3

    Well if you are still hanging on… thanks and good job. We only have a bit more to go…. (you can go back to Part 1 or Part 2)

    Time to regroup as to where we are in the Big Picture:

    This is the flow of the Logic App. In Part 2 we just finished up the GetKeys block… so onto the Decryptor….

    Some more code of course as this is another Azure Function….

    public static class MHKPGPDecryptor
            public static async Task<IActionResult> Run(
                [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
                ILogger log)
                log.LogInformation($"C# HTTP trigger function {nameof(MHKPGPDecryptor)} processed a request.");
                string vaultKey = req.Query["privatekeysecretid"];
                string useVault = req.Query["useVault"];
                string privateKey = "";

    A familiar start to our Azure Function. Here we are placing two Query parameters:

      privatekeysecretid and useVault

    The privatekeysecretid contains the full PGP key we got from the vault. The second parameter is just a flag to tell the function if the privatekeysecretid  should used or not. I’ve made the private key value required, and the use vault is optional.

    When useVault is something like a “Yes”, the function will assume to use the privatekeysecretid as the actual PGP key. This is what all of this code is about:

                if (!String.IsNullOrEmpty(vaultKey))
                    log.LogInformation($"Vault key found privatekeysecretid");
                    log.LogInformation($"privatekeysecretid = is missing from the call. This must be provided!");
                    return new BadRequestObjectResult("Missing the paramenter privatekeysecretid. This must must have the private key.");
                if (!string.IsNullOrEmpty(useVault))
                    if (useVault.ToUpper().Contains("YES"))
                      privateKey = vaultKey;
                      log.LogInformation($"Using Key from the Vault.");
                      privateKey = @"-----BEGIN PGP PRIVATE KEY BLOCK-----
                                     Version: GnuPG v1.4.9 (MingW32)
                          //something secret is here....
                                     -----END PGP PRIVATE KEY BLOCK-----";
                        log.LogInformation($"Using Key from the internal store.");

    (Yes that’s me hard-coding a key into the function… well it’s test code get over it 😉).

    Now we have the key, what next? Let’s take a couple of steps back.

    The encrypted content in our adventure is sitting in the request body when this function is call (yeap I did not make that obvious because I’m about to go on about it).

    When the Decryptor function is called, this content is passed in. Dipping back to the Logic App:

    Notice the Request Body gets the File Content from the sFTP content. Also notice what privatekeysecretid gets. It is the Body content from the GetKeys function that was just called. **Now that’s an important matter. This is Content Scope… one should pause and think about what is being said here. It should be obvious to most who have done any Dot Net Core, MVC, and even for that matter any Web API’s (ok I’ll stop  beating on my drum about it, but put the wrong content in the wrong place and 😬).  

    Our next matter is the PGP parts… We have a Key… We have encrypted contain… Time to make it happen!

    First thing, you will need to add a NuGet Package to the Azure Function code. At the time or this post I’m using PgpCore v1.4.1:

    The Using are:

    The rest of the main method is:

        log.LogInformation("Now Decrypting the body");
        Stream decryptedData = await DecryptAsync(req.Body, privateKey, log);
        return new OkObjectResult(decryptedData);

    Here we call DecryptAsync. Followed up with the decrypted content going back to the Logic App with a 200.

    We have but one more method to do:

    private static async Task<Stream> DecryptAsync(Stream inputStream, string privateKey, ILogger log)
               log.LogInformation("So it begins...");
               using (PGP pgp = new PGP())
                   Stream outputStream = new MemoryStream();
                   Stream temp = new MemoryStream();
                   temp = GenerateStreamFromString("Place Holder for errors.");
                       using (inputStream)
                       using (Stream privateKeyStream = GenerateStreamFromString(privateKey))
                           log.LogInformation("Now it is done...");
                           await pgp.DecryptStreamAsync(inputStream, outputStream, privateKeyStream, "MY SUPER SECRET PASSPHRASE");
                           outputStream.Seek(0, SeekOrigin.Begin);
                           return outputStream;
                   catch (Exception ex)
                       log.LogInformation("Error Throw");
                       log.LogInformation($"This was {ex.Message}");
                       temp = GenerateStreamFromString("Stupid PGP errored: " + ex.Message.ToString());
                       temp.Seek(0, SeekOrigin.Begin);
                       return temp;
           private static Stream GenerateStreamFromString(string s)
               MemoryStream stream = new MemoryStream();
               StreamWriter writer = new StreamWriter(stream);
               stream.Position = 0;
               return stream;

    So PGP decrypt takes some content (as a stream), a key, and a passphrase for that key. Mostly super simple. This is all that the decyptor does.

    Now, one last step in our Logic App:

    We must output the content somewhere. Here I have a file share on a Azure storage account. This time the Body Content (which becomes our File Content) is the response from the PGPDecryptor.

    Wrapping it up….

    Can this be improved upon… But of course. For one matter the Pass Phrase should be passed into the Decryptor and should come from it’s own Vault possibly. This can be different (or at least it should be different) for each PGP key. There could be more error handling, and what about Encrypting? PGPCore the handy NuGet package also has methods for Encrypting and Encrypting/Signing.

    But I will leave those Matters for you to explore….

    If you need to go back Parts 1 & 2 are here Part 1 Part 2

    I hope this has been a help….


  • Microsoft

    The Azure Vault, PGP, and other matters Part 2

    Ok, where were we (Back to Part 1) … Ah, we are down to the PGP content in the Azure Vault getting ready to use it….

    At this point I gather you have created your vault and placed the middle contents of the PGP Key file into the secrets value…. Drilling into my Secret:

    We are going to use parts of this detail to pass along to the Get Keys Azure function – as a reminder we are here:

    My Azure function takes three values:

    SecretName, SecretVersion, and VaultPath. These values come from the URL that you find on the Secret Detail shown above.


    From the Overview of your Vault, under Settings you will find the Secrets link to get down into the detail window. You will need to click through some windows before you get to the Secret Identifier (the url to the secret). Keep in mind if you added addition key values you get a new Version id each time.

    So why do the GetKeys Azure Function this way? Easy, it’s generic. One can place as many PGP keys as needed in either the same vault or same secret and use just different versions of the secret – Or – create a new secret within the same vault – Or create different vaults (Keep in mind on that last choice, one must grant access to new vaults for this or other Azure Functions to be able to access it). What level of “Generic” is up to you, just know the access path.

    Let’s get to the interesting part, an Azure Function.

    public static class GetKeys
            public static async Task<IActionResult> Run(
                [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
                ILogger log)
                log.LogInformation("C# HTTP trigger function processed a request.");
                string nameVault = req.Query["VaultPath"];
                string nameSecret = req.Query["SecretName"];
                string versionSecret = req.Query["SecretVersion"];

    We start the Azure Function (using VS 2019) by naming it and setting up some Query vars on the Request. This Function is based on Dot Net Core 2.2.0 API. This is how the VaultPath, SecretName, and SecretVersion values come into the function.

    On the Logic App side, this the the Queries block:

      "SecretName": "<Get From the URL>",
      "SecretVersion": "<Get From the URL>",
      "VaultPath": "<Get From the URL>.vault.azure.net"

    This next spot of code takes these values and forms our url that is need to speak to the Vault:

    string secretKeyUrl = $"https://" + nameVault + $"/secrets/" + nameSecret + @"/" + versionSecret;

    To access the vault we need to get a provider token and setup a vault client:

        var azureServiceTokenProvider = new AzureServiceTokenProvider();
        var kvClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
        var keyValue = await kvClient.GetSecretAsync(secretKeyUrl).ConfigureAwait(false);

    The last statement here is where the async call is made into the value. Note my secret url is used here.

    If everything is happy in vault land, keyValue here will contain the secret (middle part of the PGP key that we pasted into the vault value). So we are good, right? Well almost. Remember that part I was going on about in Part 1? The PGP Key format? We have to fix that up now before passing it back to the Logic App.

    string privKey = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + "Version: GnuPG v1.4.9 (MingW32)\n\n";
    //must fix up the key to look like a real PGP key file
    // So why?
    //  The format of the key must be
    // Version: GnuPG v1.4.9(MingW32)[CRLF]
    // [CRLF]
    //   <key detail> [CRLF]
    //   <key detail2> [CRLF]
    //   <key detail3> [CRLF]
    // [CRLF]
    // -----END PGP PRIVATE KEY BLOCK-----
    //  The "vault" does not store the [CRLF] Gotta love that
    privKey = privKey + keyValue.Value.Replace(" ", "\n") + "\n-----END PGP PRIVATE KEY BLOCK-----";

    The comment section shows what we are trying to do here… take the value from the vault surround it with the PGP header/Trailer while putting back in the [CRLF]’s

    Yes, I agree this is a colossal load of crap, but this is what we have.

    The last part of the GetKeys function:

                return new OkObjectResult($"{privKey}");
            catch (Exception ex)
                log.LogInformation($"Error getting key from Vault: {keyUrl} Message: {ex.Message}");
                return (new BadRequestObjectResult($"GetKeys Error {ex.Message}"));

    Returns back the Ok (200) with the response body containing the PGP key content.

    In the end, it’s not too bad, and it does work…

    In last part, we will finish up by decrypting some stuff…. See in Part 3 (or go back to Part 1).


  • Microsoft

    The Azure Vault, PGP, and other matters Part 1

    Let’s step back into cloud space for a moment. I had this challenge to see if I could do some decrypting of partner files. A simple matter, well yes and no (it does have some interesting parts to deal with).

    First off, the files encrypted here are with PGP. Now this type of file protecting is not hard once you’ve gained an understanding of how to create and use keys. I’m not going to go into the deep end around PGP. There’s plenty of that for you to find on the internet. But I will need to mention a matter or two about how PGP key files are formatted and how they are used by some common PGP Nuget packages (more on that in a bit).

    Back up in the cloud for a little while….

    My design for getting encrypted partner files, decrypted them, and finally passing them along to downstream systems is simple for the most part. I use an Azure Logic App (a.k.a. a cloud work-flow) to handle the file movements and calling functions to decrypt (there are couple of Azure Functions to deal with the PGP Keys and Decrypting).

    So the general over all design is something like this:

    • Logic App triggered on a new file showing up on an sFTP site. The trigger runs on a timed interval.
    • Next, the Logic App brings in the file content and removes the file from the sFTP site.
    • We then get the decrypting key from a secrets store using an Azure Vault. This is done in a Azure Function.
    • Once we have a key and file content, we call another Azure Function to decrypt the content.
    • And finally, the decrypted content is pushed back out to a file.

    Basic and mostly straight forward… Shall we begin….

    Starting with our connector:

    This is sFTP connector… I have /out folder where I start looking for files every 3 minutes..

    Next Action filter on the filename with a Control:

    Now I know my files end in a .asc, so I will only grab those using the Control Conditional (yes, I probably should .Upper the filename to cover all bases, but one must leave room for improvements). That “List of Fil… btw is “List of Files Path” Dynamic content from the sFTP connector.

    This gives us our True/False choices:

    The “True” is where we want to go to do processing the file, of course. But what about the False side? We get here because, while we detected a file landing or changing on our sFTP folder, it did not meet our requirement that the filename contain a .asc. Big deal, right? Well, think about it. This may not be a problem, but if somewhere down the road one starts getting complaints about files not arriving… would it not be nice to have some historical trail when crap happened? At the end of the day the False side is optional, but why start out with throwing away events that may be important at some point?

    This is where the cloud (Azure) makes life really easy… lets just push a false note to a Queue. Again, I’m not going to dive into creating a Storage account and creating a queue in that storage account – this is simple enough with a little reading and doing. But needless to say you will need a storage account and queue to do the following in the False:

    Once you create a connection to your storage account, the available queues within that storage will show up in the drop down. Now what you push into the queue is up to your choice. Here I’m putting my False note into some jason. I’ve also added a couple of Dynamic values… the “List Of Files Name” gives us the the filename from sFTP, and then we get the system timestamp.

    Now the True side is good bit more interesting of course, because there’s something to do:

    The top block is where we must get the file content. This is encrypted as this point. Once we have the content, we should delete the file on the sFTP server:

    The “Put a message on the queue” side executes only if we cannot get the content. The “Run After” is set if Get Content “Has” anything except is successful so:

    This way the App will not continue nor will it delete the file from the sFTP server.

    Next we have the magic… Get the keys from Azure Vault:

    Now setting up a secret in the vault comes down to several steps…. You must:

    • Create a Key Vault
    • Create a Secrets in the Vault using the PGP file as the Secret content.
    • Provide access to the vault

    The only step in building the vault that is tricky is knowing what to put in the secrets value to get PGP to work…

    Consider the ascii format of a PGP key:

                    —–BEGIN PGP PRIVATE KEY BLOCK—– [CRLF]
                   Version: GnuPG v1.4.9(MingW32)[CRLF]  – this line is optional
                    <key detail> [CRLF]
                    <key detail2> [CRLF]
                    <key detail3> [CRLF]
                    —–END PGP PRIVATE KEY BLOCK—-

    Nope, I’m not making that up….  PGP, and more precisely the NuGet Packages for handling PGP are fussy about how the PGP key file is formatted. Trust me the PGP code will not be able to find the key if you don’t get the format correct. And there lies the problem with the Azure Vault.

    It’s not really a problem… if you understand what is going on. If one uses the Web Portal to insert the secrets value, then understand that the [CRLF] are stripped from the cut/paste of the value. Yes, PGP does not like that. So what is the trick? The part of the key file to paste into the secret value is:

                    <key detail> [CRLF]
                    <key detail2> [CRLF]
                    <key detail3> [CRLF]

    The middle part of the key. One will find that the [CRLF] become a space (yes that is problem, but one that can be dealt with in the Azure Function :))

    ** I’m going to stop here for now… and make a Part 2 of this. We will pick up with the Azure Get keys function that deals with the PGP key from the secrets.

    On to Part 2