Quantcast
Channel: Fabric Controller
Viewing all articles
Browse latest Browse all 19

Create advanced webhooks for Azure Automation with a Webtask

$
0
0
Create advanced webhooks for Azure Automation with a Webtask

Azure Automation already supports webhooks but these are currently scoped to a single runbook. This post explains how you can use a Webtask to send secret settings (encrypted), internal settings (which the caller of the webhook cannot change) and also public settings to your Runbook. These public settings allow you to:

  • Specify values (eg: the name of the runbook) in the querystring
  • Specify values in the POST body

The goal here is that we can create a webhook that would work like this:

https://webtask.it.auth0.com/api/run/YOUR_CONTAINER/my-webhook?RUNBOOK_NAME=Sample-Runbook&some_value=123  

This would then run Sample-Runbook with these parameters: some_value=123

Prerequisites

You'll need an Automation Account and a Runbook (make sure you also publish it!). Here's a sample Runbook you can use:

workflow Sample-Runbook  
{
   param ([Parameter(Mandatory=$false)][object]$context)
    # Context which was sent to the runbook.
    if ($context) {
        $body = ConvertTo-Json -InputObject $context 
        Write-Output "You sent: ${body}"
    } else {
        Write-Output "You did not send anything."
    }

    # Get the credential.
    $credentialName = 'DefaultAzureCredential'
    $credential = Get-AutomationPSCredential -Name $credentialName
    if(!$credential) {
        Throw "Could not find an Automation Credential Asset named '${credentialName}'. Make sure you have created one in this Automation Account."
    }

    # Connect to your Azure Account
    $account = Add-AzureAccount -Credential $credential
    if(!$account) {
        Throw "Could not authenticate to Azure using the credential asset '${credential}'. Make sure the user name and password are correct."
    }

    # Return Subscription
    $subscription = Get-AzureSubscription -Default
    $subscriptionBody = ConvertTo-Json -InputObject $subscription
    Write-Output "Your default Azure subscription is: ${subscriptionBody}"
}

Note that the $context parameter here is important, as the Webtask will send everything over in the context parameter (JSON object).

The Webtask

The full source of the Webtask is available on Github.

This Webtask will do a few things:

  • Validate that we have all the settings we need
  • Authenticate with Azure AD
  • Then talk to the Resource Manager API to start the Runbook
  • Return the details of the job (eg: ID, etc...)

Here is the most important part of the code:

  const internalSettings = {
    resourceGroup: "lab",
    automationAccount: "automation-lab"
  };

  authenticate(ctx.data.AD_TENANT_ID, ctx.data.AD_CLIENT_ID, ctx.data.AD_SERVICE_PRINCIPAL_PASSWORD, (err, accessToken) => {
    if (err) {
      return done({
        message: 'Error authenticating.',
        err: err
      });
    }

    const jobId = uuid.v4();
    const parameters = _.extend({ }, ctx.query, { 
        someInternalValue: 1,
        someSecretValue: ctx.data.AD_CLIENT_ID
    });

    const req = {
      properties: {
        runbook: {
           name: ctx.query.RUNBOOK_NAME
        },
        parameters: {
           context: JSON.stringify(parameters),
           MicrosoftApplicationManagementStartedBy: "\"A Webtask\""
        }
      },
      tags: {}
    };

    const path = `/providers/Microsoft.Automation/automationAccounts/${internalSettings.automationAccount}/jobs/${jobId}?api-version=2015-01-01-preview`
    sendRequest(accessToken, ctx.data.AZURE_SUBSCRIPTION_ID, internalSettings.resourceGroup, path, req, (err, body) => {
      if (err) {
        console.log('Error starting Runbook:', err.message || JSON.stringify(err, null, 2));
        return done({ err: err });
      }

      console.log(`Success: ${JSON.stringify(body, null, 2)}`)
      return done(null, body);
    });
  });

As you can see, parameters which are sent to the Runbook are populated with:

  • ctx.query: Values from the querystring
  • ctx.data.AD_CLIENT_ID: A secret value which is encrypted in the Webtask
  • A hardcoded value

And that's basically it.

Deployment

Download task.js from this repository and change it to match your needs:

  • internalSettings: This should reflect your environment (Resource Group name, ...)
  • parameters: This is the final payload which is sent to the Runbook. You can add any values you want here. Everything from the querystring is added by default.

Once your task is ready you can go ahead and deploy it (on Windows you might have to wrap the wt create command in a single line):

npm i -g wt-cli  
wt init  
wt create task.js \  
    --name some-random-name-that-is-hard-to-guess \
    --secret AD_TENANT_ID="YOUR_TENANT_ID" \
    --secret AD_CLIENT_ID="YOUR_CLIENT_ID" \
    --secret AD_SERVICE_PRINCIPAL_PASSWORD="SP_PASSWORD" \
    --secret AZURE_SUBSCRIPTION_ID="YOUR_SUBSCRIPTION_ID"

Note: This blog post explains how you can create a Service Principal and access these values.

Usage

After creating the Webtask the wt-cli will return the URL of my Webtask and I can just go ahead and hit it using Postman for example (notice the query string values and how they are passed along in the parameters.context:

Create advanced webhooks for Azure Automation with a Webtask

Head back to the Azure portal and you'll see the status of the job, the input values and the Runbook output:

Create advanced webhooks for Azure Automation with a Webtask

What's next?

Well... a Slack integration of course. Creating a Slash command is pretty easy, but let's see if we can do something that reports the status of the job (even for long running processes).


Viewing all articles
Browse latest Browse all 19

Trending Articles