New to Kestra?
Use blueprints to kickstart your first workflows.
Audit Azure Logic Apps workflows for required tags and Disabled state on a schedule and alert Slack with the exact violations.
A Logic App workflow created without the governance tags a FinOps or security policy
requires does not fail loudly, it just sits there unattributed, invisible to cost reports
and ownership audits until someone goes looking resource group by resource group. A
workflow someone disabled during an incident and never re-enabled looks identical to one
that was deliberately retired. List already returns every workflow's real state and
tags, this blueprint is what reads that report on a schedule and turns it into an alert
naming the exact workflow and the exact tag keys missing.
probe_workflows (io.kestra.plugin.azure.logicapps.List) lists every workflow in
resource_group_name, up to max_workflows, with its real state and tags, with
allowFailure: true so a bad credential or resource group does not stop the flow
before it can be classified as PROBE_FAILED below.audit_workflow_governance (io.kestra.plugin.core.output.OutputValues) computes, per
workflow, which of required_tags are missing from its tags map, and whether its
state is exactly Disabled. A workflow is flagged if it fails tag_check_mode's
missing-tag rule, or if flag_disabled_workflows is true and it is Disabled, either
condition alone is enough.classify_governance_status (io.kestra.plugin.core.debug.Return) returns
PROBE_FAILED when probe_workflows produced no output at all, CRITICAL or
WARNING depending on whether the flagged count meets
violation_count_critical_threshold, or COMPLIANT when there are none.route_by_governance_status (io.kestra.plugin.core.flow.Switch) branches on that
status: COMPLIANT logs it, WARNING, CRITICAL, and PROBE_FAILED each alert Slack
with the exact workflow names, their missing tag keys, and whether they are Disabled,
never an invented count.log_audit_summary always runs last and logs the final classification.errors block posts to Slack if the flow itself fails outside the gate logic above.tag_check_mode) and whether Disabled
workflows matter at all for a given resource group (flag_disabled_workflows).logicapps.List and the real WorkflowRecord shape it returns.List is a single point-in-time read, Azure Logic Apps itself has no concept of a
schedule, a tagging policy, or an alert built from what it finds missing. Kestra adds the
recurring audit, the tag completeness check, the Disabled-state check, and a Slack alert
built only from the workflows' own reported state and tags, all as one declarative YAML
file you can version and review like code.
Microsoft.Logic/workflows/read permission (roles/Logic App Contributor or a reader
role is enough, this blueprint only reads).taskRunner and no
Docker network to join.AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID:
service principal credentials used by probe_workflows.
SLACK_WEBHOOK: Slack incoming webhook URL used by the alert tasks and the errors
block.
In Kestra OSS, set all five as base64-encoded environment variables, for example
SECRET_AZURE_TENANT_ID, SECRET_AZURE_SUBSCRIPTION_ID, SECRET_SLACK_WEBHOOK.
| Input | Type | Default | Allowed values |
|---|---|---|---|
resource_group_name |
STRING | logic-apps-rg |
any Azure resource group name |
required_tags |
JSON | ["owner", "cost-center", "environment"] |
JSON array of tag keys |
tag_check_mode |
SELECT | any_required_missing |
any_required_missing, all_required_missing |
flag_disabled_workflows |
BOOL | true |
true, false |
max_workflows |
INT | 100 |
any positive integer |
violation_count_critical_threshold |
INT | 5 |
any non-negative integer |
SLACK_WEBHOOK secrets.resource_group_name to a real resource group and required_tags to your actual
tagging policy's keys.log_audit_summary for the result.flag_disabled_workflows: false for a resource group where Disabled workflows are
expected and not a concern.daily trigger.environment to be
exactly prod, staging, or dev, by extending the jq filter in
audit_workflow_governance.CRITICAL that opens a ticket per flagged workflow with
its name and missing tags already filled in, instead of only one Slack message.tags comes back as an empty map, not null, for an untagged workflow, in the audit this
correctly counts as missing every required tag, confirm that is the behavior you want
before enabling all_required_missing on a resource group with many legitimately
untagged legacy workflows.List returns workflows in whatever order the Azure Resource Manager API returns them,
not alphabetically or by creation time, do not assume the first max_workflows results
are the newest ones.Disabled here means the Logic Apps-level trigger is turned off, it does not mean the
workflow definition was deleted, a Disabled workflow still exists, still carries cost
for any static resources it owns, and still needs the same tags.