Set up Just-in-Time VM access policies, configure adaptive application controls, enable file integrity monitoring, create workflow automations for auto-remediation, and build a monitoring dashboard for healthcare VM environments.
Just-in-Time (JIT) VM access reduces the attack surface by closing management ports on Azure VMs and opening them only when an administrator needs access for a defined time window. Adaptive application controls use machine learning to recommend application allowlists for your VMs, blocking unauthorized executables from running on production workloads. File Integrity Monitoring (FIM) tracks changes to critical system files, registry keys, and configuration files, alerting you when unexpected modifications occur. Workflow automation with Logic Apps enables auto-remediation of security alerts, closing the loop between detection and response without manual intervention. In this lab you will configure all four capabilities across a fleet of Azure VMs and build a unified monitoring dashboard.
Scenario: MedSecure Health operates 150 Azure VMs across three regions handling electronic health records (EHR) and patient billing data subject to HIPAA regulations. System administrators require RDP and SSH access during scheduled maintenance windows but management ports must remain closed at all other times to satisfy audit requirements.
The security team needs to ensure only approved healthcare applications run on production VMs, preventing unauthorized software installations by clinical staff. Compliance auditors require evidence that critical system files on patient-facing servers have not been tampered with between audit cycles. The SOC team wants automated responses when a JIT access request is denied or when an unapproved application attempts to execute.
Success criteria: JIT access configured on all 150 VMs, adaptive application controls enforced, FIM active on patient data servers, and automated remediation workflows operational.
JIT VM Access and Adaptive Controls are critical for enterprise security because they enforce the principle of least privilege at the network and application layers. Open management ports are among the most exploited attack vectors, and JIT eliminates persistent exposure by granting time-limited access only when needed. Adaptive application controls prevent unauthorized software from executing on production workloads, reducing the risk of malware, ransomware, and insider threats. Combined with File Integrity Monitoring and workflow automation, these capabilities create a closed-loop defense that detects, prevents, and remediates threats without manual intervention. essential for regulated industries like healthcare where compliance evidence must be continuous and auditable.
Just-in-Time VM access is a Defender for Cloud feature that locks down inbound traffic to management ports on Azure VMs. When an administrator needs access, they submit a request specifying the port, source IP, and duration. Defender for Cloud then creates a temporary NSG rule to allow the connection.
Enable JIT on your target VMs to lock down management ports. You can enable JIT through the Azure portal, Azure CLI, or PowerShell.
# Set the target subscription where your VMs reside.
# Replace YOUR_SUBSCRIPTION_ID with your Azure subscription GUID
# (find it via: az account list -o table).
az account set --subscription "YOUR_SUBSCRIPTION_ID"
# Enable JIT on a specific VM with SSH (22) and RDP (3389) ports.
# --resource-group: the RG containing the target VM.
# --location: Azure region of the VM (must match exactly).
# --name "default": JIT policy name; "default" is the standard convention.
# "maxRequestAccessDuration": "PT3H" = max 3-hour access window per request
# (ISO 8601 duration - PT1H = 1 hour, PT30M = 30 minutes).
# WHY: Once enabled, Defender for Cloud adds deny-all NSG rules on these
# ports, closing them to all inbound traffic until a JIT request is approved.
az security jit-policy create \
--resource-group "rg-healthcare-vms" \
--location "eastus" \
--name "default" \
--virtual-machines "[{ \
\"id\":\"/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/rg-healthcare-vms/providers/Microsoft.Compute/virtualMachines/vm-ehr-01\", \
\"ports\":[{\"number\":22,\"protocol\":\"TCP\",\"maxRequestAccessDuration\":\"PT3H\"}, \
{\"number\":3389,\"protocol\":\"TCP\",\"maxRequestAccessDuration\":\"PT3H\"}] \
}]"
# Verify JIT is enabled by listing protected VMs.
# Expected output: a table showing the full resource ID of each VM
# covered by the JIT policy. If empty, the policy did not apply.
az security jit-policy show \
--resource-group "rg-healthcare-vms" \
--location "eastus" \
--name "default" \
--query "virtualMachines[].id" -o table# Authenticate to Azure and set the subscription context.
# Replace YOUR_SUBSCRIPTION_ID with your Azure subscription GUID.
Connect-AzAccount
Set-AzContext -SubscriptionId "YOUR_SUBSCRIPTION_ID"
# Define the JIT policy for a single VM.
# "id": full ARM resource ID of the VM to protect.
# "ports": array of management ports to lock down.
# number 22 = SSH (Linux); number 3389 = RDP (Windows).
# maxRequestAccessDuration "PT3H" = admins can request up to 3 hours
# of access per session (ISO 8601 duration format).
$jitPolicy = @{
id = "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/rg-healthcare-vms/providers/Microsoft.Compute/virtualMachines/vm-ehr-01"
ports = @(
@{ number = 22; protocol = "TCP"; maxRequestAccessDuration = "PT3H" }
@{ number = 3389; protocol = "TCP"; maxRequestAccessDuration = "PT3H" }
)
}
# Apply the JIT policy. This adds deny-all inbound NSG rules for
# the specified ports immediately, blocking all management access
# until a time-limited JIT request is approved.
# -Kind "Basic": standard JIT policy type.
Set-AzJitNetworkAccessPolicy `
-ResourceGroupName "rg-healthcare-vms" `
-Location "eastus" `
-Name "default" `
-VirtualMachine $jitPolicy `
-Kind "Basic"
# Confirm the policy was created. The output lists all VMs and ports
# protected by JIT in this resource group and region.
Get-AzJitNetworkAccessPolicy -ResourceGroupName "rg-healthcare-vms" -Location "eastus"Once JIT is enabled, administrators must request access each time they need to connect to a protected VM. Requests can be submitted through the portal, CLI, or API.
# Request time-limited RDP access to a JIT-protected VM.
# This creates a temporary allow rule in the NSG for the specified port.
# --name "default": must match the JIT policy name set during enablement.
# "allowedSourceAddressPrefix": restrict access to YOUR IP only (never use
# "*" - a wildcard defeats the purpose of JIT by allowing any source).
# "endTimeUtc": ISO 8601 timestamp when access expires automatically.
# The NSG allow rule is removed after this time, re-blocking the port.
# WHY: Provides auditable, time-limited access that satisfies HIPAA
# minimum-necessary requirements and prevents persistent port exposure.
az security jit-policy initiate \
--resource-group "rg-healthcare-vms" \
--location "eastus" \
--name "default" \
--virtual-machines "[{ \
\"id\":\"/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/rg-healthcare-vms/providers/Microsoft.Compute/virtualMachines/vm-ehr-01\", \
\"ports\":[{\"number\":3389,\"allowedSourceAddressPrefix\":\"203.0.113.50\",\"endTimeUtc\":\"2026-03-06T18:00:00Z\"}] \
}]"# Define the JIT access request for RDP (port 3389).
# "allowedSourceAddressPrefix": your workstation IP - only this IP can
# connect during the access window. Use your actual public IP here.
# "endTimeUtc": calculates a 2-hour window from now. The temporary
# NSG allow rule auto-expires after this timestamp.
# WHY: Every JIT request is logged in Azure Activity Log, creating a
# full audit trail of who accessed which VM, when, and from where.
$request = @{
id = "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/rg-healthcare-vms/providers/Microsoft.Compute/virtualMachines/vm-ehr-01"
ports = @(
@{
number = 3389
allowedSourceAddressPrefix = "203.0.113.50"
endTimeUtc = (Get-Date).AddHours(2).ToUniversalTime().ToString("o")
}
)
}
# Submit the JIT access request. On success, the NSG is updated with
# a time-limited allow rule. You can now RDP to the VM from 203.0.113.50.
# Expected output: the request status and the ports that were opened.
Start-AzJitNetworkAccessPolicy `
-ResourceGroupName "rg-healthcare-vms" `
-Location "eastus" `
-Name "default" `
-VirtualMachine $requestDefault JIT policies cover common ports, but enterprise environments often need custom configurations. You can define per-port maximum durations, restrict source IP ranges, and add application-specific management ports.
# Custom JIT policy with per-port restrictions tailored for healthcare VMs.
# RDP (3389): max 1-hour window - sufficient for routine maintenance.
# SSH (22): max 2-hour window - for Linux admin tasks.
# Port 8443: custom EHR management port, max 30 minutes - tightest window
# because EHR admin interfaces are high-value targets.
# "allowedSourceAddressPrefixes": restricts which networks can request
# access. RFC 1918 ranges (10.x, 172.16.x) ensure only internal
# corporate networks are allowed - no internet-based requests.
# WHY: Per-port durations follow least-privilege principles. Short windows
# for sensitive ports reduce the attack surface during maintenance.
az security jit-policy create \
--resource-group "rg-healthcare-vms" \
--location "eastus" \
--name "default" \
--virtual-machines "[{ \
\"id\":\"/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/rg-healthcare-vms/providers/Microsoft.Compute/virtualMachines/vm-ehr-01\", \
\"ports\":[ \
{\"number\":3389,\"protocol\":\"TCP\",\"maxRequestAccessDuration\":\"PT1H\",\"allowedSourceAddressPrefixes\":[\"10.0.0.0/8\",\"172.16.0.0/12\"]}, \
{\"number\":22,\"protocol\":\"TCP\",\"maxRequestAccessDuration\":\"PT2H\",\"allowedSourceAddressPrefixes\":[\"10.0.0.0/8\"]}, \
{\"number\":8443,\"protocol\":\"TCP\",\"maxRequestAccessDuration\":\"PT30M\",\"allowedSourceAddressPrefixes\":[\"10.10.0.0/16\"]} \
] \
}]"# Define a standard port policy applied uniformly across all VMs.
# PT2H/PT1H/PT30M = max access durations (2h SSH, 1h RDP, 30m EHR port).
# Using consistent policies across a fleet simplifies auditing and ensures
# no VM is left with overly permissive access windows.
$standardPorts = @(
@{ number = 22; protocol = "TCP"; maxRequestAccessDuration = "PT2H" }
@{ number = 3389; protocol = "TCP"; maxRequestAccessDuration = "PT1H" }
@{ number = 8443; protocol = "TCP"; maxRequestAccessDuration = "PT30M" }
)
# Retrieve all VMs in the resource group to build policies dynamically.
# This avoids hardcoding VM IDs and ensures new VMs are included.
$vms = Get-AzVM -ResourceGroupName "rg-healthcare-vms"
# Build a JIT policy object for each VM using the standard port template.
# ForEach-Object maps each VM's ARM resource ID to the port policy.
$jitVMs = $vms | ForEach-Object {
@{
id = $_.Id
ports = $standardPorts
}
}
# Apply the JIT policy to ALL VMs in a single API call.
# This is far more efficient than enabling JIT per-VM individually.
# Expected output: confirmation that the policy covers N VMs.
Set-AzJitNetworkAccessPolicy `
-ResourceGroupName "rg-healthcare-vms" `
-Location "eastus" `
-Name "default" `
-VirtualMachine $jitVMs `
-Kind "Basic"
Write-Host "JIT enabled on $($vms.Count) VMs"Every JIT access request generates entries in the Azure Activity Log. You can query these logs with KQL to build audit reports for compliance teams.
// Retrieve all JIT access requests from the last 30 days.
// WHY: Builds an audit trail for HIPAA compliance - auditors require
// evidence of who accessed patient-facing servers and when.
// OperationNameValue filter targets only JIT initiate actions,
// excluding policy creation/deletion events.
// OUTPUT: Table of timestamped requests showing the requesting user
// (Caller), target resource group, specific VM, approval status,
// and the justification provided for the access request.
AzureActivity
| where TimeGenerated > ago(30d)
| where OperationNameValue == "Microsoft.Security/locations/jitNetworkAccessPolicies/initiate/action"
| project
TimeGenerated,
Caller, // User or SPN who requested access
ResourceGroup,
ResourceId = tostring(parse_json(Properties).resourceId), // Target VM resource ID
Status = ActivityStatusValue, // Succeeded = approved, Failed = denied
Justification = tostring(parse_json(Properties).justification)
| order by TimeGenerated desc// Find denied or failed JIT access attempts in the past 7 days.
// WHY: Repeated denied requests may indicate a compromised account
// trying to gain access, or a misconfigured JIT policy blocking
// legitimate administrators. Both scenarios require investigation.
// has "jitNetworkAccessPolicies": catches all JIT operations (initiate,
// create, delete) to surface any failures across the policy lifecycle.
// OUTPUT: Count of denied attempts per user (Caller) and resource group,
// with the most recent attempt timestamp. Investigate callers with high
// DeniedCount values as priority security incidents.
AzureActivity
| where TimeGenerated > ago(7d)
| where OperationNameValue has "jitNetworkAccessPolicies"
| where ActivityStatusValue in ("Failed", "Denied")
| summarize
DeniedCount = count(),
LastAttempt = max(TimeGenerated)
by Caller, ResourceGroup
| order by DeniedCount descAdaptive application controls analyze the applications running on your VMs over a learning period and recommend allowlist policies. Once enforced, only approved applications can execute on protected machines.
After the learning period, review the recommended allowlists to verify that all legitimate applications are included and no malicious software has been inadvertently allowlisted.
// List adaptive application control violations from the last 7 days.
// WHY: Each violation means an unapproved executable ran (or attempted
// to run) on a protected VM. In audit mode this is logged; in enforce
// mode the application was blocked. Either way, review is required to
// determine if it is a legitimate new application or malicious activity.
// OUTPUT: Table of alerts showing the affected VM (CompromisedEntity),
// description of the blocked application, and suggested remediation steps.
// High volume from one VM may indicate malware or a poorly tuned allowlist.
SecurityAlert
| where TimeGenerated > ago(7d)
| where AlertType has "AdaptiveApplication"
| project
TimeGenerated,
AlertName,
CompromisedEntity,
Description,
RemediationSteps
| order by TimeGenerated descWhen an unapproved application runs on a protected VM, Defender for Cloud generates a security alert. Proper alert handling ensures real threats are investigated while false positives are resolved quickly.
// Identify which VMs generate the most application control alerts.
// WHY: A VM with many alerts is either running unapproved software
// (potential compromise) or has a misconfigured allowlist (false positives).
// UniqueApps: count of distinct blocked application names - a high number
// suggests the allowlist is missing many legitimate apps; a low number
// with high AlertCount suggests the same app keeps executing (persistent
// malware or a recurring false positive that should be allow-listed).
// OUTPUT: Table ranked by AlertCount. Investigate the top entries first.
SecurityAlert
| where TimeGenerated > ago(30d)
| where AlertType has "AdaptiveApplication"
| summarize
AlertCount = count(),
UniqueApps = dcount(tostring(parse_json(ExtendedProperties).["Application Name"]))
by CompromisedEntity
| order by AlertCount descFile Integrity Monitoring tracks changes to operating system files, application binaries, Windows registry keys, and configuration files. It alerts you when critical files are modified unexpectedly.
# Point to the Log Analytics workspace where FIM data will be stored.
# Replace YOUR_SUBSCRIPTION_ID with your actual subscription GUID.
$workspaceId = "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/rg-security/providers/Microsoft.OperationalInsights/workspaces/law-healthcare"
# Enable the ChangeTracking solution in the workspace.
# This is the backend service that powers FIM - it collects file,
# registry, and Linux file change events from connected VMs.
# WHY: Without this solution enabled, FIM has no data pipeline.
Set-AzOperationalInsightsSolution `
-ResourceGroupName "rg-security" `
-WorkspaceName "law-healthcare" `
-SolutionType "ChangeTracking"
# Configure a custom file tracking rule for EHR application configs.
# Kind "WindowsPath": monitors files on Windows VMs at the specified path.
# Path wildcard *.xml: tracks all XML config files in the EHR directory.
# Recurse $true: includes subdirectories for complete coverage.
# GroupTag: labels these changes in reports for easy filtering.
# WHY: EHR config tampering could alter patient data processing rules,
# medication dosage calculations, or billing integrations - all critical
# for HIPAA compliance and patient safety.
$fileTrackingConfig = @{
Name = "EHR_App_Config"
ResourceGroup = "rg-security"
WorkspaceName = "law-healthcare"
Kind = "WindowsPath"
Path = "C:\\EHRApp\\Config\\*.xml"
Recurse = $true
GroupTag = "EHR Application"
}
# Apply the tracking configuration to start monitoring.
# Changes to these files will appear in the ConfigurationChange table.
New-AzOperationalInsightsDataSource @fileTrackingConfigAfter FIM is active, changes to monitored files and registry keys appear in the Log Analytics workspace. Use KQL to query change records and identify unauthorized modifications.
// List all monitored file changes from the last 7 days.
// WHY: Unexpected file modifications on patient-facing servers may
// indicate malware installation, unauthorized config changes, or
// insider threats. HIPAA requires evidence that critical files have
// not been tampered with between audit cycles.
// ConfigChangeType == "Files": filters to file-system changes only
// (excludes registry and Linux file changes).
// OUTPUT: Each row shows the timestamp, affected machine, file path,
// change category (Modified/Created/Deleted), before/after file sizes,
// and the account that made the change. Sudden size changes or
// unexpected accounts are red flags.
ConfigurationChange
| where TimeGenerated > ago(7d)
| where ConfigChangeType == "Files"
| project
TimeGenerated,
Computer,
FileSystemPath,
ChangeCategory,
PreviousSize = FileContentOldSize,
CurrentSize = FileContentNewSize,
ModifiedBy = Account
| order by TimeGenerated desc// Detect registry changes to auto-start and service registration keys.
// WHY: Attackers commonly add entries to CurrentVersion\Run (auto-start
// on login) or CurrentControlSet\Services (install as a Windows service)
// to achieve persistence after initial compromise. Changes to these keys
// outside of approved maintenance windows are high-priority alerts.
// has_any: matches if the registry key path contains either substring.
// OUTPUT: Each row shows the machine, exact registry key, value name,
// value data (e.g., path to a new executable), and whether it was
// Created, Modified, or Deleted. New entries pointing to unexpected
// executables warrant immediate investigation.
ConfigurationChange
| where TimeGenerated > ago(7d)
| where ConfigChangeType == "Registry"
| where RegistryKey has_any ("CurrentVersion\\Run", "CurrentControlSet\\Services")
| project
TimeGenerated,
Computer,
RegistryKey,
RegistryValueName = ValueName,
RegistryValueData = ValueData,
ChangeCategory
| order by TimeGenerated desc// Correlate file changes with security alerts on the same machine
// within a 60-minute window. This is a powerful indicator of compromise:
// if a file changed shortly before or after a security alert fired,
// the file change is likely related to the attack.
// WHY: Isolated file changes are often benign (patches, updates), but
// changes that coincide with alerts (e.g., malware detection, brute-force
// attempt) strongly suggest an active threat requiring urgent response.
// abs(datetime_diff("minute"...)): matches changes within ยฑ60 minutes of
// the alert, regardless of which happened first.
// OUTPUT: Paired rows showing the file change and the correlated alert.
// Prioritise these over standalone FIM or alert events.
let fileChanges = ConfigurationChange
| where TimeGenerated > ago(7d)
| where ConfigChangeType == "Files"
| project ChangeTime = TimeGenerated, Computer, FileSystemPath;
let alerts = SecurityAlert
| where TimeGenerated > ago(7d)
| project AlertTime = TimeGenerated, CompromisedEntity, AlertName;
fileChanges
| join kind=inner (alerts) on $left.Computer == $right.CompromisedEntity
| where abs(datetime_diff("minute", ChangeTime, AlertTime)) < 60
| project ChangeTime, Computer, FileSystemPath, AlertTime, AlertName
| order by ChangeTime descWorkflow automation in Defender for Cloud triggers Logic Apps in response to security alerts and recommendations. You can build automated remediation flows that respond to JIT, adaptive application control, and FIM events.
# Define the scope and Logic App target for the workflow automation.
# $automationScope: the subscription to monitor for security alerts.
# $logicAppId: the ARM resource ID of the Logic App that will execute
# when alerts match the filter criteria.
# Replace YOUR_SUBSCRIPTION_ID with your actual subscription GUID.
$automationScope = "/subscriptions/YOUR_SUBSCRIPTION_ID"
$logicAppId = "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/rg-security/providers/Microsoft.Logic/workflows/auto-remediate-jit"
# Build the workflow automation definition as a JSON payload.
# isEnabled: activates the automation immediately after creation.
# scopes: which subscriptions/resource groups to monitor.
# sources.eventSource "Alerts": triggers on Defender for Cloud security alerts.
# ruleSets.rules: filter to High-severity alerts only - avoids noisy
# automation triggers from informational or low-severity findings.
# actions.actionType "LogicApp": calls the specified Logic App when
# a matching alert fires. The Logic App handles the actual remediation
# (e.g., isolating a VM, notifying the SOC, creating a ticket).
# WHY: Automated response closes the gap between alert detection and
# remediation, critical in healthcare where every minute of exposure
# to an active threat risks patient data compromise.
$body = @{
properties = @{
description = "Auto-remediate JIT and adaptive control alerts"
isEnabled = $true
scopes = @(@{ scopePath = $automationScope })
sources = @(@{
eventSource = "Alerts"
ruleSets = @(@{
rules = @(
@{
propertyJPath = "Severity"
propertyType = "String"
expectedValue = "High"
operator = "Equals"
}
)
})
})
actions = @(@{
actionType = "LogicApp"
logicAppResourceId = $logicAppId
uri = "https://prod-eastus.logic.azure.com:443/workflows/YOUR_WORKFLOW_ID/triggers/manual/paths/invoke"
})
}
} | ConvertTo-Json -Depth 10
# Deploy the automation via the Azure REST API.
# PUT method creates or updates the automation resource.
# api-version 2019-01-01-preview: the Security automations API version.
# Expected output: HTTP 200/201 with the created automation resource JSON.
Invoke-AzRestMethod -Method PUT `
-Path "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/rg-security/providers/Microsoft.Security/automations/jit-auto-remediation?api-version=2019-01-01-preview" `
-Payload $bodyCreate an Azure Monitor Workbook that consolidates JIT access activity, adaptive application control alerts, and FIM change data into a single dashboard for the security operations team.
// Daily summary of JIT access requests over 30 days.
// WHY: Trends reveal whether JIT adoption is growing, whether denied
// requests are increasing (potential policy issues), and whether
// access patterns align with scheduled maintenance windows.
// OUTPUT: Time series with daily counts of total, approved, and denied
// requests. Visualise as a line chart to spot anomalies (e.g., weekend
// spikes or sudden increases in denied requests).
AzureActivity
| where TimeGenerated > ago(30d)
| where OperationNameValue has "jitNetworkAccessPolicies"
| summarize
TotalRequests = count(),
Approved = countif(ActivityStatusValue == "Succeeded"),
Denied = countif(ActivityStatusValue == "Failed")
by bin(TimeGenerated, 1d)
| order by TimeGenerated asc// Top 10 users requesting JIT access in the last 30 days.
// WHY: Identifies which administrators use JIT most frequently.
// Unusually high request counts from a single user may indicate
// shared credentials, automation misconfiguration, or a compromised
// account systematically trying to gain access to VMs.
// OUTPUT: Bar chart of users ranked by request volume.
AzureActivity
| where TimeGenerated > ago(30d)
| where OperationNameValue has "jitNetworkAccessPolicies/initiate"
| summarize RequestCount = count() by Caller
| top 10 by RequestCount desc// Daily trend of adaptive application control violations over 30 days.
// WHY: A declining trend after initial rollout is expected as the
// allowlist matures. A sudden spike may indicate new malware, an
// unauthorised software installation, or a policy change that
// invalidated existing allowlist entries.
// OUTPUT: Line chart showing daily alert counts. Correlate spikes
// with known change events (patches, deployments) to distinguish
// false positives from genuine threats.
SecurityAlert
| where TimeGenerated > ago(30d)
| where AlertType has "AdaptiveApplication"
| summarize AlertCount = count() by bin(TimeGenerated, 1d)
| order by TimeGenerated asc// Distribution of FIM-detected changes by type over 30 days.
// Categories: Files, Registry, Linux files.
// WHY: Gives a quick health check - a balanced distribution is normal,
// but a sudden dominance of one category (e.g., many Registry changes)
// may signal an attack targeting persistence mechanisms.
// OUTPUT: Pie chart showing the proportion of each change type.
// Use this to decide where to focus deeper investigation.
ConfigurationChange
| where TimeGenerated > ago(30d)
| summarize ChangeCount = count() by ConfigChangeType
| order by ChangeCount descaz security jit-policy delete --resource-group "rg-healthcare-vms" --location "eastus" --name "default"| Resource | Description |
|---|---|
| Just-in-time VM access usage and configuration | Configure and manage time-limited VM port access requests |
| Adaptive application controls overview | Use ML-based allowlists to block unauthorized applications on VMs |
| File Integrity Monitoring in Defender for Cloud | Track changes to critical system files and registry keys |
| Automate responses to Defender for Cloud triggers | Create Logic App workflows for automated alert remediation |
| Understanding JIT VM access | Learn how JIT modifies NSG rules to reduce attack surface |
| Defender for Servers plans overview | Compare Plan 1 and Plan 2 features for server workloads |
| Azure Monitor Workbooks | Build interactive dashboards for security monitoring and reporting |
| Azure Logic Apps overview | Design automated workflows for cloud security operations |
| Microsoft Defender for Cloud pricing | Review per-server hourly billing and plan cost estimates |