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 querystringctx.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
:
Head back to the Azure portal and you'll see the status of the job, the input values and the Runbook output:
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).