> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Track Azure resource tagging compliance

This guide demonstrates how to implement an Azure resource tagging initiative in Port. You will learn how to:

  • Create a blueprint with calculated properties to detect missing tags.
  • Set up a scorecard to track tagging compliance at Bronze, Silver, and Gold levels.
  • Build a self-service action to let teams add missing tags directly from Port.
  • Create a dashboard to visualize compliance across your Azure resources.
Implement with AI

Send this guide to your coding agent.

Prerequisite: Install Port MCP

Open plan mode if your tool supports it; otherwise present the plan below filled in and wait for my approval. Implement this Port guide in my org via MCP:

https://docs.port.io/guides/all/azure-resource-tagging-initiative

Read the raw markdown version at https://docs.port.io/guides/all/azure-resource-tagging-initiative.md - it contains every tab and code block without page markup.

Goal: get the guide's core flow working end-to-end in my org; adapting it to fit my existing setup takes priority over matching the guide 1:1.

Plan:
1. Confirm MCP is connected, in the right org, with sufficient permissions.
2. If the guide offers alternative implementation paths (tabs), pick the one matching my installed integrations and tools, confirm it with me, and implement only that path.
3. Diff the guide's data model (blueprints, properties, relations, workflows, actions, agents, automations, integrations, webhook data sources, secrets) against mine.
4. Propose adaptations for gaps, reusing existing blueprints/relations over guide-named duplicates.
5. Flag what needs a UI click, credential, or secret from me, testing MCP capability empirically before ruling anything out. If the guide has a "Set up via API" section, use it for anything MCP can't do before treating a step as UI-only.
6. Stop on any blocker and give me options. Approving this plan authorizes the writes it lists; pause only for writes beyond what's listed.

Build:
- Extend blueprint schema additively when upserting; don't remove or overwrite existing properties, and treat type conflicts as a blocker, not an auto-fix.
- Never print secret values into the chat or logs; ask me to set them in Port, or write them via the secrets API without echoing them back.
- List any mock data in the plan, minimal and labeled mock; once approved, seed it without re-asking, and tell me what you seeded.
- For anything the guide writes downstream (e.g. a webhook target), use a real entity, not a mock.
- For pages/widgets, use the real page identifier from the app URL, not a guessed slug.
- When you hit a UI step confirmed (not assumed) unsupported via MCP and not covered by the guide's API sections, pause, give exact clicks, then resume via MCP.
- Validate and give links after each meaningful step (only a tool-returned URL, no guessed paths); don't proceed if the last run wasn't a success.

Done:
- Run the guide's "Let's test it" steps where possible (e.g. execute a workflow test run) and confirm the expected output exists in Port.
- Summarize adaptations, seeded data, what was mocked or skipped, remaining UI steps, and how to verify.
Available GitHub integrations

This guide includes steps that require integration with GitHub:

  • GitHub (Ocean) - uses the Ocean framework. We strongly recommend this integration for new and migrated setups.
  • GitHub (Sunset) - uses a GitHub app that is in sunset and will be fully deprecated on September 15, 2026.
Azure Resource Tagging compliance dashboard

Common use cases

  • Track which Azure resources are missing required tags for cost attribution.
  • Enable teams to self-remediate tagging gaps without waiting for platform engineers.
  • Report on tagging compliance progress across subscriptions and resource groups.
  • Add or update tags on a single Azure resource directly from its Port entity page.

Prerequisites

This guide assumes the following:

Dedicated Workflows Repository

We recommend creating a dedicated repository for the workflows that are used by Port actions.

Set up data model

We will create a blueprint to represent Azure resources with calculated properties that check for the presence of required tags.

This initiative uses three compliance levels:

  • Bronze: owner, cost-center, environment tags (mandatory).
  • Silver: Adds project and application tags (recommended).
  • Gold: All tags present (full compliance).

Create the Azure resource blueprint

  1. Go to the Builder page in Port.

  2. Click on + Blueprint.

  3. Click Edit JSON.

  4. Copy and paste the following JSON configuration into the editor:

    Azure resource blueprint (Click to expand)
    {
    "identifier": "azureResource",
    "title": "Azure Cloud Resource",
    "icon": "Azure",
    "schema": {
    "properties": {
    "type": {
    "title": "Resource Type",
    "type": "string"
    },
    "location": {
    "title": "Location",
    "type": "string"
    },
    "tags": {
    "title": "Tags",
    "type": "object"
    },
    "resourceGroup": {
    "title": "Resource Group",
    "type": "string"
    },
    "subscriptionId": {
    "title": "Subscription ID",
    "type": "string"
    }
    }
    },
    "calculationProperties": {
    "hasOwnerTag": {
    "title": "Has Owner Tag",
    "type": "boolean",
    "calculation": ".properties.tags.owner != null"
    },
    "hasCostCenterTag": {
    "title": "Has Cost Center Tag",
    "type": "boolean",
    "calculation": ".properties.tags.\"cost-center\" != null"
    },
    "hasEnvironmentTag": {
    "title": "Has Environment Tag",
    "type": "boolean",
    "calculation": ".properties.tags.environment != null"
    },
    "hasProjectTag": {
    "title": "Has Project Tag",
    "type": "boolean",
    "calculation": ".properties.tags.project != null"
    },
    "hasApplicationTag": {
    "title": "Has Application Tag",
    "type": "boolean",
    "calculation": ".properties.tags.application != null"
    }
    },
    "mirrorProperties": {},
    "relations": {}
    }
  5. Click Save to create the blueprint.

