List icon
OutputValues icon
Return icon
Switch icon
Log icon
SlackIncomingWebhook icon
Schedule icon

Logic Apps Workflow Tag Compliance Gate

Audit Azure Logic Apps workflows for required tags and Disabled state on a schedule and alert Slack with the exact violations.

Categories
CloudInfrastructure

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.

How it works

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. log_audit_summary always runs last and logs the final classification.
  6. The errors block posts to Slack if the flow itself fails outside the gate logic above.

What you get

  • A real list of which workflows are missing governance tags and which are sitting Disabled, not an assumption that tagging policy was followed at creation time.
  • A Slack alert naming the exact workflow and the exact missing tag keys, never an invented number.
  • A choice of how strict the tag check is (tag_check_mode) and whether Disabled workflows matter at all for a given resource group (flag_disabled_workflows).

Who it's for

  • Platform and FinOps teams enforcing a tagging policy across Azure resources who need proof Logic Apps workflows actually comply, not just the resources a cost report happens to surface.
  • Teams running a lot of Logic Apps who want to catch a workflow that was disabled during an incident and never re-enabled, before it is noticed by a user instead of an audit.
  • Teams evaluating the Logic Apps plugin who want a working example of logicapps.List and the real WorkflowRecord shape it returns.

Why orchestrate this with Kestra

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.

Prerequisites

  • An Azure resource group containing Logic App workflows, and a service principal with Microsoft.Logic/workflows/read permission (roles/Logic App Contributor or a reader role is enough, this blueprint only reads).
  • A Slack incoming webhook for alerts.
  • Logic Apps is a managed Azure service with no self-hostable open-source emulator, there is no local container to start for it. This plugin calls the Azure Resource Manager API directly from the Kestra worker process, there is no sub-container taskRunner and no Docker network to join.

Secrets

  • 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.

Inputs

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

Quick start

  1. Add the Azure and SLACK_WEBHOOK secrets.
  2. Set resource_group_name to a real resource group and required_tags to your actual tagging policy's keys.
  3. Run this flow manually and read log_audit_summary for the result.
  4. Set flag_disabled_workflows: false for a resource group where Disabled workflows are expected and not a concern.
  5. Enable the daily trigger.

How to extend

  • Check tag values, not just key presence, for example requiring environment to be exactly prod, staging, or dev, by extending the jq filter in audit_workflow_governance.
  • Add a second probe for a second resource group and reuse the same classification logic to audit a whole subscription's worth of Logic Apps from one flow.
  • Chain a downstream task after CRITICAL that opens a ticket per flagged workflow with its name and missing tags already filled in, instead of only one Slack message.

Pitfalls

  • 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.
  • This blueprint never changes a tag or a workflow's state, there is no remediation task in the Logic Apps plugin for either, the fix has to be applied in the Azure portal, CLI, or your infrastructure-as-code pipeline.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.