Update the integration mapping

  1. Go to the Data sources page in Port.

  2. Select your Azure integration.

  3. Add the following YAML block into the editor to ingest Azure resources with their tags:

    Azure integration configuration (Click to expand)
    resources:
    - kind: resource
    selector:
    query: 'true'
    graphQuery: >-
    resources
    | project id, type, name, location, tags, subscriptionId, resourceGroup
    | extend resourceGroup=tolower(resourceGroup)
    | extend type=tolower(type)
    port:
    entity:
    mappings:
    identifier: .id | gsub(" ";"_")
    title: .name
    blueprint: '"azureResource"'
    properties:
    tags: .tags
    type: .type
    location: .location
    resourceGroup: .resourceGroup
    subscriptionId: .subscriptionId
  4. Click Save & Resync to apply the mapping.

Set up the tagging scorecard

Now let's create a scorecard to evaluate tagging compliance at different levels.

  1. Go to the Builder page in Port.

  2. Search for the Azure Cloud Resource blueprint and select it.

  3. Click the Scorecards tab, then click + New Scorecard.

  4. Click on the {...} button in the top right corner, and choose Edit JSON.

  5. Paste the following JSON configuration:

    Tagging compliance scorecard (Click to expand)
    {
    "identifier": "azure_tagging_compliance",
    "title": "Azure Resource Tagging Compliance",
    "levels": [
    {
    "color": "paleBlue",
    "title": "Basic"
    },
    {
    "color": "bronze",
    "title": "Bronze"
    },
    {
    "color": "silver",
    "title": "Silver"
    },
    {
    "color": "gold",
    "title": "Gold"
    }
    ],
    "rules": [
    {
    "identifier": "has_owner_tag",
    "title": "Has owner tag",
    "level": "Bronze",
    "query": {
    "combinator": "and",
    "conditions": [
    {
    "operator": "=",
    "property": "hasOwnerTag",
    "value": true
    }
    ]
    }
    },
    {
    "identifier": "has_cost_center_tag",
    "title": "Has cost center tag",
    "level": "Bronze",
    "query": {
    "combinator": "and",
    "conditions": [
    {
    "operator": "=",
    "property": "hasCostCenterTag",
    "value": true
    }
    ]
    }
    },
    {
    "identifier": "has_environment_tag",
    "title": "Has environment tag",
    "level": "Bronze",
    "query": {
    "combinator": "and",
    "conditions": [
    {
    "operator": "=",
    "property": "hasEnvironmentTag",
    "value": true
    }
    ]
    }
    },
    {
    "identifier": "has_project_tag",
    "title": "Has project tag",
    "level": "Silver",
    "query": {
    "combinator": "and",
    "conditions": [
    {
    "operator": "=",
    "property": "hasProjectTag",
    "value": true
    }
    ]
    }
    },
    {
    "identifier": "has_application_tag",
    "title": "Has application tag",
    "level": "Silver",
    "query": {
    "combinator": "and",
    "conditions": [
    {
    "operator": "=",
    "property": "hasApplicationTag",
    "value": true
    }
    ]
    }
    },
    {
    "identifier": "full_compliance",
    "title": "Full tag compliance",
    "level": "Gold",
    "query": {
    "combinator": "and",
    "conditions": [
    {
    "operator": "=",
    "property": "hasOwnerTag",
    "value": true
    },
    {
    "operator": "=",
    "property": "hasCostCenterTag",
    "value": true
    },
    {
    "operator": "=",
    "property": "hasEnvironmentTag",
    "value": true
    },
    {
    "operator": "=",
    "property": "hasProjectTag",
    "value": true
    },
    {
    "operator": "=",
    "property": "hasApplicationTag",
    "value": true
    }
    ]
    }
    }
    ]
    }
  6. Click Save.

Set up self-service action

Now let's create a self-service action to allow teams to add missing tags directly from Port. Follow the steps below to create the action:

Choose the action configuration that matches the workflow implementation you will create later in this guide.

  1. Go to the Self-service page in Port.

  2. Click on the + New Action button.

  3. Click on the {...} Edit JSON button.

  4. Copy and paste the following JSON configuration into the editor.

    Use this action with the Azure CLI workflow. It exposes the compliance fields used by the scorecard and dashboard.

    Azure CLI action (Click to expand)
    Replace the variables
    • <GITHUB-ORG> - your GitHub organization or user name.
    • <GITHUB-REPO> - your GitHub repository name.
    • <YOUR_GITHUB_OCEAN_INTEGRATION_ID> - your GitHub Ocean integration installation ID.
    {
    "identifier": "add_tags_to_azure_resource",
    "title": "Add tags to Azure resource",
    "icon": "Azure",
    "description": "Add or update tags on an Azure resource to improve compliance",
    "trigger": {
    "type": "self-service",
    "operation": "DAY-2",
    "userInputs": {
    "properties": {
    "owner": {
    "title": "Owner",
    "type": "string",
    "description": "Team or individual responsible for this resource"
    },
    "cost_center": {
    "title": "Cost Center",
    "type": "string",
    "description": "Financial cost center for billing"
    },
    "environment": {
    "title": "Environment",
    "type": "string",
    "enum": ["production", "staging", "development", "sandbox"],
    "description": "Deployment environment"
    },
    "project": {
    "title": "Project",
    "type": "string",
    "description": "Project or initiative name"
    },
    "application": {
    "title": "Application",
    "type": "string",
    "description": "Application or service name"
    }
    },
    "required": ["owner", "cost_center", "environment"],
    "order": ["owner", "cost_center", "environment", "project", "application"]
    },
    "blueprintIdentifier": "azureResource"
    },
    "invocationMethod": {
    "type": "INTEGRATION_ACTION",
    "installationId": "<YOUR_GITHUB_OCEAN_INTEGRATION_ID>",
    "integrationActionType": "dispatch_workflow",
    "integrationActionExecutionProperties": {
    "org": "<GITHUB-ORG>",
    "repo": "<GITHUB-REPO>",
    "workflow": "tag-azure-resource.yml",
    "workflowInputs": {
    "owner": "{{ .inputs.owner }}",
    "cost_center": "{{ .inputs.cost_center }}",
    "environment": "{{ .inputs.environment }}",
    "project": "{{ .inputs.project }}",
    "application": "{{ .inputs.application }}",
    "port_context": {
    "runId": "{{ .run.id }}",
    "entity": "{{ .entity }}"
    }
    },
    "reportWorkflowStatus": true
    }
    },
    "requiredApproval": false
    }
  5. Click Save to create the action.

Create the GitHub workflow

Before creating the GitHub workflow, add the following Port secrets to your GitHub repository:

Choose the workflow implementation that matches how you manage Azure resources:

Use this path to update tags directly on any Azure resource using its Azure resource ID.

Add the following secret to your GitHub repository:

  • AZURE_CREDENTIALS - Azure service principal credentials in JSON format.

    Azure credentials secret format (Click to expand)
    {
    "clientSecret": "<AZURE_CLIENT_SECRET>",
    "subscriptionId": "<AZURE_SUBSCRIPTION_ID>",
    "tenantId": "<AZURE_TENANT_ID>",
    "clientId": "<AZURE_CLIENT_ID>"
    }

The action tags a single Azure resource when you run it from that resource's entity page, and it supports broader compliance remediation from the dashboard.

Create the file .github/workflows/tag-azure-resource.yml in the .github/workflows folder of your repository with the following content:

GitHub workflow (Click to expand)
name: Add tags to Azure resource

on:
workflow_dispatch:
inputs:
owner:
required: true
type: string
cost_center:
required: true
type: string
environment:
required: true
type: string
project:
required: false
type: string
application:
required: false
type: string
port_context:
required: true
type: string

jobs:
add-tags:
runs-on: ubuntu-latest
steps:
- name: Inform Port of workflow start
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
baseUrl: https://api.port.io
operation: PATCH_RUN
runId: ${{ fromJson(inputs.port_context).runId }}
logMessage: Starting to add tags to Azure resource ${{ fromJson(inputs.port_context).entity.title }}

- name: Azure Login
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Add tags to resource
uses: azure/CLI@v1
env:
RESOURCE_ID: ${{ fromJson(inputs.port_context).entity.identifier }}
with:
azcliversion: latest
inlineScript: |
TAGS="owner=${{ inputs.owner }}"
TAGS="$TAGS cost-center=${{ inputs.cost_center }}"
TAGS="$TAGS environment=${{ inputs.environment }}"

if [ -n "${{ inputs.project }}" ]; then
TAGS="$TAGS project=${{ inputs.project }}"
fi

if [ -n "${{ inputs.application }}" ]; then
TAGS="$TAGS application=${{ inputs.application }}"
fi

az tag update --resource-id "$RESOURCE_ID" --operation merge --tags $TAGS

- name: Inform Port about success
if: success()
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
baseUrl: https://api.port.io
operation: PATCH_RUN
runId: ${{ fromJson(inputs.port_context).runId }}
status: 'SUCCESS'
logMessage: ✅ Successfully added tags to ${{ fromJson(inputs.port_context).entity.title }}
summary: Tags added successfully

- name: Inform Port about failure
if: failure()
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
baseUrl: https://api.port.io
operation: PATCH_RUN
runId: ${{ fromJson(inputs.port_context).runId }}
status: 'FAILURE'
logMessage: ❌ Failed to add tags to ${{ fromJson(inputs.port_context).entity.title }}
summary: Failed to add tags

Visualize tagging compliance

With your data, scorecard, and action in place, let's create a dashboard to visualize tagging compliance across your Azure resources.

Create a dashboard

  1. Navigate to the Catalog page in Port.

  2. Click on the + button in the left sidebar.

  3. Select New dashboard.

  4. Name the dashboard Azure Resource Tagging.

  5. Input Track tagging compliance across Azure resources under Description.

  6. Select the Azure icon.

  7. Click Create.

Add widgets

In the new dashboard, create the following widgets:

Total resources (Click to expand)
  1. Click + Widget and select Number chart.

  2. Title: Total resources (add the Azure icon).

  3. Select Count entities Chart type and choose Azure Cloud Resource as the Blueprint.

  4. Select count for the Function.

  5. Click Save.

Compliance by level (Click to expand)
  1. Click + Widget and select Pie chart.

  2. Title: Compliance by level (add the Azure icon).

  3. Choose the Azure Cloud Resource blueprint.

  4. Under Breakdown by property, select the Azure Resource Tagging Compliance scorecard.

  5. Click Save.

Resources needing attention (Click to expand)
  1. Click + Widget and select Table.

  2. Title: Resources needing attention (add the Azure icon).

  3. Choose the Azure Cloud Resource blueprint.

  4. Click Save to add the widget to the dashboard.

  5. Click on the ... button in the top right corner of the table and select Customize table.

  6. Click on the filter icon and add a filter where Azure Resource Tagging Compliance equals Basic.

  7. In the top right corner of the table, click on Manage Properties and add: Title, Resource Type, Location, Tags.

  8. Click on the save icon in the top right corner of the widget.

Resources by environment (Click to expand)
  1. Click + Widget and select Pie chart.

  2. Title: Resources with environment tag (add the Azure icon).

  3. Choose the Azure Cloud Resource blueprint.

  4. Under Breakdown by property, select Environment (from the tags property).

  5. Click Save.

Resources by type (Click to expand)
  1. Click + Widget and select Pie chart.

  2. Title: Resources by type (add the Azure icon).

  3. Choose the Azure Cloud Resource blueprint.

  4. Under Breakdown by property, select Resource Type.

  5. Click Save.

Add tags action card (Click to expand)
  1. Click + Widget and select Action card.

  2. Choose the Add tags to Azure resource action we created in this guide.

  3. Click Save.

Extend the tagging initiative

Once you have the basic tagging initiative in place, consider these enhancements:

Automate notifications

Create an automation to notify teams via Slack when new resources are created without required tags:

Slack notification automation (Click to expand)
{
"identifier": "notify_untagged_resources",
"title": "Notify on Untagged Azure Resources",
"trigger": {
"type": "automation",
"event": {
"type": "ENTITY_CREATED",
"blueprintIdentifier": "azureResource"
},
"condition": {
"type": "JQ",
"expressions": [
".diff.after.properties.tags.owner == null"
]
}
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "<SLACK_WEBHOOK_URL>",
"body": {
"text": "⚠️ New Azure resource created without required tags!\n*Resource:* {{ .event.diff.after.title }}\n*Type:* {{ .event.diff.after.properties.type }}"
}
}
}

Define enforcement strategies

Consider implementing enforcement at different levels:

  • Awareness: Make dashboards visible to all teams, send weekly compliance reports.
  • Accountability: Include compliance metrics in team reviews and leadership reports.
  • Prevention: Use Azure Policy to deny resource creation without required tags.

Measure success metrics

Monitor these KPIs to measure your initiative's progress:

MetricTarget
Bronze compliance100% within 30 days
Silver compliance80% within 60 days
Gold compliance50% within 90 days
Cost attribution coverage95%+ of cloud spend

More relevant guides