Azure Lighthouse Cross-Tenant Management Options
Managing 3 Azure Tenants with Lighthouse
Azure Cross-Tenancy Management Overview
Azure SQL Managed Instance Private Endpoint Guide
Network Traffic Breakdown for Security Strategy
what are the limitations of DSC
Cloud Network and Corporate Network Diagram
AWS vs Azure Network Design Differences
Microsoft 365 Dependency on Azure Landing Zones
SASE Replaces Traditional Network TAP Capabilities
Changing Work Item Types in Azure DevOps
Jan-Bow Milestones Developmental Screening Overview
Azure DevOps and Azure Tenancy Linkage
DevOps Overlay on Landing Zone and VDI
Azure UDR Operational Inefficiency and Best Practices
SD-WAN Integration in Azure Architectures Explained
AWS Route Table vs Azure UDR Comparison
Best Practice CIDR Design for Azure Virtual WAN
Azure DevOps Subnet IP Range Guide
Decoupling Azure Networking for Modern Security
Palo Alto Cloud NGFW Introduction Timeline
Best Practices for CIDR in Azure Landing Zones
Implementing Azure Landing Zone Steps Guide
Using Azure AD for Multiple Tenants
Deploy Azure DevOps in Production and Non-Prod
Azure vWAN vs Traditional Hub Comparison
Azure Virtual WAN Cost Savings Explained
Securing Azure Single Tenant for Business Units
Designing Azure Security Landing Zones Features
Securing Azure Single-Tenant Architecture Guide
Security Risks and Mitigations for Azure Virtual WAN
Free vs Paid DeepSeek Features Explained
Azure Network Landing Zone Design Overview
How to migrate from azure hub an
Migrate Azure Hub-Spoke to Virtual WAN
How to migrate azure hub and spo
Azure Firewall Design Document with Diagrams
Azure Firewall Migration Components Overview
Migrating Palo Alto Firewall to Azure
As-Built Azure Landing Zone Audit Document
As-Built Azure Landing Zone Audit Guide
Finding and Managing Azure Environments Guide
Websites That Earn via Subscription Referrals
Migrating Exadata to Azure Guide
Trump Tariff Calculations Criticized for Flaws
Trump’s Tariff Calculations Criticized by Experts
Finding Azure Resource Health Alerts Guide
Finding Log Analytics Configuration in Azure
Azure DevOps Fabric Integration Purpose Explained
DSC Security Risks in Azure Landing Zone
Components of a DevOps Design Overview
Pros and Cons of Environment Routing in Power Platform
Structured Power Platform Support Model Guide
Testing Power Platform Catalog Assignment Authorizations
what is the name of the observat
Azure Landing Zone Design Components Overview
Best Practice Test Plan Structure Guide
Sample Test Plan for Power Apps Application
Best Practices for DLP in Power Apps
DLP Policies for Power Apps Examples
Microsoft DSC Attribute Configuration Mechanisms Explained
Security Model for Microsoft Power Platform
Best Practices for Power Platform Authentication
Best Practices for Access Control in Power Pages
Best Practices for Power Apps Conditional Access
Deploy Power Platform Using DSC Guide
Power Platform Security Groups Overview
Best Practices for RBAC in Power Apps
Best RBAC Practices for Power Platform Environments
Monitoring Settings for Microsoft Planner and Forms
Benefits of Power Platform Tenant Analytics
Persona Model in Conditional Access Policies
Power Platform Tenant and Admin Settings Purpose
Power Platform Data Sources Overview
Upgrade HP Elite Laptop SSD to 512GB
Artist Guitars Australia Sales Voucher Guide
Steps to Build Chatbot Language Model
Understanding Quantum Computing Basics and Applications
Specifying PII Fields in Azure Purview Email Scan
Azure APIs for Email PII Data Scanning
BitLocker and SSD Replacement Security Guide
Rahab in Bible Verses and Contexts
March 10 Cherry Blossom Busan Inquiry
how to connect external user to
how to create a base template fo
what is lowest fare from sydney
what is lowest cost way to fly f
show me a sample power platform
where are settings for power bi
what settings allow launch of mi
where do i configure task notifi
how to extract microsoft power p
which church in Canberra has kor
what ae the configuration settin
what are the configuration setti
what are the configuration setti
what are the configuration setti
what are the configuration setti
what are the configuration setti
Azure Lighthouse Cross-Tenant Management Options
what are options for cross tenant management using Azure Lighthouse?
Of course! Azure Lighthouse is the premier and recommended solution for secure, large-scale cross-tenant management. It enables you to manage resources across multiple customer tenants from a single, centralized managing tenant.
Here are the primary options and patterns for cross-tenant management using Azure Lighthouse, broken down from basic to advanced.
- Core Concept: Delegated Resource Management
The foundation of Azure Lighthouse is delegated resource management. You don’t get direct access to the customer tenant. Instead, the customer delegates their Azure resources (subscriptions, resource groups) to your managing tenant. Your authorized users and managed identities can then see and operate on these delegated resources as if they were in your own tenant, but without having a user account or role in the customer tenant.
- Primary Onboarding Options
There are two main ways to onboard a customer tenant to Azure Lighthouse.
Option A: ARM Templates (Recommended for Partners & Service Providers)
This is the most common and scalable method. You provide the customer with an Azure Resource Manager (ARM) template or a service-managed offer via the Azure Marketplace. The customer deploys this template in their own tenant, which explicitly grants the permissions you’ve defined.
- How it works:
- You create an ARM template that defines:
- principalId: The User, Group, or Service Principal in your tenant who needs access.
- roleDefinitionId: The built-in or custom Azure RBAC role (e.g., Contributor, Reader, Log Analytics Contributor).
- principalIdDisplayName: A friendly name for your team (e.g., “Contoso Support Team”).
- The customer deploys this template via the Portal, PowerShell, CLI, or a CI/CD pipeline in their tenant.
- Upon successful deployment, the resources are visible in your “My Customers” page in Azure Portal.
- You create an ARM template that defines:
- Best for: Managed Service Providers (MSPs), SIs, and partners with multiple customers. It’s auditable, version-controlled, and easy to automate.
Option B: Managed Service Offers via Azure Marketplace
This method is formal and involves publishing a “Managed Service” plan to the Azure Marketplace. The customer can then “purchase” (it’s free) this offer, which triggers the onboarding process.
- How it works:
- You create a “Managed Service” offer in Partner Center.
- You define the same authorization details (users, roles) as in the ARM template.
- You publish the offer privately to specific customer tenants or publicly.
- The customer accepts the offer in the Azure Portal, which creates the delegation.
- Best for: Partners who want a formal, marketplace-driven process and may be part of the Cloud Solution Provider (CSP) program.
- Management & Operationalization Options
Once onboarded, you can leverage various Azure native services from your managing tenant to manage the delegated resources.
Option 1: Native Azure Portal Experience
This is the simplest way to get started. After onboarding, delegated resources appear in your managing tenant’s Azure Portal.
- “My Customers” Page: A dedicated page (Azure Active Directory -> My Customers) lists all your customers and their delegated subscriptions/resources.
- Directory + Subscription Switcher: Use the switcher at the top of the Azure Portal to change context from your tenant to a specific customer’s subscription. Once selected, you can manage their resources directly.
- Activity Logs: View activity logs for the delegated resources, filtered to show only actions taken by users from your managing tenant.
Option 2: Azure Policy for Governance
Apply and enforce compliance at scale across all customer tenants.
- How it works:
- Create Policy Definitions and Initiatives (as blueprints) in your managing tenant.
- Assign these policies directly to the delegated subscriptions or resource groups in the customer tenants.
- The policy’s compliance state, remediation tasks, and effects are managed from your tenant.
- Use Case: Enforcing that all customer VMs must have a specific tag, or that storage accounts must disable public network access.
Option 3: Azure Monitor for Centralized Logging & Alerting
Gain a unified view of the health and performance of all customer environments.
- Log Analytics Workspaces: Deploy a central Log Analytics workspace in your managing tenant (or use a regional one in a customer tenant). Use Azure Monitor Agent to send logs from VMs in any customer tenant to this central workspace.
- Azure Monitor Alerts: Create alerts in your managing tenant that monitor conditions across delegated resources. For example, an alert rule that fires if any VM in any customer tenant has >90% CPU for 5 minutes.
- Workbooks & Dashboards: Create comprehensive dashboards that aggregate data from multiple customer tenants for a single-pane-of-glass view.
Option 4: Automation with Scripts & Managed Identities
Automate management tasks securely using Azure Automation Runbooks or Logic Apps.
- How it works:
- Create an Automation Account with a System-Assigned Managed Identity in your managing tenant.
- Grant this Managed Identity the necessary RBAC role on the customer’s delegated resources (this is done during the initial ARM template onboarding).
- Your runbook scripts (PowerShell, Python) can now authenticate using the Managed Identity and perform actions across all customer tenants without storing any credentials.
- Use Case: A nightly runbook that shuts down all non-essential VMs across all customer environments to save costs.
Option 5: Azure Security Center & Microsoft Defender for Cloud
Centralize security management.
- How it works: When you have a delegated subscription, its security posture, recommendations, and alerts (from Microsoft Defender for Cloud) will appear in your managing tenant’s Defender for Cloud portal. You can set secure scores and track compliance across your entire customer base.
Option 6: Azure Backup & Site Recovery
Manage disaster recovery and backup for customer resources.
- How it works: Use the Backup Center and Site Recovery vault in your managing tenant to monitor and manage backup jobs, restores, and replication for items in customer tenants.
- Advanced Scenarios
- Cross-Tenant Azure Arc Management: Use Lighthouse to manage servers, Kubernetes clusters, and SQL Managed Instances that are connected via Azure Arc, even if they are hosted outside of Azure (on-premises, other clouds).
- Nested Delegations: A partner (Tier 1) can delegate a customer’s resources to a sub-partner (Tier 2). The sub-partner then manages the resources from their own tenant.
- Custom RBAC Roles: Create highly specific custom roles in your managing tenant to provide “least privilege” access for different teams (e.g., a “VM Operator” role that can only start/stop/deallocate VMs).
Summary Table of Options
Option | Primary Use Case | Key Benefit |
ARM Template Onboarding | Scalable, automated customer onboarding. | Developer-friendly, version control, CI/CD integration. |
Marketplace Offer | Formal, partner-led onboarding. | Integrated with Partner Center/CSP program. |
Native Portal Experience | Day-to-day manual management & troubleshooting. | Simple, no extra tools required. |
Azure Policy | Governance & Compliance. | Enforce rules at scale across all customers. |
Azure Monitor | Centralized monitoring, logging, and alerting. | Single-pane-of-glass for operational health. |
Automation Accounts | Automated remediation & management tasks. | Reduces manual toil, ensures consistency. |
Defender for Cloud | Unified security management. | Centralized view of security posture and threats. |
Key Considerations
- Security & Least Privilege: Always follow the principle of least privilege. Use custom roles to grant only the permissions absolutely necessary.
- Pricing: There are no direct costs for using Azure Lighthouse itself. You pay for the underlying Azure services you use (e.g., the cost of the Log Analytics workspace, Automation jobs, etc.) and for any actions performed on the customer’s resources, which are billed to the customer’s subscription.
- Auditing: All actions taken by users from the managing tenant are logged in the customer tenant’s Activity Log, providing a clear audit trail.
By leveraging these options, you can build a highly efficient, secure, and scalable multi-tenant management solution for any scenario, from simple resource management to complex, automated governance and security operations.
what are options for cross tenant management using Entra ID
Excellent question. While Azure Lighthouse is specifically designed for resource delegation and management, Entra ID (formerly Azure Active Directory) provides the foundational identity and access capabilities that enable cross-tenant scenarios. The options here are more about connecting identities and enabling access rather than directly managing another tenant’s resources.
Here are the primary options for cross-tenant management and collaboration using Entra ID:
- Entra ID External ID (B2B) Collaboration
This is the most common and fundamental method. It allows you to invite users from any Entra ID tenant (or even other identity providers like Google, etc.) to be “guest users” in your tenant. They authenticate with their home tenant but can be assigned access to resources in your tenant.
- How it works:
- You invite a user from tenant-b.com to your tenant-a.com.
- They receive an invitation and redeem it.
- A “Guest User” object is created in your tenant-a.com directory.
- You can assign this guest user to Azure AD groups and grant them access to applications (SaaS apps, custom apps) and Azure resources, just like a member user.
- Key Features:
- Access Packages (Entra Entitlement Management): For scalable, policy-driven access. You can create a catalog of applications/resources and let external users request access via a portal, with automated approval and expiration workflows.
- Cross-Tenant Access Settings: Granular control over the collaboration flow between your tenant and other specific tenants.
- Best for:
- Collaborating with individual users from partner organizations.
- Giving a customer’s IT admin access to a SaaS application you host.
- Federating development teams across company boundaries.
- Entra ID Cross-Tenant Access Settings (XTAS)
This is the control plane for B2B collaboration. It allows you to define granular inbound and outbound rules for how you collaborate with specific external Entra ID tenants.
- How it works:
You configure settings for a specific partner tenant (e.g., partner-company.com). You can independently control:- Inbound Access: What users from the partner tenant can do in your tenant (e.g., allow B2B collaboration, block access to specific apps).
- Outbound Access: What your users can do in the partner tenant when they are invited as guests.
- Key Capabilities:
- Trust Settings: Automatically accept Multi-Factor Authentication (MFA) and compliant device claims from a trusted partner tenant, so their users don’t have to perform MFA again in your tenant.
- Application Restrictions: Block your internal users from taking data out to unsanctioned applications in other tenants.
- B2B Direct Connect: The underlying technology for the next option.
- Best for:
- Establishing secure, trusted partnerships with specific organizations.
- Simplifying the user experience by honoring MFA and device compliance from the user’s home tenant.
- Entra ID B2B Direct Connect
This is a more integrated form of collaboration focused on sharing applications between two Entra ID tenants, without the need for guest user accounts or invitations.
- How it works:
- Two tenants establish a mutual trust relationship via Cross-Tenant Access Settings.
- An admin in tenant-a.com can now grant the entire “Users” group from tenant-b.com access to an application in tenant-a.com.
- A user from tenant-b.com goes directly to tenant-a.com’s application. They are seamlessly signed in using their own tenant-b.com account. There is no “guest user” object created in tenant-a.com.
- Key Differentiator from B2B:
B2B Collaboration | B2B Direct Connect |
Creates a “Guest User” object in your directory. | No guest user is created in your directory. |
Good for collaborating with many different orgs. | Designed for 1:1, mutual tenant relationships. |
User must redeem an invitation. | User access is seamless; they just navigate to the app. |
- Best for:
- Deep integration between two specific partner companies (e.g., a manufacturer and its primary supplier sharing an ERP module).
- Sharing applications within a corporate group where each subsidiary has its own tenant.
- Entra ID Multi-Tenant Applications
This isn’t about “managing” other tenants but enabling your application to be used by users from any Entra ID tenant.
- How it works:
- You develop an application (e.g., a SaaS app) and register it in your home tenant as Multi-Tenant.
- A customer from tenant-c.com consents to your application, either by an admin granting tenant-wide consent or a user granting consent for themselves.
- This creates a “service principal” (an enterprise application) in the customer’s tenant, and users there can now sign in to your app with their own work accounts.
- Best for:
- ISVs (Independent Software Vendors) building SaaS applications for multiple customers.
- This is the identity pattern that powers the vast majority of SaaS apps in the Microsoft ecosystem.
- Combining Entra ID with Azure Lighthouse
This is the most powerful pattern for true cross-tenant management. You use Entra ID for identity and access control within your managing tenant, and Lighthouse for resource delegation from customer tenants.
- How it works:
- You use Entra ID Groups in your managing tenant. For example, you create a group “Tier-2-Support-Engineers”.
- When onboarding a customer via an Azure Lighthouse ARM template, you authorize the Entra ID Group’s object ID (instead of individual users) for a specific RBAC role (e.g., Contributor).
- Now, any user you add to that group in your tenant automatically gets Contributor access to all delegated customer resources. Removing them from the group revokes their access.
- Key Benefit:
- Simplified User Lifecycle Management: You manage access by simply adding/removing users from groups in your central tenant. You don’t need to update the Lighthouse delegation for every customer every time an employee joins or leaves.
Summary Table: Entra ID Cross-Tenant Options
Option | Primary Use Case | Key Concept |
Entra ID B2B Collaboration | Inviting individual external users to access your resources/apps. | “Guest Users” in your directory. |
Cross-Tenant Access Settings | Controlling B2B collaboration with specific partner tenants. | The “trust and security” control plane. |
B2B Direct Connect | Seamlessly sharing apps between two organizations without guest users. | 1:1 tenant trust; no guest objects. |
Multi-Tenant Apps | Building a SaaS application for customers to sign into with their own Entra ID. | Customer “consent” to your app. |
Entra ID + Lighthouse | Scalable identity management for service providers managing customer Azure resources. | Use Groups in your tenant to control access to delegated resources. |
How to Choose:
- To manage a customer’s Azure resources (VMs, networks, etc.): Use Azure Lighthouse, and leverage Entra ID Groups for scalable access control.
- To give a customer access to your Azure-based SaaS application: Use a Multi-Tenant Application.
- To collaborate with specific users from a partner on internal projects/apps: Use B2B Collaboration.
- To establish a deep, seamless app-sharing partnership with one other company: Use B2B Direct Connect.
- To configure trust and security policies for any of the above: Use Cross-Tenant Access Settings.
what are options for cross tenant management using Least Privilege Access Custome Roles?
Excellent question. Implementing Least Privilege with Custom Roles is a critical security practice for cross-tenant management, especially when built-in roles are too broad. Here’s a comprehensive guide to the options and patterns for using custom roles in cross-tenant scenarios, primarily with Azure Lighthouse.
Core Concept: Why Custom Roles for Cross-Tenant?
Built-in roles like Owner, Contributor, or even Reader are often too permissive for specific management tasks. Custom roles allow you to:
- Grant only the actions needed for a specific function
- Reduce attack surface and potential for accidental damage
- Meet compliance requirements for principle of least privilege
- Custom Role Creation & Structure
Where to Create Custom Roles
- Managing Tenant: Create custom roles in your managing tenant
- Customer Tenant: Alternatively, create them in the customer tenant (less common for service providers)
Basic Custom Role Structure
json
{
“Name”: “VM Operator – Read and Start/Stop”,
“Description”: “Can view VMs and start/deallocate them, but not create or delete”,
“Actions”: [
“Microsoft.Compute/virtualMachines/read”,
“Microsoft.Compute/virtualMachines/start/action”,
“Microsoft.Compute/virtualMachines/deallocate/action”,
“Microsoft.Compute/virtualMachines/instanceView/read”
],
“NotActions”: [],
“DataActions”: [],
“NotDataActions”: [],
“AssignableScopes”: [“/”] // Or specific subscriptions
}
- Cross-Tenant Deployment Patterns
Pattern A: Create in Managing Tenant, Deploy via Lighthouse
Most common pattern for service providers
- Create custom role in your managing tenant
- Reference it in ARM template for Lighthouse onboarding
- Deploy to customer tenant – the role definition is copied automatically
json
{
“$schema”: “https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“mspOfferName”: { “type”: “string” },
“managedByTenantId”: { “type”: “string” }
},
“variables”: {
“vmOperatorRoleId”: “[guid(‘vm-operator-role’)]”
},
“resources”: [
{
“type”: “Microsoft.Authorization/roleDefinitions”,
“apiVersion”: “2018-01-01-preview”,
“name”: “[variables(‘vmOperatorRoleId’)]”,
“properties”: {
“roleName”: “VM Operator – Cross Tenant”,
“description”: “Custom VM operator role for cross-tenant management”,
“type”: “customRole”,
“permissions”: [
{
“actions”: [
“Microsoft.Compute/virtualMachines/read”,
“Microsoft.Compute/virtualMachines/start/action”,
“Microsoft.Compute/virtualMachines/deallocate/action”,
“Microsoft.Compute/virtualMachines/instanceView/read”,
“Microsoft.ResourceHealth/availabilityStatuses/read”,
“Microsoft.Resources/subscriptions/resourceGroups/read”
],
“notActions”: [],
“dataActions”: [],
“notDataActions”: []
}
],
“assignableScopes”: [
“[subscription().id]”
]
}
},
{
“type”: “Microsoft.ManagedServices/registrationDefinitions”,
“apiVersion”: “2019-09-01”,
“name”: “[guid(parameters(‘mspOfferName’))]”,
“properties”: {
“registrationDefinitionName”: “[parameters(‘mspOfferName’)]”,
“description”: “[parameters(‘mspOfferName’)]”,
“managedByTenantId”: “[parameters(‘managedByTenantId’)]”,
“authorizations”: [
{
“principalId”: “[parameters(‘principalId’)]”, // Your user/group
“roleDefinitionId”: “[subscriptionResourceId(‘Microsoft.Authorization/roleDefinitions’, variables(‘vmOperatorRoleId’))]”,
“principalIdDisplayName”: “VM Operations Team”
}
]
}
}
]
}
Pattern B: Pre-create in Customer Tenant
For highly regulated environments
- Create custom role directly in customer tenant
- Reference existing role in Lighthouse onboarding
- Requires customer cooperation but gives them full visibility
json
“authorizations”: [
{
“principalId”: “[parameters(‘principalId’)]”,
“roleDefinitionId”: “/subscriptions/{customer-sub-id}/providers/Microsoft.Authorization/roleDefinitions/{custom-role-id}”,
“principalIdDisplayName”: “Security Monitoring Team”
}
]
- Common Least Privilege Custom Role Examples
Example 1: Backup Operator
json
{
“permissions”: [
{
“actions”: [
“Microsoft.RecoveryServices/vaults/backupFabrics/operationResults/read”,
“Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/read”,
“Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/operationResults/read”,
“Microsoft.RecoveryServices/vaults/backupJobs/*”,
“Microsoft.RecoveryServices/vaults/backupPolicies/read”,
“Microsoft.RecoveryServices/vaults/backupProtectedItems/read”,
“Microsoft.RecoveryServices/vaults/backupProtectionContainers/read”,
“Microsoft.RecoveryServices/vaults/read”,
“Microsoft.RecoveryServices/Vaults/backupOperations/read”,
“Microsoft.RecoveryServices/Vaults/backupValidateOperation/action”
]
}
]
}
Example 2: Security Reader + Remediation
json
{
“permissions”: [
{
“actions”: [
“Microsoft.Security/*/read”,
“Microsoft.Security/assessments/*”,
“Microsoft.Security/policies/read”,
“Microsoft.Security/securityContacts/read”,
“Microsoft.Security/regulatoryComplianceStandards/read”,
// Limited write for remediation
“Microsoft.Security/tasks/start/action”,
“Microsoft.Sql/servers/firewallRules/write”,
“Microsoft.Storage/storageAccounts/delete”
]
}
]
}
Example 3: Cost Management Operator
json
{
“permissions”: [
{
“actions”: [
“Microsoft.Consumption/*/read”,
“Microsoft.CostManagement/*/read”,
“Microsoft.Billing/billingAccounts/read”,
“Microsoft.Resources/subscriptions/read”,
“Microsoft.Resources/tags/read”,
“Microsoft.Resources/tags/write” // For cost allocation tagging
]
}
]
}
Example 4: Network Security Operator
json
{
“permissions”: [
{
“actions”: [
“Microsoft.Network/networkSecurityGroups/read”,
“Microsoft.Network/networkSecurityGroups/securityRules/read”,
“Microsoft.Network/networkSecurityGroups/securityRules/write”,
“Microsoft.Network/networkWatchers/queryFlowLogStatus/action”,
“Microsoft.Network/networkWatchers/securityGroupView/action”,
“Microsoft.OperationalInsights/workspaces/query/read”
]
}
]
}
- Advanced Patterns & Best Practices
Pattern: Layered Role Assignment
Assign multiple custom roles to the same principal for different scopes:
json
“authorizations”: [
{
“principalId”: “[parameters(‘monitoringTeamId’)]”,
“roleDefinitionId”: “[subscriptionResourceId(‘Microsoft.Authorization/roleDefinitions’, variables(‘readerRoleId’))]”,
“principalIdDisplayName”: “Monitoring Team – Reader”,
“delegatedRoleDefinitionIds”: [ “acdd72a7-3385-48ef-bd42-f606fba81ae7” ] // Reader
},
{
“principalId”: “[parameters(‘monitoringTeamId’)]”,
“roleDefinitionId”: “[subscriptionResourceId(‘Microsoft.Authorization/roleDefinitions’, variables(‘logContributorRoleId’))]”,
“principalIdDisplayName”: “Monitoring Team – Log Contributor”,
“delegatedRoleDefinitionIds”: [ “92aaf0da-9dab-42b6-94a3-d43ce8d16293” ] // Log Analytics Contributor
}
]
Best Practice: Use Deny Assignments with Caution
While you can use NotActions, consider that deny assignments are complex in cross-tenant scenarios and should be used sparingly.
Best Practice: Regular Role Auditing
powershell
# Check what custom roles exist across delegated subscriptions
Get-AzRoleDefinition | Where-Object { $_.IsCustom -eq $true } |
Select-Object Name, Description, Actions, NotActions
Best Practice: Version Control for Roles
Store custom role definitions as ARM templates in source control with proper versioning and change management.
- Limitations and Considerations
Consideration | Impact on Cross-Tenant Custom Roles |
Role Limit | Up to 5000 custom roles per tenant |
Management Complexity | Each custom role requires maintenance and auditing |
Permission Changes | Role definition updates may require re-onboarding |
Data Actions | Custom roles can include data plane operations (e.g., storage blob contributor) |
Inheritance | Roles apply to the delegated scope and all child resources |
- Implementation Workflow
- Audit Requirements: Document exactly what actions each team needs to perform
- Map to Azure Actions: Use Get-AzProviderOperation to find exact action names
- Create & Test: Develop custom roles in test environment first
- Document: Clearly document the purpose and permissions of each role
- Deploy via Lighthouse: Include in ARM templates for customer onboarding
- Monitor & Refine: Use Azure Activity Logs to identify unused permissions
Summary
Using custom roles with Azure Lighthouse enables truly least-privilege cross-tenant management by:
- Eliminating over-permission compared to built-in roles
- Enabling task-specific access for different teams
- Reducing risk of accidental or malicious changes
- Meeting compliance requirements for privileged access
The key is careful planning of permission requirements and systematic implementation through well-structured ARM templates during the Lighthouse onboarding process.
what are options for cross tenant management using Entra ID PIM for JIT Access
Excellent question! Using Entra ID Privileged Identity Management (PIM) for Just-In-Time (JIT) access in cross-tenant scenarios is a powerful security pattern that combines the principle of least privilege with time-bound elevation. Here are the comprehensive options and implementation patterns:
- Core Architecture: PIM with Azure Lighthouse
The most effective pattern uses PIM in the managing tenant to control access to delegated resources in customer tenants via Azure Lighthouse.
How It Works:
- Lighthouse Delegation: Customer delegates resources to your managing tenant
- PIM Eligibility: You make users/groups eligible for Azure AD roles in your tenant
- JIT Activation: Users activate their eligible role when needed
- Cross-Tenant Access: Activated role grants access to customer resources via Lighthouse
- Implementation Patterns
Pattern A: PIM for Azure Built-in Roles + Lighthouse
Use PIM to make users eligible for standard roles that map to Lighthouse authorizations:
json
// Lighthouse ARM template with broad authorization
“authorizations”: [
{
“principalId”: “[parameters(‘pimEligibleGroupId’)]”, // Security group for PIM
“roleDefinitionId”: “[parameters(‘contributorRoleId’)]”,
“principalIdDisplayName”: “PIM-Eligible Support Team”
}
]
PIM Configuration:
- Role: Contributor (or other built-in role)
- Assignment Type: Eligible
- Members: Security group containing support engineers
- Activation Requirements: MFA, justification, approval (optional), max duration (e.g., 2 hours)
Pattern B: PIM for Custom Roles + Lighthouse
More granular control with custom roles:
json
// Custom role for specific operations
{
“Name”: “PIM-JIT-Emergency-Responder”,
“Actions”: [
“Microsoft.Compute/virtualMachines/read”,
“Microsoft.Compute/virtualMachines/start/action”,
“Microsoft.Compute/virtualMachines/deallocate/action”,
“Microsoft.Compute/virtualMachines/restart/action”,
“Microsoft.Support/*”
],
“AssignableScopes”: [“/”]
}
json
// Lighthouse authorization referencing custom role
“authorizations”: [
{
“principalId”: “[parameters(’emergencyRespondersGroupId’)]”,
“roleDefinitionId”: “[subscriptionResourceId(‘Microsoft.Authorization/roleDefinitions’, variables(’emergencyRoleId’))]”,
“principalIdDisplayName”: “PIM-Emergency-Responders”
}
]
- Specific PIM Configuration Options for Cross-Tenant
- Time-Bound Eligibility Settings
powershell
# Example PIM role settings for cross-tenant access
$settings = @{
“MaxEligibleDuration” = “P90D” # Maximum eligibility period
“MaxActiveDuration” = “PT8H” # Maximum activation duration (8 hours)
“RequireMFA” = $true
“RequireJustification” = $true
“RequireApproval” = $true # For sensitive roles
“Approvers” = @($approverGroupId)
}
- Multi-Stage Approval Workflows
For highly sensitive customer environments:
- First approver: Internal team lead
- Second approver: Customer-nominated contact (via Entra ID B2B)
- Automatic expiration: Based on risk level
- Emergency Access (“Break Glass”)
json
// Custom break-glass role with broader permissions
{
“Name”: “Break-Glass-Cross-Tenant”,
“Actions”: [“*”],
“NotActions”: [
“Microsoft.Authorization/*/write”,
“Microsoft.Blueprint/*”,
“Microsoft.PolicyInsights/*”
]
}
PIM Settings:
- Activation: Requires multiple approvers
- Duration: Maximum 1-2 hours
- Notification: Alerts to both internal and customer security teams
- Entra ID PIM Role Options for Cross-Tenant
- Azure AD Roles (Identity Plane)
These control access to the managing tenant itself:
Role | Use Case for Cross-Tenant |
Privileged Role Administrator | For PIM administrators managing the system |
Global Reader | Read-only access to monitor cross-tenant operations |
Groups Administrator | Manage security groups used for Lighthouse assignments |
User Administrator | Manage B2B guest users for customer collaboration |
- Azure Resource Roles (Resource Plane)
These control access to customer resources via Lighthouse:
Role | JIT Use Case |
Reader | Temporary read-only access for audits |
Contributor | Emergency incident response |
Security Admin | Security investigation and remediation |
SQL DB Contributor | Database emergency maintenance |
VM Contributor | Virtual machine troubleshooting |
- Custom Azure Roles
Tailored for specific cross-tenant functions:
json
{
“Name”: “PIM-Customer-Security-Responder”,
“Actions”: [
“Microsoft.Security/*/read”,
“Microsoft.Security/tasks/*”,
“Microsoft.Compute/virtualMachines/read”,
“Microsoft.Compute/virtualMachines/start/action”,
“Microsoft.Compute/virtualMachines/deallocate/action”,
“Microsoft.OperationalInsights/workspaces/search/action”
]
}
- Advanced PIM Patterns for Cross-Tenant
Pattern 1: Tiered Access Model
Pattern 2: Customer-Specific PIM Groups
Create separate PIM-eligible groups for different customers:
powershell
# Customer A – Limited access
New-AzADGroup -DisplayName “PIM-CustomerA-Support” -MailEnabled $false -SecurityEnabled $true
# Customer B – Broader access
New-AzADGroup -DisplayName “PIM-CustomerB-Full” -MailEnabled $false -SecurityEnabled $true
Pattern 3: Time-Bound Lighthouse with PIM
Combine PIM with temporary Lighthouse delegations:
json
{
“type”: “Microsoft.ManagedServices/registrationDefinitions”,
“properties”: {
“authorizations”: [
{
“principalId”: “[parameters(‘pimGroupId’)]”,
“roleDefinitionId”: “[parameters(‘contributorRoleId’)]”,
“principalIdDisplayName”: “JIT-Support-Team”
}
],
“eligibleAuthorizations”: [
{
“principalId”: “[parameters(‘pimGroupId’)]”,
“roleDefinitionId”: “[parameters(‘contributorRoleId’)]”,
“principalIdDisplayName”: “JIT-Support-Team”,
“justInTimeAccessPolicy”: {
“multiFactorAuthProvider”: “Azure”,
“maximumActivationDuration”: “PT8H”
}
}
]
}
}
- Automation and Integration Options
- PowerShell Automation for PIM Activation
powershell
# Function to request PIM activation for cross-tenant access
function Request-CrossTenantPIMAccess {
param(
[string]$RoleName,
[string]$CustomerName,
[string]$Justification,
[int]$DurationHours = 4
)
# Check current PIM eligibility
$eligibleAssignments = Get-AzRoleEligibilitySchedule -Filter “asTarget()”
# Request activation
$activationParams = @{
RoleDefinitionId = $roleId
Duration = “PT${DurationHours}H”
Reason = “Cross-tenant support for $CustomerName: $Justification”
}
New-AzRoleAssignmentScheduleRequest @activationParams
}
- Logic Apps for Approval Workflows
Create automated approval flows that:
- Receive PIM activation requests
- Notify customer contacts via email
- Wait for customer approval
- Auto-approve/deny based on customer response
- Log all actions for audit purposes
- Azure Monitor Alerts for PIM Activations
json
{
“alertRule”: {
“name”: “CrossTenant-PIM-Activation”,
“condition”: {
“field”: “category”,
“equals”: “RoleAssignment”
},
“actions”: [
{
“actionGroupId”: “/subscriptions/…/actionGroups/SecurityTeam”
}
]
}
}
- Security and Compliance Considerations
- Access Reviews
Configure regular access reviews for:
- PIM-eligible groups membership
- Customer resource access patterns
- Activation history and justification quality
- Audit and Monitoring
kusto
// KQL query to monitor cross-tenant PIM activations
AuditLogs
| where OperationName == “Elevate access (PIM)”
| where Result == “success”
| extend TargetTenant = tostring(TargetResources[0].DisplayName)
| project TimeGenerated, Identity, TargetTenant, ResultReason
- Conditional Access Policies
Integrate with Conditional Access for:
- Device compliance requirements
- Location-based restrictions (only activate from corporate IPs)
- Session controls for sensitive customers
- Implementation Checklist
- Define JIT use cases for each customer/cross-tenant scenario
- Create custom roles with least privilege for common tasks
- Establish PIM-eligible security groups in managing tenant
- Configure PIM policies with appropriate approval workflows
- Integrate Lighthouse delegations with PIM group principals
- Set up monitoring and alerting for PIM activations
- [ Conduct access reviews regularly
- Document procedures for emergency and routine JIT access
- Train users on PIM activation and justification requirements
Summary
Using Entra ID PIM for JIT access in cross-tenant management provides:
✅ Time-bound, approved access to customer resources
✅ Audit trail of all activations and justifications
✅ Reduced standing privileges across tenant boundaries
✅ Flexible approval workflows involving customer stakeholders
✅ Integration with Conditional Access for additional security controls
The key is combining PIM’s eligibility model with Azure Lighthouse’s resource delegation to create a secure, auditable, and efficient cross-tenant access management system.
what are options for cross tenant management using Entra ID Conditional Access Policy
Excellent question! Using Entra ID Conditional Access (CA) for cross-tenant management provides critical security controls that extend beyond your tenant boundaries. Here are the comprehensive options and implementation patterns:
- Core Architecture: Where Conditional Access Applies
Key Understanding:
- CA policies are enforced in the tenant where the identity resides
- For cross-tenant scenarios, this means:
- Your managing tenant: Controls access for YOUR employees
- Customer tenants: Control access for THEIR employees accessing your services
- Conditional Access for Azure Lighthouse Scenarios
Pattern A: Protect Access TO Customer Resources
Apply CA policies in YOUR managing tenant to control how your staff accesses delegated customer resources:
json
// CA Policy: Require MFA and compliant device for service desk
{
“displayName”: “CA01 – Lighthouse Access – Require MFA + Compliant Device”,
“users”: {
“include”: [“Lighthouse-ServiceDesk-Group”],
“exclude”: [“Break-Glass-Accounts”]
},
“applications”: {
“include”: [“Microsoft Azure Management”]
},
“conditions”: {
“locations”: {
“include”: [“All”]
},
“clientApps”: {
“include”: [“Browser”, “MobileAppsAndDesktopClients”]
}
},
“grant”: {
“operator”: “AND”,
“controls”: [
{ “control”: “RequireMultiFactorAuthentication” },
{ “control”: “RequireCompliantDevice” }
]
}
}
Pattern B: Time and Location-Based Restrictions
json
// CA Policy: Restrict support hours and locations
{
“displayName”: “CA02 – Lighthouse – Business Hours Only”,
“users”: {
“include”: [“All-Lighthouse-Engineers”]
},
“applications”: {
“include”: [“Microsoft Azure Management”]
},
“conditions”: {
“locations”: {
“include”: [“Corporate-IP-Ranges”],
“exclude”: [“All”]
},
“times”: {
“include”: [
{“day”: “monday”, “hours”: “0600-1800”},
{“day”: “tuesday”, “hours”: “0600-1800”},
{“day”: “friday”, “hours”: “0600-1700”}
],
“exclude”: [“All”]
}
},
“grant”: {
“operator”: “OR”,
“controls”: [
{ “control”: “Block” }
]
}
}
- Cross-Tenant Access Settings + Conditional Access
Leverage Entra ID Cross-Tenant Access Settings (XTAS) for B2B Collaboration:
Inbound Access Settings (Customers accessing YOUR tenant)
json
// In your managing tenant – control how external users access
{
“tenantRestrictions”: {
“partnerTenantId”: “customer-tenant-id”,
“inboundTrust”: {
“mfa”: “acceptsMfa”,
“compliance”: “acceptsCompliance”
},
“inboundAccess”: {
“applications”: {
“accessType”: “allowed”,
“targetApplications”: [“your-saas-app-id”]
}
}
}
}
Outbound Access Settings (Your users accessing CUSTOMER tenants)
json
// In your managing tenant – control what your users can access externally
{
“tenantRestrictions”: {
“partnerTenantId”: “customer-tenant-id”,
“outboundAccess”: {
“applications”: {
“accessType”: “blocked”,
“targetApplications”: [“unsanctioned-customer-app-id”]
}
}
}
}
- Specific Conditional Access Policy Examples for Cross-Tenant
Policy 1: High-Risk Customer Access
json
{
“displayName”: “CA03 – High-Risk Customers – Require MFA + Trusted Location”,
“users”: {
“include”: [“High-Risk-Customer-Support-Team”]
},
“applications”: {
“include”: [“Microsoft Azure Management”]
},
“conditions”: {
“locations”: {
“include”: [“Trusted-IP-Ranges”],
“exclude”: [“All”]
},
“userRisk”: {
“include”: [“High”, “Medium”]
}
},
“grant”: {
“operator”: “AND”,
“controls”: [
{ “control”: “RequireMultiFactorAuthentication” },
{ “control”: “RequirePasswordChange” }
]
}
}
Policy 2: Customer Data Protection
json
{
“displayName”: “CA04 – Customer Data – Require App Protection”,
“users”: {
“include”: [“All-Customer-Facing-Users”]
},
“applications”: {
“include”: [“Office365”, “Your-Customer-Portal-App”]
},
“conditions”: {
“clientApps”: {
“include”: [“MobileAppsAndDesktopClients”]
},
“platforms”: {
“include”: [“Android”, “iOS”]
}
},
“grant”: {
“operator”: “OR”,
“controls”: [
{ “control”: “RequireAppProtectionPolicy” },
{ “control”: “Block” }
]
}
}
Policy 3: Session Management for Customer Access
json
{
“displayName”: “CA05 – Customer Portal – Sign-in Frequency”,
“users”: {
“include”: [“External-Collaborators-Group”]
},
“applications”: {
“include”: [“Your-Customer-Portal-App”]
},
“session”: {
“signInFrequency”: {
“value”: 4,
“type”: “hours”,
“isEnabled”: true
},
“persistentBrowser”: {
“mode”: “never”,
“isEnabled”: true
}
},
“grant”: {
“operator”: “OR”,
“controls”: [
{ “control”: “Block” }
]
}
}
- Advanced Cross-Tenant Conditional Access Patterns
Pattern 1: Tiered Access Based on Customer Sensitivity
Pattern 2: Customer-Specific CA Policies
Create dynamic groups based on customer assignments:
json
// CA Policy for Financial Services Customers
{
“displayName”: “CA-FinServ-Customers – Stricter Controls”,
“users”: {
“include”: [“FinServ-Support-Team-DynamicGroup”]
},
“applications”: {
“include”: [“Microsoft Azure Management”]
},
“grant”: {
“operator”: “AND”,
“controls”: [
{ “control”: “RequireMultiFactorAuthentication” },
{ “control”: “RequireCompliantDevice” },
{ “control”: “RequireApprovedClientApp” }
]
}
}
Pattern 3: Break-Glass Emergency Access
json
{
“displayName”: “CA-BreakGlass – Emergency Bypass”,
“users”: {
“include”: [“Break-Glass-Accounts”]
},
“applications”: {
“include”: [“All”]
},
“grant”: {
“operator”: “OR”,
“controls”: [
{ “control”: “Block” }
]
},
“session”: null,
“state”: “disabled” // Enable only during emergencies
}
- Integration with Other Entra ID Capabilities
- Conditional Access + Identity Protection
json
// Automatically require password reset for risky sign-ins
{
“displayName”: “CA-Risky-Signins – Cross-Tenant Access”,
“users”: {
“include”: [“All-Lighthouse-Users”]
},
“applications”: {
“include”: [“Microsoft Azure Management”]
},
“conditions”: {
“userRisk”: {
“include”: [“High”]
}
},
“grant”: {
“operator”: “OR”,
“controls”: [
{ “control”: “RequirePasswordChange” },
{ “control”: “Block” }
]
}
}
- Conditional Access + Terms of Use
json
// Require acceptance of customer data handling policy
{
“displayName”: “CA-Require-Data-Agreement”,
“users”: {
“include”: [“All-Customer-Facing-Users”]
},
“applications”: {
“include”: [“Microsoft Azure Management”, “Your-Customer-Portal”]
},
“grant”: {
“operator”: “AND”,
“controls”: [
{ “control”: “RequireTermsOfUse” },
{ “control”: “RequireMultiFactorAuthentication” }
]
}
}
- Device Filter-based Policies
json
// Use device filters for granular control
{
“displayName”: “CA-Corporate-Devices-Only”,
“users”: {
“include”: [“Lighthouse-Engineering-Team”]
},
“applications”: {
“include”: [“Microsoft Azure Management”]
},
“conditions”: {
“devices”: {
“deviceFilter”: {
“mode”: “include”,
“rule”: “device.trustType -ne \”ServerAD\” -or device.isCompliant -eq True”
}
}
},
“grant”: {
“operator”: “OR”,
“controls”: [
{ “control”: “Block” }
]
}
}
- Monitoring and Reporting for Cross-Tenant CA
- Azure Monitor Workbooks for Cross-Tenant Insights
kusto
// KQL query for cross-tenant CA monitoring
SigninLogs
| where ConditionalAccessPolicies != “[]”
| where ResourceTenantId != HomeTenantId
| extend CAResult = ConditionalAccessPolicies[0].result
| project TimeGenerated, UserPrincipalName, AppDisplayName,
ResourceTenantId, CAResult, IPAddress, Location
- Alert Rules for Cross-Tenant Policy Failures
json
{
“alertRule”: {
“displayName”: “Cross-Tenant CA Blocked Sign-ins”,
“description”: “Alert when CA policies block cross-tenant access”,
“condition”: {
“allOf”: [
{
“field”: “SigninLogs”,
“operator”: “Contains”,
“value”: “block”
},
{
“field”: “SigninLogs”,
“operator”: “Contains”,
“value”: “ResourceTenantId”
}
]
},
“actions”: [
{
“actionGroupId”: “/subscriptions/…/actionGroups/SecurityTeam”
}
]
}
}
- Implementation Strategy and Best Practices
Phase 1: Baseline Policies
- Require MFA for all external access
- Block legacy authentication protocols
- Require compliant devices for administrative access
Phase 2: Customer-Specific Policies
- Create customer sensitivity tiers
- Implement location-based restrictions for high-sensitivity customers
- Configure session controls for external applications
Phase 3: Advanced Protections
- Integrate with Identity Protection for risk-based policies
- Implement Terms of Use for data handling agreements
- Create emergency access procedures with appropriate controls
Best Practices:
- Use report-only mode initially to test policies
- Create dynamic groups for customer-based assignments
- Monitor sign-in logs specifically for cross-tenant activity
- Regularly review and update CA policies based on new threats
- Coordinate with customers on their CA requirements and trusted locations
- Customer Communication Template
When implementing cross-tenant CA policies, communicate with customers:
text
Subject: Enhanced Security Controls for Your Azure Environment
Dear [Customer Name],
As part of our ongoing security commitment, we’re implementing additional Conditional Access controls for accessing your Azure environment:
- Multi-Factor Authentication required for all support access
- Device compliance requirements for administrative tasks
- Location-based restrictions aligned with your security policies
- Session timeouts for extended access periods
These controls help ensure that access to your environment meets the highest security standards.
Please whitelist our corporate IP ranges: [Your IP Ranges]
Summary
Using Entra ID Conditional Access for cross-tenant management provides:
✅ Granular security controls based on user, device, location, and risk
✅ Consistent policy enforcement across all customer tenants
✅ Risk-based access decisions using Identity Protection integration
✅ Session controls for sensitive customer data access
✅ Compliance alignment with customer security requirements
The key is layering CA policies that become progressively stricter based on customer sensitivity and access scenarios, while maintaining operational efficiency through proper planning and communication.
what are options for cross tenant management using Azure centralised logging and monitoring?
Excellent question! Centralized logging and monitoring is a critical component of effective cross-tenant management, providing visibility, security, and operational insights across all customer environments. Here are the comprehensive options and patterns:
- Core Architecture Patterns
Pattern A: Hub-and-Spoke Model (Recommended)
Central Logging Workspace in Managing Tenant
- Single Log Analytics workspace in your managing tenant
- Data collected from all customer tenants
- Unified querying, alerting, and dashboards
Pattern B: Regional Hub Model
Multiple Central Workspaces (e.g., East US, West Europe)
- Works better for data residency requirements
- More complex to manage but addresses compliance needs
Pattern C: Customer-Specific with Central Aggregation
Local workspaces in customer tenants + central aggregation
- Customers retain their own data
- Selective data forwarded to central location
- Data Collection Methods
Method 1: Azure Monitor Agent (AMA) – Cross-Workspace
Collect data from customer VMs/Resources directly to your central workspace
json
// Data Collection Rule (DCR) in customer tenant targeting central workspace
{
“location”: “eastus”,
“properties”: {
“dataSources”: {
“performanceCounters”: [
{
“name”: “perfCounterDataSource”,
“streams”: [“Microsoft-Perf”],
“scheduledTransferPeriod”: “PT1M”,
“samplingFrequencyInSeconds”: 60,
“counterSpecifier”: “\\Processor(_Total)\\% Processor Time”
}
],
“windowsEventLogs”: [
{
“name”: “eventLogDataSource”,
“streams”: [“Microsoft-WindowsEvent”],
“scheduledTransferPeriod”: “PT1M”,
“xPathQueries”: [“Security!*[System[(Level=1 or Level=2 or Level=3)]]”]
}
]
},
“destinations”: {
“logAnalytics”: [
{
“workspaceResourceId”: “/subscriptions/{managing-sub}/resourcegroups/{rg}/providers/microsoft.operationalinsights/workspaces/{central-workspace}”,
“name”: “centralWorkspace”
}
]
},
“dataFlows”: [
{
“streams”: [“Microsoft-Perf”, “Microsoft-WindowsEvent”],
“destinations”: [“centralWorkspace”]
}
]
}
}
Method 2: Diagnostic Settings – Cross-Tenant
Send Azure resource logs directly to central workspace
json
// Diagnostic setting on customer resource
{
“properties”: {
“workspaceId”: “/subscriptions/{managing-sub}/resourceGroups/{rg}/providers/Microsoft.OperationalInsights/workspaces/{central-workspace}”,
“logs”: [
{
“category”: “Administrative”,
“enabled”: true,
“retentionPolicy”: {
“days”: 90,
“enabled”: true
}
}
]
}
}
Method 3: Azure Lighthouse-Aware Queries
Query across multiple workspaces using KQL
kql
// Cross-workspace query from managing tenant
union workspace(‘customer1-workspace’).SecurityEvent,
workspace(‘customer2-workspace’).SecurityEvent,
workspace(‘customer3-workspace’).SecurityEvent
| where TimeGenerated >= ago(24h)
| where EventID == 4624 // Successful logons
| project TimeGenerated, Computer, Account, IpAddress, Workspace = _ResourceId
- Centralized Monitoring Solutions
- Azure Dashboard – Cross-Tenant Views
Create unified dashboards in managing tenant
json
{
“lenses”: {
“0”: {
“order”: 0,
“parts”: [
{
“position”: {
“x”: 0,
“y”: 0,
“rowSpan”: 2,
“colSpan”: 3
},
“metadata”: {
“type”: “Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart”,
“inputs”: [
{
“name”: “Query”,
“value”: “Perf | summarize AggregatedValue = avg(CounterValue) by Computer, bin(TimeGenerated, 1h) | where Computer contains ‘customer'”
}
]
}
}
]
}
}
}
- Azure Monitor Workbooks – Multi-Tenant Reporting
Interactive reports with tenant filtering
json
// Workbook template for cross-tenant security overview
{
“version”: “1.0”,
“items”: [
{
“type”: “query”,
“content”: {
“query”: “SecurityEvent | where TimeGenerated >= ago(7d) | summarize EventCount = count() by Tenant = tostring(split(_ResourceId, ‘/’)[8]), Activity”,
“size”: 20,
“title”: “Security Events by Tenant”,
“visualization”: “barchart”
}
}
],
“parameters”: [
{
“name”: “TenantFilter”,
“type”: “dropdown”,
“label”: “Select Tenant”,
“query”: “find where TimeGenerated > ago(1h) | distinct Tenant”
}
]
}
- Azure Monitor Alerts – Cross-Tenant Alerting
Unified alert rules covering all customers
json
// Alert rule for critical security events across all tenants
{
“location”: “global”,
“properties”: {
“description”: “Alert on critical security events across all customer tenants”,
“severity”: 1,
“enabled”: true,
“condition”: {
“allOf”: [
{
“field”: “Entities”,
“operator”: “Contains”,
“values”: [“SecurityEvent”]
},
{
“field”: “AlertSeverity”,
“operator”: “Equals”,
“values”: [“High”]
}
]
},
“actions”: [
{
“actionGroupId”: “/subscriptions/{sub}/resourceGroups/{rg}/providers/microsoft.insights/actionGroups/CrossTenant-SecurityTeam”
}
]
}
}
- Specific Cross-Tenant Monitoring Scenarios
Scenario 1: Security & Compliance Monitoring
kql
// Cross-tenant security baseline monitoring
let timeRange = 1h;
union isfuzzy=true
workspace(‘customer1-workspace’).SecurityEvent,
workspace(‘customer2-workspace’).SecurityEvent,
workspace(‘customer3-workspace’).SecurityEvent
| where TimeGenerated >= ago(timeRange)
| where EventID in (4625, 4648, 4672) // Failed logons, special privileges
| extend Tenant = extract(@”\/subscriptions\/([^\/]+)”, 1, _ResourceId)
| summarize FailedAttempts = count() by Tenant, Account, Computer, bin(TimeGenerated, 15m)
| where FailedAttempts > 5
Scenario 2: Performance & Health Monitoring
kql
// Cross-tenant performance analysis
Perf
| where TimeGenerated >= ago(1h)
| where ObjectName == “Processor” and CounterName == “% Processor Time”
| extend Tenant = tostring(split(_ResourceId, ‘/’)[8])
| summarize
AvgCPU = avg(CounterValue),
P95CPU = percentile(CounterValue, 95),
MaxCPU = max(CounterValue)
by Tenant, Computer, bin(TimeGenerated, 5m)
| where AvgCPU > 80
Scenario 3: Cost & Resource Optimization
kql
// Cross-tenant resource utilization and cost tracking
AzureActivity
| where TimeGenerated >= ago(7d)
| where OperationNameValue endswith “write”
| extend ResourceType = tostring(parse_json(Properties).entity),
Tenant = Caller
| summarize
ResourceChanges = count(),
DistinctUsers = dcount(Caller)
by Tenant, ResourceType, bin(TimeGenerated, 1d)
- Advanced Centralized Logging Patterns
Pattern 1: Tiered Data Collection
json
// Different data collection rules based on customer tier
{
“BasicTier”: {
“performanceCounters”: [“\\Processor\\% Processor Time”, “\\Memory\\Available MBytes”],
“eventLogs”: [“Security”, “System”],
“samplingFrequency”: “PT5M”
},
“PremiumTier”: {
“performanceCounters”: [“*”], // All counters
“eventLogs”: [“Security”, “System”, “Application”, “Windows PowerShell”],
“samplingFrequency”: “PT1M”,
“syslog”: [“auth”, “authpriv”, “daemon”]
}
}
Pattern 2: Customer-Specific Data Routing
kql
// KQL function for customer-specific data routing
let CustomerDataRouting = (customerName: string) {
union
workspace(${customerName}-infra).Perf,
workspace(${customerName}-apps).AppExceptions,
workspace(${customerName}-sec).SecurityEvent
};
CustomerDataRouting(“Contoso”)
| where TimeGenerated >= ago(1h)
Pattern 3: Automated Baseline & Anomaly Detection
kql
// Cross-tenant anomaly detection
let baselineData =
Perf
| where TimeGenerated >= ago(30d)
| where ObjectName == “Processor” and CounterName == “% Processor Time”
| summarize baseline=percentile(CounterValue, 95) by Computer;
Perf
| where TimeGenerated >= ago(1h)
| where ObjectName == “Processor” and CounterName == “% Processor Time”
| join kind=inner baselineData on Computer
| extend deviation = CounterValue – baseline
| where deviation > 20 // More than 20% above baseline
| project TimeGenerated, Computer, CounterValue, baseline, deviation, Tenant
- Integration with Azure Services
- Azure Sentinel for Cross-Tenant SIEM
kql
// Sentinel cross-workspace hunting query
union isfuzzy=true workspace(‘customer1’).SecurityEvent,
workspace(‘customer2’).SecurityEvent,
workspace(‘customer3’).SecurityEvent
| where TimeGenerated >= ago(1d)
| where EventID == 4688 // Process creation
| where NewProcessName contains “powershell”
| extend CommandLine = tostring(CommandLine)
| where CommandLine contains “-EncodedCommand”
| project TimeGenerated, Computer, Account, CommandLine, Tenant
- Azure Resource Graph for Inventory
kql
// Cross-tenant resource inventory
Resources
| where type in~ (‘microsoft.compute/virtualmachines’, ‘microsoft.network/virtualnetworks’)
| extend Tenant = subscriptionId
| project Tenant, ResourceType = type, Name, Location, SKU, Status = properties.provisioningState
- Application Insights Cross-Tenant
kql
// Monitor multi-tenant applications
union app(‘customer1-app’).requests,
app(‘customer2-app’).requests,
app(‘customer3-app’).requests
| where timestamp >= ago(1h)
| summarize
TotalRequests = count(),
FailedRequests = countif(success == false),
AvgDuration = avg(duration)
by Customer = appName, bin(timestamp, 5m)
- Automation and Deployment
- ARM Template for Cross-Tenant Monitoring
json
{
“$schema”: “https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“customerSubscriptionId”: { “type”: “string” },
“centralWorkspaceId”: { “type”: “string” }
},
“resources”: [
{
“type”: “Microsoft.Resources/deployments”,
“apiVersion”: “2020-10-01”,
“name”: “crossTenantMonitoring”,
“subscriptionId”: “[parameters(‘customerSubscriptionId’)]”,
“properties”: {
“mode”: “Incremental”,
“template”: {
“$schema”: “https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“resources”: [
{
“type”: “Microsoft.Insights/dataCollectionRules”,
“apiVersion”: “2022-06-01”,
“name”: “CrossTenant-DCR”,
“location”: “eastus”,
“properties”: {
“dataSources”: {
“performanceCounters”: [/*…*/],
“windowsEventLogs”: [/*…*/]
},
“destinations”: {
“logAnalytics”: [
{
“workspaceResourceId”: “[parameters(‘centralWorkspaceId’)]”,
“name”: “centralLogs”
}
]
},
“dataFlows”: [/*…*/]
}
}
]
}
}
}
]
}
- PowerShell Automation
powershell
# Deploy cross-tenant monitoring at scale
function Deploy-CrossTenantMonitoring {
param(
[string[]]$CustomerSubscriptions,
[string]$CentralWorkspaceId
)
foreach ($sub in $CustomerSubscriptions) {
# Set context to customer subscription
Set-AzContext -SubscriptionId $sub
# Create Data Collection Rule
New-AzDataCollectionRule -ResourceGroupName “monitoring-rg” -Name “CrossTenant-DCR” -Location “EastUS” -JsonString (Get-DCRTemplate -WorkspaceId $CentralWorkspaceId)
# Deploy diagnostic settings to key resources
Set-AzDiagnosticSetting -ResourceId “/subscriptions/$sub/resourceGroups/*” -WorkspaceId $CentralWorkspaceId -Enabled $true
}
}
- Security and Compliance Considerations
- Data Segregation and Access Control
json
// Azure RBAC for workspace access with customer context
{
“role”: “Log Analytics Reader”,
“scope”: “/subscriptions/{central-sub}/resourceGroups/{rg}/providers/Microsoft.OperationalInsights/workspaces/{workspace}”,
“conditions”: [
{
“condition”: “(@Resource[Microsoft.OperationalInsights/workspaces:TenantId] StringEqualsIgnoreCase ‘customer-tenant-id’)”
}
]
}
- Data Retention Policies
json
// Tiered retention based on data sensitivity
{
“tableLevelRetentionPolicies”: {
“SecurityEvent”: 365, // 1 year for security
“Perf”: 93, // 93 days for performance
“Heartbeat”: 30, // 30 days for heartbeat
“AzureActivity”: 180 // 6 months for activity logs
}
}
- Cost Management
kql
// Monitor and optimize cross-tenant logging costs
Usage
| where TimeGenerated >= ago(30d)
| where DataType in (“Perf”, “SecurityEvent”, “WindowsEvent”)
| extend Tenant = tostring(split(_ResourceId, ‘/’)[8])
| summarize
TotalGB = sum(Quantity),
EstimatedCost = sum(Quantity) * 2.76 // Per GB pricing
by Tenant, DataType, bin(TimeGenerated, 1d)
- Implementation Checklist
- Design data collection strategy (what, how, where)
- Establish central Log Analytics workspace in managing tenant
- Configure cross-tenant data collection rules using Lighthouse
- Implement diagnostic settings for Azure resource logs
- Create unified dashboards and workbooks
- Set up cross-tenant alert rules
- Establish data retention and archiving policies
- Implement access controls and data segregation
- Configure cost monitoring and optimization
- Develop runbooks for common issues
- Establish compliance and audit reporting
Summary
Centralized logging and monitoring for cross-tenant management provides:
✅ Unified visibility across all customer environments
✅ Standardized alerting and incident response
✅ Cost-effective data aggregation and analysis
✅ Security compliance and audit capabilities
✅ Operational efficiency through automation
✅ Proactive monitoring and trend analysis
The key success factors are proper architecture planning, automated deployment, careful cost management, and maintaining appropriate data segregation while still achieving the benefits of centralized visibility.
what are options for cross tenant management using Naming Convention and Tagging?
Excellent question! Naming conventions and tagging are foundational for effective cross-tenant management, providing organization, automation, and cost management across multiple customer environments. Here are comprehensive options and patterns:
- Cross-Tenant Naming Convention Framework
- Resource Naming Standard Structure
text
{tenant}-{environment}-{location}-{service}-{instance}-{role}
Example Implementation:
json
{
“namingStandard”: {
“tenant”: [“contoso”, “fabrikam”, “adventureworks”],
“environment”: [“prod”, “dev”, “test”, “stg”, “uat”],
“location”: [“eus”, “weu”, “neu”, “sea”],
“service”: [“vm”, “sql”, “str”, “vnet”, “nsg”],
“instance”: [“001”, “002”, “web”, “api”, “db”],
“role”: [“primary”, “secondary”, “dr”, “mgmt”]
}
}
- Real-World Naming Examples
bash
# Virtual Machine
contoso-prod-eus-vm-web-001
fabrikam-dev-weu-vm-sql-primary
# Storage Account (with uniqueness)
contosoprodstrweubackup001
fabrikamdevstrsuslogs002
# Virtual Network
contoso-prod-eus-vnet-core-001
fabrikam-dev-weu-vnet-app-001
# Resource Group
rg-contoso-prod-eus-network
rg-fabrikam-dev-weu-databases
- Comprehensive Tagging Strategy for Cross-Tenant
- Mandatory Tags for All Resources
json
{
“mandatoryTags”: {
“Tenant”: “contoso”,
“Environment”: “production”,
“CostCenter”: “IT-12345”,
“Project”: “CustomerPortal”,
“ManagedBy”: “MSP-Operations”,
“DataClassification”: “Confidential”,
“Compliance”: “PCI-DSS”,
“DeploymentVersion”: “v2.1.0”
}
}
- Operational Tags
json
{
“operationalTags”: {
“ApplicationOwner”: “customer-support@company.com”,
“TechnicalOwner”: “azure-team@msp.com”,
“SupportTier”: “24×7-Premium”,
“BackupRetention”: “30-days”,
“MaintenanceWindow”: “Sat-02:00-04:00-UTC”,
“DRPriority”: “Tier-1”,
“AutoShutdown”: “Enabled”
}
}
- Business and Billing Tags
json
{
“businessTags”: {
“BusinessUnit”: “Customer-Facing-Apps”,
“InvoiceGroup”: “Contoso-Q2-2024”,
“ChargebackDepartment”: “IT-Infrastructure”,
“ProjectID”: “PRJ-2024-001”,
“CustomerPO”: “PO-789123”,
“ServiceLevel”: “Gold”
}
}
- Implementation Patterns
Pattern A: ARM Template Tag Inheritance
json
{
“$schema”: “https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“tenantCode”: { “type”: “string” },
“environment”: { “type”: “string” },
“projectName”: { “type”: “string” }
},
“variables”: {
“baseTags”: {
“Tenant”: “[parameters(‘tenantCode’)]”,
“Environment”: “[parameters(‘environment’)]”,
“Project”: “[parameters(‘projectName’)]”,
“DeploymentDate”: “[utcNow()]”,
“ManagedBy”: “AzureLighthouse-MSP”
}
},
“resources”: [
{
“type”: “Microsoft.Compute/virtualMachines”,
“apiVersion”: “2023-03-01”,
“name”: “[concat(parameters(‘tenantCode’), ‘-‘, parameters(‘environment’), ‘-vm-web-001’)]”,
“location”: “[resourceGroup().location]”,
“tags”: “[variables(‘baseTags’)]”,
“properties”: { /* VM properties */ }
}
]
}
Pattern B: Azure Policy for Tag Enforcement
json
{
“mode”: “Indexed”,
“policyRule”: {
“if”: {
“allOf”: [
{
“field”: “type”,
“equals”: “Microsoft.Resources/subscriptions/resourceGroups”
},
{
“field”: “tags[‘Tenant’]”,
“exists”: false
}
]
},
“then”: {
“effect”: “append”,
“details”: [
{
“field”: “tags[‘Tenant’]”,
“value”: “[subscription().displayName]”
},
{
“field”: “tags[‘Environment’]”,
“value”: “unspecified”
},
{
“field”: “tags[‘ManagedBy’]”,
“value”: “cross-tenant-mgmt”
}
]
}
}
}
Pattern C: PowerShell Automation for Tag Management
powershell
function Set-CrossTenantTags {
param(
[string]$TenantName,
[string]$Environment,
[string]$CostCenter,
[string]$SubscriptionId
)
$tags = @{
“Tenant” = $TenantName
“Environment” = $Environment
“CostCenter” = $CostCenter
“ManagedBy” = “Azure-Lighthouse-MSP”
“Compliance” = “Standard”
“LastReviewed” = (Get-Date).ToString(“yyyy-MM-dd”)
}
# Apply to subscription
New-AzSubscriptionTag -Tag $tags -SubscriptionId $SubscriptionId
# Apply to all resource groups
$resourceGroups = Get-AzResourceGroup -SubscriptionId $SubscriptionId
foreach ($rg in $resourceGroups) {
Update-AzTag -ResourceId $rg.ResourceId -Tag $tags -Operation Merge
}
}
- Cross-Tenant Resource Identification
- Azure Resource Graph Queries with Tags
kql
// Find all resources by tenant
Resources
| where tags[‘Tenant’] =~ ‘contoso’
| project name, type, resourceGroup, subscriptionId, location, tags
// Cost analysis by tenant and environment
Resources
| where isnotempty(tags[‘Tenant’])
| extend Tenant = tags[‘Tenant’], Environment = tags[‘Environment’]
| join (ResourceContainers | where type=~’microsoft.resources/subscriptions’ | project subscriptionId, subscriptionName) on subscriptionId
| summarize TotalCost = sum(todouble(properties.cost)) by Tenant, Environment, subscriptionName
// Compliance reporting
Resources
| where tags[‘Compliance’] != ‘Compliant’
| extend Tenant = tags[‘Tenant’], Owner = tags[‘ApplicationOwner’]
| project name, type, resourceGroup, Tenant, Owner, ComplianceStatus = tags[‘Compliance’]
- Automated Discovery and Tagging
powershell
function Discover-AndTag-TenantResources {
param([string]$SubscriptionId, [string]$TenantCode)
Set-AzContext -SubscriptionId $SubscriptionId
$resources = Get-AzResource -SubscriptionId $SubscriptionId
foreach ($resource in $resources) {
$currentTags = $resource.Tags
if (!$currentTags) { $currentTags = @{} }
# Add cross-tenant tags if missing
if (!$currentTags[‘Tenant’]) {
$currentTags[‘Tenant’] = $TenantCode
}
if (!$currentTags[‘Environment’]) {
$currentTags[‘Environment’] = Infer-Environment -ResourceName $resource.Name
}
if (!$currentTags[‘ManagedBy’]) {
$currentTags[‘ManagedBy’] = “Azure-Lighthouse”
}
# Update resource tags
Set-AzResource -ResourceId $resource.ResourceId -Tag $currentTags -Force
}
}
- Cost Management and Chargeback
- Cost Allocation Tags
json
{
“chargebackTags”: {
“BillingEntity”: “Contoso-Corporate”,
“Department”: “Marketing-Digital”,
“CostCenter”: “CC-MKT-2024-Q2”,
“ProjectCode”: “PROJ-CONTOSO-REDESIGN”,
“BusinessUnit”: “Digital-Transformation”,
“ServiceCatalog”: “Web-Hosting-Services”
}
}
- Cost Analysis Queries
kql
// Cost by tenant and environment
CostManagement
| where TimeGenerated >= ago(30d)
| extend Tenant = tags[‘Tenant’], Environment = tags[‘Environment’]
| where isnotempty(Tenant)
| summarize TotalCost = sum(Cost) by Tenant, Environment, ServiceName
| order by TotalCost desc
// Chargeback reporting
Resources
| extend Department = tags[‘Department’], ProjectCode = tags[‘ProjectCode’]
| where isnotempty(Department)
| join (CostManagement | where Date >= startofmonth(now())) on $left.id == $right.ResourceId
| summarize
DepartmentCost = sum(Cost),
ResourceCount = count()
by Department, ProjectCode, ServiceName
- Security and Compliance Tagging
- Security Classification Tags
json
{
“securityTags”: {
“DataClassification”: “Public|Internal|Confidential|Restricted”,
“PII”: “Yes|No”,
“GDPR”: “Applicable|NotApplicable”,
“BackupRequired”: “Yes|No”,
“EncryptionRequired”: “Yes|No”,
“SecurityZone”: “DMZ|Internal|Management”
}
}
- Compliance Enforcement via Policy
json
{
“if”: {
“allOf”: [
{
“field”: “type”,
“equals”: “Microsoft.Storage/storageAccounts”
},
{
“field”: “tags[‘DataClassification’]”,
“equals”: “Confidential”
},
{
“field”: “Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly”,
“notEquals”: true
}
]
},
“then”: {
“effect”: “deny”,
“details”: {
“message”: “Storage accounts with Confidential data must have HTTPS only enabled”
}
}
}
- Automation and Governance
- Azure DevOps Pipeline for Tag Enforcement
yaml
# azure-pipelines.yml
stages:
– stage: ValidateTags
jobs:
– job: CheckResourceTags
steps:
– task: AzureCLI@2
inputs:
azureSubscription: ‘lighthouse-connection’
scriptType: ‘pscore’
scriptLocation: ‘inlineScript’
inlineScript: |
$requiredTags = @(‘Tenant’, ‘Environment’, ‘CostCenter’, ‘ManagedBy’)
$resources = az graph query -q “Resources | where resourceGroup =~ ‘$(resourceGroup)'” –output json | ConvertFrom-Json
foreach ($resource in $resources.data) {
foreach ($tag in $requiredTags) {
if (!$resource.tags.$tag) {
Write-Error “Resource $($resource.name) is missing required tag: $tag”
exit 1
}
}
}
– stage: ApplyDefaultTags
jobs:
– job: TagResources
steps:
– task: AzurePowerShell@5
inputs:
azureSubscription: ‘lighthouse-connection’
ScriptType: ‘InlineScript’
Inline: |
$tags = @{
Tenant = ‘$(tenantName)’
Environment = ‘$(environment)’
ManagedBy = ‘Azure-Lighthouse’
DeploymentPipeline = ‘$(Build.DefinitionName)’
BuildId = ‘$(Build.BuildId)’
}
Set-AzResourceGroup -Name ‘$(resourceGroup)’ -Tag $tags
- Azure Function for Tag Maintenance
csharp
// C# Azure Function for automated tag management
[FunctionName(“CrossTenantTagManager”)]
public static async Task Run([TimerTrigger(“0 0 2 * * *”)] TimerInfo myTimer, ILogger log)
{
var tenants = await GetManagedTenantsAsync();
foreach (var tenant in tenants)
{
var resources = await GetTenantResourcesAsync(tenant.SubscriptionId);
foreach (var resource in resources)
{
var updatedTags = EnsureRequiredTags(resource.Tags, tenant);
if (updatedTags != resource.Tags)
{
await UpdateResourceTagsAsync(resource.ResourceId, updatedTags);
}
}
}
}
private static IDictionary<string, string> EnsureRequiredTags(
IDictionary<string, string> currentTags,
TenantInfo tenant)
{
var requiredTags = new Dictionary<string, string>
{
[“Tenant”] = tenant.Code,
[“Environment”] = tenant.Environment,
[“ManagedBy”] = “Azure-Lighthouse-MSP”,
[“LastTagReview”] = DateTime.UtcNow.ToString(“yyyy-MM-dd”)
};
// Merge with existing tags
return requiredTags
.Concat(currentTags ?? new Dictionary<string, string>())
.GroupBy(kvp => kvp.Key)
.ToDictionary(g => g.Key, g => g.First().Value);
}
- Monitoring and Reporting
- Tag Compliance Dashboard
kql
// Tag compliance reporting
Resources
| extend
Tenant = tags[‘Tenant’],
Environment = tags[‘Environment’],
ManagedBy = tags[‘ManagedBy’]
| summarize
TotalResources = count(),
TaggedWithTenant = countif(isnotempty(Tenant)),
TaggedWithEnvironment = countif(isnotempty(Environment)),
TaggedWithManagedBy = countif(isnotempty(ManagedBy))
by subscriptionId
| extend
TenantTagCompliance = TaggedWithTenant * 100 / TotalResources,
EnvironmentTagCompliance = TaggedWithEnvironment * 100 / TotalResources,
ManagedByTagCompliance = TaggedWithManagedBy * 100 / TotalResources
- Resource Inventory by Tenant
kql
// Cross-tenant resource inventory
Resources
| where isnotempty(tags[‘Tenant’])
| extend
Tenant = tags[‘Tenant’],
Environment = tags[‘Environment’],
CostCenter = tags[‘CostCenter’]
| summarize
ResourceCount = count(),
Locations = dcount(location),
ResourceTypes = dcount(type)
by Tenant, Environment
| order by Tenant, Environment
- Implementation Strategy
Phase 1: Foundation
- Define naming convention standard
- Establish mandatory tag dictionary
- Create Azure Policy for tag enforcement
- Document standards for all teams
Phase 2: Implementation
- Apply policies to all managed tenants
- Implement automated tagging solutions
- Update deployment templates with tagging
- Train teams on naming and tagging standards
Phase 3: Optimization
- Implement cost chargeback reporting
- Establish compliance monitoring
- Create automated remediation
- Continuous improvement based on usage patterns
Best Practices:
- Start simple with 5-10 mandatory tags
- Use Azure Policy to enforce standards
- Automate tagging during deployment
- Regularly audit tag compliance
- Educate customers on tagging benefits
- Use consistent casing (PascalCase recommended)
- Document tag values and meanings
Summary
Effective naming conventions and tagging for cross-tenant management provide:
✅ Resource identification across tenant boundaries
✅ Cost management and chargeback capabilities
✅ Automation enablement through consistent patterns
✅ Security and compliance enforcement
✅ Operational efficiency in management tasks
✅ Reporting and analytics across all customers
The key is establishing consistent standards, enforcing them through automation and policy, and continuously refining based on operational experience across all managed tenants.
what are options for cross tenant management using Azure Private Link
Excellent question! Azure Private Link is a crucial component for secure cross-tenant management, enabling private connectivity between your managing tenant and customer environments without exposing services to the public internet. Here are comprehensive options and implementation patterns:
- Core Architecture Patterns
Pattern A: Centralized Private Link Hub
Private connectivity through shared hub virtual network
Pattern B: Direct Private Link per Customer
Dedicated private endpoints for each customer environment
Pattern C: Hybrid DNS Resolution
Central DNS with conditional forwarding to customer DNS
- Private Link for Azure PaaS Services Cross-Tenant
- Key Azure Services Supporting Private Link
- Azure Storage (Blob, File, Table, Queue)
- Azure SQL Database & Azure SQL Managed Instance
- Azure Key Vault
- Azure Container Registry
- Azure App Service & Azure Functions
- Azure Monitor (Log Analytics, Application Insights)
- Azure Backup & Azure Site Recovery
- Azure Automation
- Implementation Template for Storage Private Link
json
{
“$schema”: “https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“customerStorageAccountName”: { “type”: “string” },
“customerSubscriptionId”: { “type”: “string” },
“hubVNetId”: { “type”: “string” },
“privateEndpointSubnetId”: { “type”: “string” }
},
“resources”: [
{
“type”: “Microsoft.Network/privateEndpoints”,
“apiVersion”: “2023-05-01”,
“name”: “[concat(parameters(‘customerStorageAccountName’), ‘-pe’)]”,
“location”: “[resourceGroup().location]”,
“properties”: {
“subnet”: {
“id”: “[parameters(‘privateEndpointSubnetId’)]”
},
“privateLinkServiceConnections”: [
{
“name”: “[concat(parameters(‘customerStorageAccountName’), ‘-pls-connection’)]”,
“properties”: {
“privateLinkServiceId”: “[resourceId(parameters(‘customerSubscriptionId’), ‘Microsoft.Storage/storageAccounts’, parameters(‘customerStorageAccountName’))]”,
“groupIds”: [“blob”]
}
}
]
}
},
{
“type”: “Microsoft.Network/privateDnsZones”,
“apiVersion”: “2020-06-01”,
“name”: “privatelink.blob.core.windows.net”,
“location”: “global”,
“resources”: [
{
“type”: “virtualNetworkLinks”,
“apiVersion”: “2020-06-01”,
“name”: “[concat(‘hub-vnet-link’)]”,
“location”: “global”,
“dependsOn”: [
“[resourceId(‘Microsoft.Network/privateDnsZones’, ‘privatelink.blob.core.windows.net’)]”
],
“properties”: {
“virtualNetwork”: {
“id”: “[parameters(‘hubVNetId’)]”
},
“registrationEnabled”: false
}
}
]
}
]
}
- Cross-Tenant Private Link Scenarios
Scenario 1: Secure Log Analytics Workspace Access
Private connectivity to central Log Analytics workspace
json
{
“resources”: [
{
“type”: “Microsoft.OperationalInsights/clusters”,
“apiVersion”: “2021-06-01”,
“name”: “central-logs-cluster”,
“location”: “eastus”,
“sku”: { “name”: “CapacityReservation”, “capacity”: 1000 }
},
{
“type”: “Microsoft.OperationalInsights/workspaces”,
“apiVersion”: “2020-08-01”,
“name”: “central-logs-workspace”,
“location”: “eastus”,
“properties”: {
“sku”: { “name”: “PerGB2018” },
“features”: {
“clusterResourceId”: “[resourceId(‘Microsoft.OperationalInsights/clusters’, ‘central-logs-cluster’)]”
}
}
},
{
“type”: “Microsoft.Network/privateEndpoints”,
“apiVersion”: “2023-05-01”,
“name”: “la-workspace-pe”,
“location”: “eastus”,
“properties”: {
“subnet”: { “id”: “[variables(‘privateEndpointSubnetId’)]” },
“privateLinkServiceConnections”: [
{
“properties”: {
“privateLinkServiceId”: “[resourceId(‘Microsoft.OperationalInsights/workspaces’, ‘central-logs-workspace’)]”,
“groupIds”: [“api”]
}
}
]
}
}
]
}
Scenario 2: Cross-Tenant Azure Automation
Private connectivity for automation runbooks and update management
json
{
“resources”: [
{
“type”: “Microsoft.Automation/automationAccounts”,
“apiVersion”: “2021-06-22”,
“name”: “cross-tenant-automation”,
“location”: “eastus”,
“properties”: {
“sku”: { “name”: “Basic” },
“publicNetworkAccess”: false // Force private access only
}
},
{
“type”: “Microsoft.Network/privateEndpoints”,
“apiVersion”: “2023-05-01”,
“name”: “automation-account-pe”,
“properties”: {
“subnet”: { “id”: “[variables(‘automationSubnetId’)]” },
“privateLinkServiceConnections”: [
{
“properties”: {
“privateLinkServiceId”: “[resourceId(‘Microsoft.Automation/automationAccounts’, ‘cross-tenant-automation’)]”,
“groupIds”: [“Webhook”, “DSCAndHybridWorker”]
}
}
]
}
}
]
}
Scenario 3: Secure Key Vault Access
Private connectivity for cross-tenant secret management
json
{
“resources”: [
{
“type”: “Microsoft.KeyVault/vaults”,
“apiVersion”: “2023-02-01”,
“name”: “cross-tenant-kv”,
“location”: “eastus”,
“properties”: {
“sku”: { “name”: “standard”, “family”: “A” },
“tenantId”: “[subscription().tenantId]”,
“enableRbacAuthorization”: true,
“publicNetworkAccess”: “Disabled” // Enforce private access
}
},
{
“type”: “Microsoft.Network/privateEndpoints”,
“apiVersion”: “2023-05-01”,
“name”: “keyvault-pe”,
“properties”: {
“subnet”: { “id”: “[variables(‘keyVaultSubnetId’)]” },
“privateLinkServiceConnections”: [
{
“properties”: {
“privateLinkServiceId”: “[resourceId(‘Microsoft.KeyVault/vaults’, ‘cross-tenant-kv’)]”,
“groupIds”: [“vault”]
}
}
]
}
}
]
}
- DNS Configuration for Cross-Tenant Private Link
- Central Private DNS Zones in Hub
json
{
“resources”: [
{
“type”: “Microsoft.Network/privateDnsZones”,
“apiVersion”: “2020-06-01”,
“name”: “privatelink.blob.core.windows.net”,
“location”: “global”
},
{
“type”: “Microsoft.Network/privateDnsZones”,
“apiVersion”: “2020-06-01”,
“name”: “privatelink.azure-automation.net”,
“location”: “global”
},
{
“type”: “Microsoft.Network/privateDnsZones”,
“apiVersion”: “2020-06-01”,
“name”: “privatelink.vaultcore.azure.net”,
“location”: “global”
},
{
“type”: “Microsoft.Network/privateDnsZones/virtualNetworkLinks”,
“apiVersion”: “2020-06-01”,
“name”: “[concat(‘hub-vnet-link-‘, parameters(‘tenantName’))]”,
“location”: “global”,
“dependsOn”: [
“[resourceId(‘Microsoft.Network/privateDnsZones’, ‘privatelink.blob.core.windows.net’)]”
],
“properties”: {
“virtualNetwork”: {
“id”: “[parameters(‘hubVNetId’)]”
},
“registrationEnabled”: false
}
}
]
}
- PowerShell DNS Configuration
powershell
function Configure-CrossTenantPrivateDNS {
param(
[string]$HubSubscriptionId,
[string]$CustomerSubscriptionId,
[string]$CustomerVNetId
)
# Set context to hub subscription
Set-AzContext -SubscriptionId $HubSubscriptionId
$privateDnsZones = @(
“privatelink.blob.core.windows.net”,
“privatelink.file.core.windows.net”,
“privatelink.azure-automation.net”,
“privatelink.vaultcore.azure.net”,
“privatelink.oms.opinsights.azure.com”,
“privatelink.ods.opinsights.azure.com”,
“privatelink.agentsvc.azure-automation.net”
)
foreach ($zoneName in $privateDnsZones) {
# Create private DNS zone if not exists
$zone = Get-AzPrivateDnsZone -Name $zoneName -ErrorAction SilentlyContinue
if (!$zone) {
$zone = New-AzPrivateDnsZone -Name $zoneName -ResourceGroupName “hub-networking”
}
# Link customer VNet to private DNS zone
$vnetLinkName = “link-$($CustomerSubscriptionId.Replace(‘-‘,”))”
New-AzPrivateDnsVirtualNetworkLink -ZoneName $zoneName -ResourceGroupName “hub-networking” `
-Name $vnetLinkName -VirtualNetworkId $CustomerVNetId
}
}
- Network Security and Access Control
- Network Security Groups for Private Endpoints
json
{
“resources”: [
{
“type”: “Microsoft.Network/networkSecurityGroups”,
“apiVersion”: “2023-05-01”,
“name”: “private-endpoint-nsg”,
“location”: “eastus”,
“properties”: {
“securityRules”: [
{
“name”: “Allow-Hub-To-PrivateEndpoints”,
“properties”: {
“protocol”: “*”,
“sourcePortRange”: “*”,
“destinationPortRange”: “*”,
“sourceAddressPrefix”: “10.1.0.0/16”, # Hub VNet
“destinationAddressPrefix”: “10.2.0.0/16”, # Private Endpoint Subnet
“access”: “Allow”,
“priority”: 100,
“direction”: “Inbound”
}
},
{
“name”: “Deny-Internet-To-PrivateEndpoints”,
“properties”: {
“protocol”: “*”,
“sourcePortRange”: “*”,
“destinationPortRange”: “*”,
“sourceAddressPrefix”: “Internet”,
“destinationAddressPrefix”: “*”,
“access”: “Deny”,
“priority”: 200,
“direction”: “Inbound”
}
}
]
}
}
]
}
- Azure Firewall for Cross-Tenant Traffic
json
{
“resources”: [
{
“type”: “Microsoft.Network/azureFirewalls”,
“apiVersion”: “2023-05-01”,
“name”: “cross-tenant-fw”,
“location”: “eastus”,
“properties”: {
“sku”: { “name”: “AZFW_Hub”, “tier”: “Standard” },
“threatIntelMode”: “Alert”,
“applicationRuleCollections”: [
{
“name”: “Allow-CrossTenant-PaaS”,
“properties”: {
“priority”: 100,
“action”: { “type”: “Allow” },
“rules”: [
{
“name”: “Allow-PrivateLink-Services”,
“protocols”: [{ “protocolType”: “Https”, “port”: 443 }],
“targetFqdns”: [
“*.privatelink.blob.core.windows.net”,
“*.privatelink.azure-automation.net”,
“*.privatelink.vaultcore.azure.net”
],
“sourceAddresses”: [“10.1.0.0/16”]
}
]
}
}
]
}
}
]
}
- Cross-Tenant Connectivity Patterns
Pattern 1: Hub-Spoke with Private Link
json
{
“resources”: [
// Hub Virtual Network
{
“type”: “Microsoft.Network/virtualNetworks”,
“apiVersion”: “2023-05-01”,
“name”: “hub-vnet”,
“location”: “eastus”,
“properties”: {
“addressSpace”: { “addressPrefixes”: [“10.1.0.0/16”] },
“subnets”: [
{
“name”: “AzureBastionSubnet”,
“properties”: { “addressPrefix”: “10.1.1.0/27” }
},
{
“name”: “private-endpoints”,
“properties”: {
“addressPrefix”: “10.1.2.0/24”,
“privateEndpointNetworkPolicies”: “Disabled”
}
}
]
}
},
// VNet Peering to Customer VNets (via Lighthouse)
{
“type”: “Microsoft.Network/virtualNetworks/virtualNetworkPeerings”,
“apiVersion”: “2023-05-01”,
“name”: “hub-to-customer1-peering”,
“dependsOn”: [“[resourceId(‘Microsoft.Network/virtualNetworks’, ‘hub-vnet’)]”],
“properties”: {
“allowVirtualNetworkAccess”: true,
“allowForwardedTraffic”: true,
“allowGatewayTransit”: false,
“useRemoteGateways”: false,
“remoteVirtualNetwork”: {
“id”: “/subscriptions/customer-sub/resourceGroups/customer-rg/providers/Microsoft.Network/virtualNetworks/customer-vnet”
}
}
}
]
}
Pattern 2: Azure Virtual WAN with Private Link
json
{
“resources”: [
{
“type”: “Microsoft.Network/virtualWans”,
“apiVersion”: “2023-05-01”,
“name”: “cross-tenant-vwan”,
“location”: “eastus”,
“properties”: {
“allowBranchToBranchTraffic”: true,
“allowVnetToVnetTraffic”: true,
“type”: “Standard”
}
},
{
“type”: “Microsoft.Network/virtualHubs”,
“apiVersion”: “2023-05-01”,
“name”: “central-hub”,
“location”: “eastus”,
“properties”: {
“virtualWan”: {
“id”: “[resourceId(‘Microsoft.Network/virtualWans’, ‘cross-tenant-vwan’)]”
},
“addressPrefix”: “10.100.0.0/16”
}
}
]
}
- Monitoring and Troubleshooting
- Azure Monitor Workbooks for Private Link
kql
// Private Link connection monitoring
AzureDiagnostics
| where ResourceType == “PRIVATEENDPOINTS”
| where Category == “PrivateEndpointConnection”
| project TimeGenerated, Resource, OperationName, ResultType, CallerIpAddress
| summarize ConnectionCount = count() by bin(TimeGenerated, 1h), OperationName
- Network Watcher for Connectivity Testing
powershell
function Test-CrossTenantPrivateConnectivity {
param(
[string]$SourceVmId,
[string]$PrivateEndpointFqdn
)
$connectionTest = Test-AzNetworkWatcherConnectivity `
-NetworkWatcherName “NetworkWatcher_eastus” `
-ResourceId $SourceVmId `
-DestinationAddress $PrivateEndpointFqdn `
-DestinationPort 443
if ($connectionTest.ConnectivityStatus -eq “Reachable”) {
Write-Output “Private Link connectivity successful to $PrivateEndpointFqdn”
} else {
Write-Error “Private Link connectivity failed to $PrivateEndpointFqdn”
# Log detailed troubleshooting info
$connectionTest | ConvertTo-Json -Depth 5 | Out-File “connectivity-debug.json”
}
}
- Security and Compliance
- Private Link with Azure Policy Enforcement
json
{
“mode”: “Indexed”,
“policyRule”: {
“if”: {
“allOf”: [
{
“field”: “type”,
“equals”: “Microsoft.Storage/storageAccounts”
},
{
“field”: “Microsoft.Storage/storageAccounts/publicNetworkAccess”,
“notEquals”: “Disabled”
}
]
},
“then”: {
“effect”: “deny”,
“details”: {
“message”: “Storage accounts must have public network access disabled and use Private Link for cross-tenant access”
}
}
}
}
- Azure Blueprints for Private Link Architecture
json
{
“properties”: {
“description”: “Cross-Tenant Private Link Blueprint”,
“targetScope”: “subscription”,
“parameters”: {
“hubVNetId”: { “type”: “string” },
“privateEndpointSubnetId”: { “type”: “string” }
},
“resourceGroups”: {
“private-link-rg”: {
“description”: “Resource group for cross-tenant private endpoints”
}
},
“artifacts”: [
{
“kind”: “policyAssignment”,
“properties”: {
“displayName”: “Enforce Private Link for PaaS”,
“policyDefinitionId”: “/providers/Microsoft.Authorization/policyDefinitions/…”
}
}
]
}
}
- Cost Optimization and Management
- Private Link Cost Analysis
kql
// Monitor Private Link costs across tenants
UsageDetails
| where MeterCategory =~ “Networking” and MeterSubCategory =~ “Private Endpoints”
| extend Tenant = tags[‘Tenant’]
| summarize
TotalCost = sum(Quantity * UnitPrice),
PrivateEndpointCount = dcount(ResourceId)
by Tenant, bin(UsageDateTime, 1d)
| order by TotalCost desc
- Automated Private Endpoint Cleanup
powershell
function Remove-OrphanedPrivateEndpoints {
$privateEndpoints = Get-AzPrivateEndpoint
foreach ($pe in $privateEndpoints) {
$connection = $pe.PrivateLinkServiceConnections[0]
if ($connection.PrivateLinkServiceId) {
$resource = Get-AzResource -ResourceId $connection.PrivateLinkServiceId -ErrorAction SilentlyContinue
if (!$resource) {
Write-Warning “Removing orphaned private endpoint: $($pe.Name)”
Remove-AzPrivateEndpoint -ResourceId $pe.Id -Force
}
}
}
}
Implementation Checklist
- Design hub VNet architecture for private endpoints
- Identify required PaaS services for private connectivity
- Configure private DNS zones for name resolution
- Implement network security controls (NSGs, Firewall)
- Deploy private endpoints for each service
- Test connectivity from all customer environments
- Configure monitoring and alerting
- Implement cost tracking for private endpoints
- Document access patterns and troubleshooting procedures
- Establish security policies for private link enforcement
Summary
Using Azure Private Link for cross-tenant management provides:
✅ Enhanced security through private connectivity
✅ Network isolation from public internet
✅ Compliance with data protection requirements
✅ Reliable service connectivity without public endpoints
✅ Centralized management of private connections
✅ Improved performance through optimized routing
The key success factors are proper DNS configuration, network security design, and automated deployment processes that scale across multiple customer tenants while maintaining security and compliance standards.
what are options for cross tenant management using Azure VNet peering?
Excellent question! Azure VNet peering provides direct network connectivity between virtual networks across tenants, enabling secure, low-latency communication for management operations. Here are comprehensive options and implementation patterns:
- Core Architecture Patterns
Pattern A: Hub-and-Spoke with Cross-Tenant Peering
Central hub VNet in managing tenant peered to customer spoke VNets
Pattern B: Full Mesh Peering
Direct peering between all relevant VNets across tenants (complex but high-performance)
Pattern C: Regional Hub Pattern
Multiple hub VNets in different regions for global customers
- VNet Peering Implementation with Azure Lighthouse
- ARM Template for Cross-Tenant VNet Peering
json
{
“$schema”: “https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“hubVNetId”: { “type”: “string” },
“customerVNetId”: { “type”: “string” },
“customerSubscriptionId”: { “type”: “string” },
“peeringName”: { “type”: “string” }
},
“resources”: [
{
“type”: “Microsoft.Network/virtualNetworks/virtualNetworkPeerings”,
“apiVersion”: “2023-05-01”,
“name”: “[concat(parameters(‘peeringName’), ‘-to-customer’)]”,
“properties”: {
“allowVirtualNetworkAccess”: true,
“allowForwardedTraffic”: true,
“allowGatewayTransit”: false,
“useRemoteGateways”: false,
“remoteVirtualNetwork”: {
“id”: “[parameters(‘customerVNetId’)]”
}
}
},
{
“type”: “Microsoft.Resources/deployments”,
“apiVersion”: “2020-10-01”,
“name”: “[concat(‘customer-peering-‘, parameters(‘peeringName’))]”,
“subscriptionId”: “[parameters(‘customerSubscriptionId’)]”,
“properties”: {
“mode”: “Incremental”,
“template”: {
“$schema”: “https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“resources”: [
{
“type”: “Microsoft.Network/virtualNetworks/virtualNetworkPeerings”,
“apiVersion”: “2023-05-01”,
“name”: “[concat(parameters(‘peeringName’), ‘-to-hub’)]”,
“properties”: {
“allowVirtualNetworkAccess”: true,
“allowForwardedTraffic”: true,
“allowGatewayTransit”: false,
“useRemoteGateways”: false,
“remoteVirtualNetwork”: {
“id”: “[parameters(‘hubVNetId’)]”
}
}
}
]
}
}
}
]
}
- PowerShell Automation for VNet Peering
powershell
function New-CrossTenantVNetPeering {
param(
[string]$HubSubscriptionId,
[string]$CustomerSubscriptionId,
[string]$HubVNetName,
[string]$CustomerVNetName,
[string]$HubResourceGroup = “hub-networking”,
[string]$CustomerResourceGroup = “customer-networking”
)
# Set context to hub subscription
Set-AzContext -SubscriptionId $HubSubscriptionId
# Get hub VNet
$hubVNet = Get-AzVirtualNetwork -Name $HubVNetName -ResourceGroupName $HubResourceGroup
# Set context to customer subscription
Set-AzContext -SubscriptionId $CustomerSubscriptionId
# Get customer VNet
$customerVNet = Get-AzVirtualNetwork -Name $CustomerVNetName -ResourceGroupName $CustomerResourceGroup
# Create peering from hub to customer
Set-AzContext -SubscriptionId $HubSubscriptionId
Add-AzVirtualNetworkPeering -Name “peer-to-$CustomerVNetName” `
-VirtualNetwork $hubVNet `
-RemoteVirtualNetworkId $customerVNet.Id `
-AllowForwardedTraffic `
-AllowVirtualNetworkAccess
# Create peering from customer to hub
Set-AzContext -SubscriptionId $CustomerSubscriptionId
Add-AzVirtualNetworkPeering -Name “peer-to-$HubVNetName” `
-VirtualNetwork $customerVNet `
-RemoteVirtualNetworkId $hubVNet.Id `
-AllowForwardedTraffic `
-AllowVirtualNetworkAccess
Write-Output “VNet peering established between $HubVNetName and $CustomerVNetName”
}
- Network Architecture and IP Planning
- IP Address Space Design
json
{
“networkDesign”: {
“hubVNet”: {
“addressSpace”: [“10.1.0.0/16”],
“subnets”: {
“management”: “10.1.1.0/24”,
“jumpboxes”: “10.1.2.0/24”,
“gateway”: “10.1.3.0/27”,
“azureBastion”: “10.1.4.0/27”
}
},
“customerVNets”: {
“contoso”: {
“addressSpace”: [“10.10.0.0/16”],
“region”: “eastus”
},
“fabrikam”: {
“addressSpace”: [“10.20.0.0/16”],
“region”: “westeurope”
},
“adventureworks”: {
“addressSpace”: [“10.30.0.0/16”],
“region”: “southeastasia”
}
}
}
}
- Subnet Planning for Management Services
json
{
“subnetDesign”: {
“managementSubnet”: {
“name”: “snet-management”,
“addressPrefix”: “10.1.1.0/24”,
“services”: [
“Azure Bastion”,
“Jumpbox VMs”,
“Azure Automation Hybrid Workers”
],
“nsg”: “nsg-management-restricted”
},
“monitoringSubnet”: {
“name”: “snet-monitoring”,
“addressPrefix”: “10.1.5.0/24”,
“services”: [
“Monitoring VMs”,
“Log Collectors”,
“Network Watcher”
],
“nsg”: “nsg-monitoring”
}
}
}
- Specific Cross-Tenant Management Scenarios
Scenario 1: Secure Jumpbox Access
Deploy bastion hosts in hub VNet for customer VM management
json
{
“resources”: [
{
“type”: “Microsoft.Network/bastionHosts”,
“apiVersion”: “2023-05-01”,
“name”: “cross-tenant-bastion”,
“location”: “eastus”,
“properties”: {
“ipConfigurations”: [
{
“name”: “bastion-ipconfig”,
“properties”: {
“subnet”: {
“id”: “[resourceId(‘Microsoft.Network/virtualNetworks/subnets’, ‘hub-vnet’, ‘AzureBastionSubnet’)]”
},
“publicIPAddress”: {
“id”: “[resourceId(‘Microsoft.Network/publicIPAddresses’, ‘bastion-pip’)]”
}
}
}
]
}
},
{
“type”: “Microsoft.Compute/virtualMachines”,
“apiVersion”: “2023-03-01”,
“name”: “jumpbox-management”,
“location”: “eastus”,
“properties”: {
“hardwareProfile”: { “vmSize”: “Standard_B2s” },
“networkProfile”: {
“networkInterfaces”: [
{
“id”: “[resourceId(‘Microsoft.Network/networkInterfaces’, ‘jumpbox-nic’)]”
}
]
},
“storageProfile”: { /* … */ },
“osProfile”: { /* … */ }
},
“dependsOn”: [
“[resourceId(‘Microsoft.Network/networkInterfaces’, ‘jumpbox-nic’)]”
]
}
]
}
Scenario 2: Hybrid Worker Management
Azure Automation hybrid workers in hub accessing customer resources
json
{
“resources”: [
{
“type”: “Microsoft.Automation/automationAccounts”,
“apiVersion”: “2022-08-08”,
“name”: “cross-tenant-automation”,
“location”: “eastus”,
“properties”: {
“sku”: { “name”: “Basic” }
}
},
{
“type”: “Microsoft.Automation/hybridRunbookWorkerGroups”,
“apiVersion”: “2022-08-08”,
“name”: “customer-management-workers”,
“properties”: {
“credential”: { /* Hybrid worker credentials */ }
}
}
]
}
Scenario 3: Cross-Tenant Backup and Recovery
Central backup infrastructure accessing customer VMs
json
{
“resources”: [
{
“type”: “Microsoft.RecoveryServices/vaults”,
“apiVersion”: “2023-02-01”,
“name”: “central-backup-vault”,
“location”: “eastus”,
“sku”: { “name”: “Standard” },
“properties”: { /* … */ }
},
{
“type”: “Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems”,
“apiVersion”: “2023-02-01”,
“name”: “cross-tenant-backup-policy”,
“properties”: {
“protectedItemType”: “Microsoft.Compute/virtualMachines”,
“policyId”: “[resourceId(‘Microsoft.RecoveryServices/vaults/backupPolicies’, ‘central-backup-vault’, ‘default-policy’)]”,
“sourceResourceId”: “/subscriptions/customer-sub/resourceGroups/customer-rg/providers/Microsoft.Compute/virtualMachines/customer-vm”
}
}
]
}
- Network Security Configuration
- Network Security Groups for Cross-Tenant Traffic
json
{
“resources”: [
{
“type”: “Microsoft.Network/networkSecurityGroups”,
“apiVersion”: “2023-05-01”,
“name”: “nsg-cross-tenant-management”,
“location”: “eastus”,
“properties”: {
“securityRules”: [
{
“name”: “Allow-RDP-From-Jumpboxes”,
“properties”: {
“protocol”: “TCP”,
“sourcePortRange”: “*”,
“destinationPortRange”: “3389”,
“sourceAddressPrefix”: “10.1.2.0/24”, # Jumpbox subnet
“destinationAddressPrefix”: “VirtualNetwork”,
“access”: “Allow”,
“priority”: 100,
“direction”: “Inbound”
}
},
{
“name”: “Allow-WinRM-From-Management”,
“properties”: {
“protocol”: “TCP”,
“sourcePortRange”: “*”,
“destinationPortRange”: “5986”,
“sourceAddressPrefix”: “10.1.1.0/24”, # Management subnet
“destinationAddressPrefix”: “VirtualNetwork”,
“access”: “Allow”,
“priority”: 110,
“direction”: “Inbound”
}
},
{
“name”: “Deny-All-Other-Inbound”,
“properties”: {
“protocol”: “*”,
“sourcePortRange”: “*”,
“destinationPortRange”: “*”,
“sourceAddressPrefix”: “*”,
“destinationAddressPrefix”: “*”,
“access”: “Deny”,
“priority”: 4096,
“direction”: “Inbound”
}
}
]
}
}
]
}
- Azure Firewall for Cross-Tenant Traffic Control
json
{
“resources”: [
{
“type”: “Microsoft.Network/azureFirewalls”,
“apiVersion”: “2023-05-01”,
“name”: “fw-cross-tenant”,
“location”: “eastus”,
“properties”: {
“sku”: { “name”: “AZFW_Hub”, “tier”: “Standard” },
“threatIntelMode”: “Alert”,
“applicationRuleCollections”: [
{
“name”: “Allow-CrossTenant-Management”,
“properties”: {
“priority”: 100,
“action”: { “type”: “Allow” },
“rules”: [
{
“name”: “Allow-Azure-Management”,
“protocols”: [{ “protocolType”: “Https”, “port”: 443 }],
“targetFqdns”: [
“management.azure.com”,
“*.blob.core.windows.net”,
“*.azure-automation.net”
],
“sourceAddresses”: [“10.1.0.0/16”]
}
]
}
}
],
“networkRuleCollections”: [
{
“name”: “Allow-CrossTenant-RDP”,
“properties”: {
“priority”: 100,
“action”: { “type”: “Allow” },
“rules”: [
{
“name”: “Allow-RDP-To-Customers”,
“protocols”: [“TCP”],
“sourceAddresses”: [“10.1.2.0/24”], # Jumpboxes
“destinationAddresses”: [“10.0.0.0/8”], # All customer ranges
“destinationPorts”: [“3389”]
}
]
}
}
]
}
}
]
}
- DNS Configuration for Cross-Tenant
- Custom DNS Servers for Name Resolution
json
{
“resources”: [
{
“type”: “Microsoft.Network/virtualNetworks”,
“apiVersion”: “2023-05-01”,
“name”: “hub-vnet”,
“location”: “eastus”,
“properties”: {
“addressSpace”: { “addressPrefixes”: [“10.1.0.0/16”] },
“dhcpOptions”: {
“dnsServers”: [“10.1.1.4”, “10.1.1.5”] # Custom DNS servers
},
“subnets”: [ /* … */ ]
}
},
{
“type”: “Microsoft.Network/privateDnsZones”,
“apiVersion”: “2020-06-01”,
“name”: “internal.management.com”,
“location”: “global”,
“resources”: [
{
“type”: “virtualNetworkLinks”,
“apiVersion”: “2020-06-01”,
“name”: “link-to-hub”,
“properties”: {
“virtualNetwork”: {
“id”: “[resourceId(‘Microsoft.Network/virtualNetworks’, ‘hub-vnet’)]”
},
“registrationEnabled”: true
}
}
]
}
]
}
- Conditional DNS Forwarding
powershell
function Configure-CrossTenantDNS {
param(
[string]$HubVNetName,
[string]$CustomerVNetName,
[string]$CustomerDomain
)
# Create DNS server in hub
$dnsServer = New-AzNetworkInterface -Name “dns-server” -ResourceGroupName “hub-networking” `
-Location “eastus” -SubnetId “/subscriptions/hub-sub/resourceGroups/hub-networking/providers/Microsoft.Network/virtualNetworks/hub-vnet/subnets/snet-management”
# Configure conditional forwarders for customer domains
Add-DnsServerConditionalForwarderZone -Name $CustomerDomain `
-MasterServers (Get-AzNetworkInterface -Name $CustomerVNetName).IpConfigurations.PrivateIpAddress
}
- Monitoring and Troubleshooting
- Network Watcher for Connectivity Testing
powershell
function Test-CrossTenantConnectivity {
param(
[string]$SourceVmId,
[string]$DestinationIp,
[int]$Port = 3389
)
$connectionTest = Test-AzNetworkWatcherConnectivity `
-NetworkWatcherName “NetworkWatcher_eastus” `
-ResourceId $SourceVmId `
-DestinationAddress $DestinationIp `
-DestinationPort $Port
return @{
Status = $connectionTest.ConnectivityStatus
Latency = $connectionTest.AvgLatencyInMs
Hops = $connectionTest.Hops
}
}
# Test connectivity to customer VMs
$customerVMs = @(
@{ Name = “contoso-web-01”; IP = “10.10.1.10” },
@{ Name = “contoso-sql-01”; IP = “10.10.2.10” }
)
foreach ($vm in $customerVMs) {
$result = Test-CrossTenantConnectivity -SourceVmId $jumpboxId -DestinationIp $vm.IP
Write-Output “Connectivity to $($vm.Name): $($result.Status), Latency: $($result.Latency)ms”
}
- Azure Monitor for Network Performance
kql
// Monitor cross-tenant network performance
AzureMetrics
| where ResourceProvider == “MICROSOFT.NETWORK”
| where MetricName == “VMAvailability”
| extend VNet = tostring(parse_json(tostring(parse_json(ResourceId).VNet)))
| where VNet contains “customer”
| summarize AvgAvailability = avg(Average) by VNet, bin(TimeGenerated, 1h)
- Automation and Governance
- Azure Policy for Network Compliance
json
{
“mode”: “Indexed”,
“policyRule”: {
“if”: {
“allOf”: [
{
“field”: “type”,
“equals”: “Microsoft.Network/virtualNetworks”
},
{
“field”: “Microsoft.Network/virtualNetworks/addressSpace.addressPrefixes”,
“notContains”: “10.”
}
]
},
“then”: {
“effect”: “deny”,
“details”: {
“message”: “Virtual networks must use RFC 1918 address space for cross-tenant peering compatibility”
}
}
}
}
- Azure Blueprints for Network Architecture
json
{
“properties”: {
“description”: “Cross-Tenant Network Architecture Blueprint”,
“targetScope”: “subscription”,
“parameters”: {
“hubAddressSpace”: { “type”: “string” },
“customerAddressSpace”: { “type”: “string” }
},
“resourceGroups”: {
“network-rg”: {
“description”: “Resource group for cross-tenant networking”
}
},
“artifacts”: [
{
“kind”: “template”,
“properties”: {
“template”: { /* Hub VNet template */ },
“parameters”: {
“addressSpace”: { “value”: “[parameters(‘hubAddressSpace’)]” }
}
}
}
]
}
}
- Cost Optimization and Management
- VNet Peering Cost Monitoring
kql
// Monitor cross-tenant data transfer costs
UsageDetails
| where MeterCategory =~ “Networking” and MeterSubCategory =~ “VNet Peering”
| extend Tenant = tags[‘Tenant’]
| summarize
TotalCost = sum(Quantity * UnitPrice),
DataTransferGB = sum(Quantity)
by Tenant, bin(UsageDateTime, 1d)
| order by TotalCost desc
- Automated Peering Cleanup
powershell
function Remove-OrphanedVNetPeerings {
$vnets = Get-AzVirtualNetwork
foreach ($vnet in $vnets) {
$peerings = Get-AzVirtualNetworkPeering -VirtualNetworkName $vnet.Name -ResourceGroupName $vnet.ResourceGroupName
foreach ($peering in $peerings) {
$remoteVNet = Get-AzResource -ResourceId $peering.RemoteVirtualNetwork.Id -ErrorAction SilentlyContinue
if (!$remoteVNet) {
Write-Warning “Removing orphaned peering: $($peering.Name) from $($vnet.Name)”
Remove-AzVirtualNetworkPeering -Name $peering.Name -VirtualNetworkName $vnet.Name -ResourceGroupName $vnet.ResourceGroupName -Force
}
}
}
}
Implementation Checklist
- Design IP address schema to avoid overlaps
- Plan hub VNet architecture with management subnets
- Configure network security groups for cross-tenant traffic
- Set up DNS resolution across peered networks
- Deploy Azure Firewall for centralized control
- Implement monitoring and connectivity testing
- Establish naming conventions for network resources
- Configure backup and disaster recovery paths
- Document network topology and access patterns
- Test failover and recovery procedures
Summary
Using Azure VNet peering for cross-tenant management provides:
✅ Low-latency, high-bandwidth connectivity between tenants
✅ Enhanced security through private network routing
✅ Centralized management of network resources
✅ Cost-effective data transfer compared to VPN/Gateway
✅ Scalable architecture for multiple customer environments
✅ Integration with other Azure services (Firewall, Bastion, etc.)
The key success factors are proper IP planning, robust security configuration, automated deployment processes, and comprehensive monitoring to ensure reliable cross-tenant connectivity for management operations.
This response is AI-generated, for reference only.
what are options for cross tenant management using Azure VPN Gateway
Excellent question! Azure VPN Gateway provides secure, encrypted cross-tenant connectivity over the public internet, offering flexible options for management scenarios where direct network peering isn’t feasible. Here are comprehensive options and implementation patterns:
- Core Architecture Patterns
Pattern A: Site-to-Site VPN with Cross-Tenant Connectivity
VPN Gateway in managing tenant connecting to customer on-premises or Azure networks
Pattern B: Point-to-Site for Remote Management
Individual administrator connections to customer networks
Pattern C: VNet-to-VNet VPN as Peering Alternative
When VNet peering isn’t possible due to overlapping IP spaces
- VPN Gateway Implementation with Azure Lighthouse
- ARM Template for Cross-Tenant VPN Gateway
json
{
“$schema”: “https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“gatewayName”: { “type”: “string” },
“gatewayType”: { “type”: “string” },
“customerGatewayPublicIp”: { “type”: “string” },
“customerAddressSpace”: { “type”: “string” },
“sharedKey”: { “type”: “securestring” }
},
“resources”: [
{
“type”: “Microsoft.Network/virtualNetworkGateways”,
“apiVersion”: “2023-05-01”,
“name”: “[parameters(‘gatewayName’)]”,
“location”: “[resourceGroup().location]”,
“properties”: {
“ipConfigurations”: [
{
“name”: “vnetGatewayConfig”,
“properties”: {
“privateIPAllocationMethod”: “Dynamic”,
“subnet”: {
“id”: “[resourceId(‘Microsoft.Network/virtualNetworks/subnets’, ‘hub-vnet’, ‘GatewaySubnet’)]”
},
“publicIPAddress”: {
“id”: “[resourceId(‘Microsoft.Network/publicIPAddresses’, concat(parameters(‘gatewayName’), ‘-pip’))]”
}
}
}
],
“gatewayType”: “[parameters(‘gatewayType’)]”,
“vpnType”: “RouteBased”,
“enableBgp”: false,
“activeActive”: false,
“sku”: {
“name”: “VpnGw2”,
“tier”: “VpnGw2”
}
}
},
{
“type”: “Microsoft.Network/localNetworkGateways”,
“apiVersion”: “2023-05-01”,
“name”: “[concat(parameters(‘gatewayName’), ‘-local’)]”,
“location”: “[resourceGroup().location]”,
“properties”: {
“gatewayIpAddress”: “[parameters(‘customerGatewayPublicIp’)]”,
“localNetworkAddressSpace”: {
“addressPrefixes”: [“[parameters(‘customerAddressSpace’)]”]
}
}
},
{
“type”: “Microsoft.Network/connections”,
“apiVersion”: “2023-05-01”,
“name”: “[concat(parameters(‘gatewayName’), ‘-connection’)]”,
“location”: “[resourceGroup().location]”,
“properties”: {
“virtualNetworkGateway1”: {
“id”: “[resourceId(‘Microsoft.Network/virtualNetworkGateways’, parameters(‘gatewayName’))]”
},
“localNetworkGateway2”: {
“id”: “[resourceId(‘Microsoft.Network/localNetworkGateways’, concat(parameters(‘gatewayName’), ‘-local’))]”
},
“connectionType”: “IPsec”,
“connectionProtocol”: “IKEv2”,
“routingWeight”: 0,
“sharedKey”: “[parameters(‘sharedKey’)]”,
“enableBgp”: false
},
“dependsOn”: [
“[resourceId(‘Microsoft.Network/virtualNetworkGateways’, parameters(‘gatewayName’))]”,
“[resourceId(‘Microsoft.Network/localNetworkGateways’, concat(parameters(‘gatewayName’), ‘-local’))]”
]
}
]
}
- PowerShell Automation for VPN Gateway Deployment
powershell
function New-CrossTenantVPNConnection {
param(
[string]$HubSubscriptionId,
[string]$CustomerName,
[string]$CustomerGatewayPublicIp,
[string]$CustomerAddressSpace,
[string]$SharedKey,
[string]$HubVNetName = “hub-vnet”,
[string]$HubResourceGroup = “hub-networking”
)
# Set context to hub subscription
Set-AzContext -SubscriptionId $HubSubscriptionId
# Create public IP for VPN gateway
$vpnPublicIp = New-AzPublicIpAddress -Name “vpn-gw-pip-$CustomerName” `
-ResourceGroupName $HubResourceGroup -Location “eastus” `
-AllocationMethod Dynamic -Sku Basic
# Get gateway subnet
$vnet = Get-AzVirtualNetwork -Name $HubVNetName -ResourceGroupName $HubResourceGroup
$gatewaySubnet = $vnet.Subnets | Where-Object { $_.Name -eq “GatewaySubnet” }
# Create VPN gateway
$vpnGateway = New-AzVirtualNetworkGateway -Name “vpn-gw-$CustomerName” `
-ResourceGroupName $HubResourceGroup -Location “eastus” `
-IpConfigurations @(
@{
Name = “vnetGatewayConfig”
PrivateIpAddress = $null
PublicIpAddress = $vpnPublicIp
Subnet = $gatewaySubnet
}
) -GatewayType “Vpn” -VpnType “RouteBased” `
-Sku @{ Name = “VpnGw1”; Tier = “VpnGw1” }
# Create local network gateway
$localGateway = New-AzLocalNetworkGateway -Name “local-gw-$CustomerName” `
-ResourceGroupName $HubResourceGroup -Location “eastus” `
-GatewayIpAddress $CustomerGatewayPublicIp `
-AddressPrefix $CustomerAddressSpace
# Create connection
$vpnConnection = New-AzVirtualNetworkGatewayConnection -Name “conn-$CustomerName” `
-ResourceGroupName $HubResourceGroup -Location “eastus” `
-VirtualNetworkGateway1 $vpnGateway -LocalNetworkGateway2 $localGateway `
-ConnectionType IPsec -SharedKey $SharedKey
Write-Output “VPN connection established to $CustomerName”
return @{
GatewayId = $vpnGateway.Id
ConnectionId = $vpnConnection.Id
PublicIp = $vpnPublicIp.IpAddress
}
}
- Network Architecture and IP Planning
- VPN Gateway Subnet and IP Design
json
{
“vpnGatewayDesign”: {
“hubVNet”: {
“addressSpace”: [“10.1.0.0/16”],
“subnets”: {
“GatewaySubnet”: “10.1.0.0/27”,
“management”: “10.1.1.0/24”,
“jumpboxes”: “10.1.2.0/24”
}
},
“customerConfigurations”: {
“contoso”: {
“gatewayPublicIp”: “203.0.113.10”,
“addressSpace”: [“192.168.1.0/24”, “10.100.0.0/16”],
“sharedKey”: “Cont0s0$3cur3K3y2024!”,
“bgpEnabled”: false
},
“fabrikam”: {
“gatewayPublicIp”: “198.51.100.20”,
“addressSpace”: [“172.16.0.0/16”],
“sharedKey”: “F@br1k@m$3cur3K3y!”,
“bgpEnabled”: true
}
}
}
}
- Route Table Configuration for VPN Traffic
json
{
“resources”: [
{
“type”: “Microsoft.Network/routeTables”,
“apiVersion”: “2023-05-01”,
“name”: “rt-vpn-management”,
“location”: “eastus”,
“properties”: {
“routes”: [
{
“name”: “to-contoso”,
“properties”: {
“addressPrefix”: “192.168.1.0/24”,
“nextHopType”: “VirtualNetworkGateway”
}
},
{
“name”: “to-fabrikam”,
“properties”: {
“addressPrefix”: “172.16.0.0/16”,
“nextHopType”: “VirtualNetworkGateway”
}
},
{
“name”: “default-to-internet”,
“properties”: {
“addressPrefix”: “0.0.0.0/0”,
“nextHopType”: “Internet”
}
}
]
}
},
{
“type”: “Microsoft.Network/routeTables/subnets”,
“apiVersion”: “2023-05-01”,
“name”: “[concat(‘rt-vpn-management/’, ‘snet-management’)]”,
“dependsOn”: [
“[resourceId(‘Microsoft.Network/routeTables’, ‘rt-vpn-management’)]”
],
“properties”: {
“addressPrefix”: “10.1.1.0/24”
}
}
]
}
- Specific Cross-Tenant Management Scenarios
Scenario 1: Site-to-Site for On-Premises Management
Connect to customer on-premises networks for hybrid management
json
{
“resources”: [
{
“type”: “Microsoft.Network/virtualNetworkGateways”,
“apiVersion”: “2023-05-01”,
“name”: “vpn-gw-onprem-management”,
“properties”: {
“ipConfigurations”: [
{
“properties”: {
“subnet”: {
“id”: “[resourceId(‘Microsoft.Network/virtualNetworks/subnets’, ‘hub-vnet’, ‘GatewaySubnet’)]”
},
“publicIPAddress”: {
“id”: “[resourceId(‘Microsoft.Network/publicIPAddresses’, ‘vpn-gw-pip’)]”
}
}
}
],
“gatewayType”: “Vpn”,
“vpnType”: “RouteBased”,
“sku”: { “name”: “VpnGw2”, “tier”: “VpnGw2” },
“vpnClientConfiguration”: {
“vpnClientProtocols”: [“OpenVPN”],
“vpnClientAddressPool”: {
“addressPrefixes”: [“172.16.201.0/24”]
}
}
}
}
]
}
Scenario 2: Point-to-Site for Administrator Access
Secure remote access for management staff
powershell
# Generate and deploy P2S VPN certificates
function New-P2SVPNConfiguration {
param([string]$CustomerName)
# Generate root certificate
$rootCert = New-SelfSignedCertificate -Type Custom -KeySpec Signature `
-Subject “CN=CrossTenantVPN-Root” -KeyExportPolicy Exportable `
-HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation “Cert:\CurrentUser\My” `
-KeyUsageProperty Sign -KeyUsage CertSign
# Generate client certificate
$clientCert = New-SelfSignedCertificate -Type Custom -KeySpec Signature `
-Subject “CN=CrossTenantVPN-Client-$CustomerName” -KeyExportPolicy Exportable `
-HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation “Cert:\CurrentUser\My” `
-Signer $rootCert -TextExtension @(“2.5.29.37={text}1.3.6.1.5.5.7.3.2”)
# Export public key for VPN gateway
$rootCertBase64 = [Convert]::ToBase64String($rootCert.RawData, ‘InsertLineBreaks’)
# Configure VPN gateway with root certificate
$vpnClientConfig = New-AzVpnClientConfiguration -ResourceGroupName “hub-networking” `
-Name “vpn-gw-$CustomerName” -AuthenticationMethod “EAPTLS” `
-ClientRootCertificates $rootCertBase64
return @{
ClientCert = $clientCert
VPNProfile = $vpnClientConfig.VPNProfileSASUrl
}
}
Scenario 3: VNet-to-VPN as Peering Alternative
When customer VNets have overlapping IP address spaces
json
{
“resources”: [
{
“type”: “Microsoft.Network/connections”,
“apiVersion”: “2023-05-01”,
“name”: “vpn-conn-overlapping-ips”,
“properties”: {
“virtualNetworkGateway1”: {
“id”: “[resourceId(‘Microsoft.Network/virtualNetworkGateways’, ‘hub-vpn-gw’)]”
},
“virtualNetworkGateway2”: {
“id”: “/subscriptions/customer-sub/resourceGroups/customer-rg/providers/Microsoft.Network/virtualNetworkGateways/customer-vpn-gw”
},
“connectionType”: “Vnet2Vnet”,
“connectionProtocol”: “IKEv2”,
“routingWeight”: 0,
“sharedKey”: “[parameters(‘vnetSharedKey’)]”,
“enableBgp”: false,
“useLocalAzureIpAddress”: false,
“usePolicyBasedTrafficSelectors”: false,
“ipsecPolicies”: [
{
“saLifeTimeSeconds”: 28800,
“saDataSizeKilobytes”: 102400000,
“ipsecEncryption”: “AES256”,
“ipsecIntegrity”: “SHA256”,
“ikeEncryption”: “AES256”,
“ikeIntegrity”: “SHA384”,
“dhGroup”: “DHGroup24”,
“pfsGroup”: “PFS24”
}
]
}
}
]
}
- Network Security Configuration
- Network Security Groups for VPN Traffic
json
{
“resources”: [
{
“type”: “Microsoft.Network/networkSecurityGroups”,
“apiVersion”: “2023-05-01”,
“name”: “nsg-vpn-management”,
“location”: “eastus”,
“properties”: {
“securityRules”: [
{
“name”: “Allow-VPN-IKE-Inbound”,
“properties”: {
“protocol”: “UDP”,
“sourcePortRange”: “*”,
“destinationPortRange”: “500”,
“sourceAddressPrefix”: “*”,
“destinationAddressPrefix”: “*”,
“access”: “Allow”,
“priority”: 100,
“direction”: “Inbound”
}
},
{
“name”: “Allow-VPN-IPSEC-Inbound”,
“properties”: {
“protocol”: “UDP”,
“sourcePortRange”: “*”,
“destinationPortRange”: “4500”,
“sourceAddressPrefix”: “*”,
“destinationAddressPrefix”: “*”,
“access”: “Allow”,
“priority”: 110,
“direction”: “Inbound”
}
},
{
“name”: “Allow-RDP-From-Customers”,
“properties”: {
“protocol”: “TCP”,
“sourcePortRange”: “*”,
“destinationPortRange”: “3389”,
“sourceAddressPrefix”: “192.168.0.0/16”,
“destinationAddressPrefix”: “10.1.2.0/24”,
“access”: “Allow”,
“priority”: 120,
“direction”: “Inbound”
}
},
{
“name”: “Deny-All-Other-Inbound”,
“properties”: {
“protocol”: “*”,
“sourcePortRange”: “*”,
“destinationPortRange”: “*”,
“sourceAddressPrefix”: “*”,
“destinationAddressPrefix”: “*”,
“access”: “Deny”,
“priority”: 4096,
“direction”: “Inbound”
}
}
]
}
}
]
}
- Azure Firewall for VPN Traffic Inspection
json
{
“resources”: [
{
“type”: “Microsoft.Network/azureFirewalls”,
“apiVersion”: “2023-05-01”,
“name”: “fw-vpn-inspection”,
“location”: “eastus”,
“properties”: {
“sku”: { “name”: “AZFW_Hub”, “tier”: “Standard” },
“threatIntelMode”: “Alert”,
“networkRuleCollections”: [
{
“name”: “Allow-CrossTenant-Management”,
“properties”: {
“priority”: 100,
“action”: { “type”: “Allow” },
“rules”: [
{
“name”: “Allow-RDP-To-Jumpboxes”,
“protocols”: [“TCP”],
“sourceAddresses”: [“192.168.0.0/16”, “172.16.0.0/16”],
“destinationAddresses”: [“10.1.2.0/24”],
“destinationPorts”: [“3389”]
},
{
“name”: “Allow-WinRM-Management”,
“protocols”: [“TCP”],
“sourceAddresses”: [“192.168.0.0/16”, “172.16.0.0/16”],
“destinationAddresses”: [“10.1.1.0/24”],
“destinationPorts”: [“5985”, “5986”]
}
]
}
}
],
“applicationRuleCollections”: [
{
“name”: “Allow-Management-Tools”,
“properties”: {
“priority”: 100,
“action”: { “type”: “Allow” },
“rules”: [
{
“name”: “Allow-Azure-Management”,
“protocols”: [{ “protocolType”: “Https”, “port”: 443 }],
“sourceAddresses”: [“10.1.0.0/16”],
“targetFqdns”: [
“management.azure.com”,
“*.blob.core.windows.net”,
“*.azure-automation.net”
]
}
]
}
}
]
}
}
]
}
- Monitoring and Troubleshooting
- VPN Gateway Diagnostics and Monitoring
json
{
“resources”: [
{
“type”: “Microsoft.Network/virtualNetworkGateways”,
“apiVersion”: “2023-05-01”,
“name”: “vpn-gw-monitored”,
“properties”: {
“ipConfigurations”: [ /* … */ ],
“gatewayType”: “Vpn”,
“vpnType”: “RouteBased”,
“sku”: { “name”: “VpnGw2”, “tier”: “VpnGw2” },
“diagnosticLogs”: {
“enabled”: true,
“storageAccountId”: “[resourceId(‘Microsoft.Storage/storageAccounts’, ‘vpnlogs’)]”,
“logs”: [
{
“category”: “GatewayDiagnosticLog”,
“enabled”: true,
“retentionPolicy”: {
“days”: 90,
“enabled”: true
}
},
{
“category”: “TunnelDiagnosticLog”,
“enabled”: true,
“retentionPolicy”: {
“days”: 90,
“enabled”: true
}
},
{
“category”: “RouteDiagnosticLog”,
“enabled”: true,
“retentionPolicy”: {
“days”: 90,
“enabled”: true
}
}
]
}
}
}
]
}
- Azure Monitor for VPN Performance
kql
// Monitor VPN tunnel status and performance
AzureMetrics
| where ResourceProvider == “MICROSOFT.NETWORK”
| where ResourceType == “VIRTUALNETWORKGATEWAYS”
| where MetricName in (“TunnelIngressBytes”, “TunnelEgressBytes”, “TunnelIngressPacketDropCount”, “TunnelEgressPacketDropCount”)
| extend GatewayName = tostring(split(ResourceId, ‘/’)[8])
| summarize
AvgIngressBytes = avg(Average),
AvgEgressBytes = avg(Average),
MaxIngressBytes = max(Maximum),
MaxEgressBytes = max(Maximum)
by GatewayName, MetricName, bin(TimeGenerated, 5m)
- Connection Testing and Alerting
powershell
function Test-VPNConnectionHealth {
param([string]$GatewayName, [string]$ResourceGroup)
$connection = Get-AzVirtualNetworkGatewayConnection -Name $GatewayName -ResourceGroupName $ResourceGroup
$tunnelStatus = Get-AzVirtualNetworkGatewayConnectionSharedKey -Name $GatewayName -ResourceGroupName $ResourceGroup
$healthStatus = @{
ConnectionName = $connection.Name
ConnectionStatus = $connection.ConnectionStatus
EgressBytes = $connection.EgressBytesTransferred
IngressBytes = $connection.IngressBytesTransferred
LastConnectionEstablished = $connection.LastConnectionEstablished
}
# Alert if connection is down for more than 5 minutes
if ($connection.ConnectionStatus -ne “Connected” -and
(Get-Date) – $connection.LastConnectionEstablished -gt (New-TimeSpan -Minutes 5)) {
Send-Alert -Message “VPN connection $($connection.Name) is down” -Severity “High”
}
return $healthStatus
}
- High Availability and Disaster Recovery
- Active-Active VPN Gateway Configuration
json
{
“resources”: [
{
“type”: “Microsoft.Network/virtualNetworkGateways”,
“apiVersion”: “2023-05-01”,
“name”: “vpn-gw-ha”,
“properties”: {
“ipConfigurations”: [
{
“name”: “gwIpConfig1”,
“properties”: {
“privateIPAllocationMethod”: “Dynamic”,
“subnet”: {
“id”: “[resourceId(‘Microsoft.Network/virtualNetworks/subnets’, ‘hub-vnet’, ‘GatewaySubnet’)]”
},
“publicIPAddress”: {
“id”: “[resourceId(‘Microsoft.Network/publicIPAddresses’, ‘vpn-gw-pip1’)]”
}
}
},
{
“name”: “gwIpConfig2”,
“properties”: {
“privateIPAllocationMethod”: “Dynamic”,
“subnet”: {
“id”: “[resourceId(‘Microsoft.Network/virtualNetworks/subnets’, ‘hub-vnet’, ‘GatewaySubnet’)]”
},
“publicIPAddress”: {
“id”: “[resourceId(‘Microsoft.Network/publicIPAddresses’, ‘vpn-gw-pip2’)]”
}
}
}
],
“gatewayType”: “Vpn”,
“vpnType”: “RouteBased”,
“enableBgp”: true,
“activeActive”: true,
“sku”: { “name”: “VpnGw3”, “tier”: “VpnGw3” },
“bgpSettings”: {
“asn”: 65515,
“bgpPeeringAddress”: “10.1.0.254”,
“peerWeight”: 0
}
}
}
]
}
- Multi-Region VPN Gateway Deployment
powershell
function Deploy-MultiRegionVPN {
param([string[]]$Regions = @(“eastus”, “westus”, “westeurope”))
foreach ($region in $Regions) {
$deploymentParams = @{
HubSubscriptionId = $HubSubscriptionId
HubResourceGroup = “hub-networking-$region”
HubVNetName = “hub-vnet-$region”
Region = $region
}
# Deploy regional VPN gateway
New-CrossTenantVPNConnection @deploymentParams
# Configure cross-region routing
Set-AzVirtualNetworkGateway -Name “vpn-gw-$region” `
-ResourceGroupName “hub-networking-$region” `
-EnableBgpRouteTranslationForNat $true
}
Write-Output “Multi-region VPN deployment completed”
}
- Cost Optimization and Management
- VPN Gateway Cost Monitoring
kql
// Monitor VPN gateway costs across tenants
UsageDetails
| where MeterCategory =~ “Networking” and MeterSubCategory =~ “VPN Gateway”
| extend GatewayName = tostring(ResourceId)
| summarize
TotalCost = sum(Quantity * UnitPrice),
GatewayHours = sum(Quantity)
by GatewayName, bin(UsageDateTime, 1d)
| order by TotalCost desc
- Automated VPN Gateway Scaling
powershell
function Optimize-VPNGatewayCost {
param([string]$GatewayName, [string]$ResourceGroup)
$gateway = Get-AzVirtualNetworkGateway -Name $GatewayName -ResourceGroupName $ResourceGroup
$connectionStats = Get-AzVirtualNetworkGatewayConnection -Name “$GatewayName-conn” -ResourceGroupName $ResourceGroup
# Calculate average bandwidth usage
$avgBandwidth = ($connectionStats.EgressBytesTransferred + $connectionStats.IngressBytesTransferred) / 24h
# Scale down if usage is low
if ($avgBandwidth -lt 100MB -and $gateway.Sku.Tier -eq “VpnGw2”) {
Write-Output “Scaling down $GatewayName from VpnGw2 to VpnGw1”
$gateway.Sku.Tier = “VpnGw1”
$gateway | Set-AzVirtualNetworkGateway
}
# Scale up during business hours if needed
if ((Get-Date).Hour -ge 8 -and (Get-Date).Hour -le 18 -and
$avgBandwidth -gt 500MB -and $gateway.Sku.Tier -eq “VpnGw1”) {
Write-Output “Scaling up $GatewayName from VpnGw1 to VpnGw2”
$gateway.Sku.Tier = “VpnGw2”
$gateway | Set-AzVirtualNetworkGateway
}
}
Implementation Checklist
- Design IP address schema for VPN connectivity
- Plan GatewaySubnet with adequate address space
- Select appropriate VPN Gateway SKU based on bandwidth requirements
- Configure cryptographic policies and shared keys
- Set up network security groups for VPN traffic
- Implement route tables for traffic steering
- Configure monitoring and alerting for connection health
- Establish certificate authority for P2S connections
- Test failover and disaster recovery procedures
- Document connection parameters for each customer
Summary
Using Azure VPN Gateway for cross-tenant management provides:
✅ Secure encrypted tunnels over public internet
✅ Flexible connectivity options (S2S, P2S, VNet-to-VNet)
✅ Compatibility with on-premises networks
✅ Solution for overlapping IP address spaces
✅ BGP support for dynamic routing
✅ High availability with active-active configuration
The key success factors are proper cryptographic configuration, robust monitoring, cost optimization through appropriate SKU selection, and comprehensive documentation of connection parameters for each customer environment.
This response is AI-generated, for reference only.
what are options for cross tenant management using Azure Bastion?
Excellent question! Azure Bastion provides secure, seamless RDP/SSH connectivity to VMs without exposing them to the public internet, making it ideal for cross-tenant management. Here are comprehensive options and implementation patterns:
- Core Architecture Patterns
Pattern A: Centralized Bastion Host
Single Azure Bastion in managing tenant accessing customer VMs via Azure Lighthouse
Pattern B: Regional Bastion Hosts
Multiple Bastion hosts in different regions for global customers
Pattern C: Customer-Dedicated Bastion
Bastion deployed per customer for isolation (higher cost)
- Azure Bastion Implementation with Azure Lighthouse
- ARM Template for Centralized Bastion
json
{
“$schema”: “https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“bastionName”: { “type”: “string” },
“bastionSubnetAddressPrefix”: { “type”: “string” }
},
“resources”: [
{
“type”: “Microsoft.Network/virtualNetworks”,
“apiVersion”: “2023-05-01”,
“name”: “hub-vnet”,
“location”: “[resourceGroup().location]”,
“properties”: {
“addressSpace”: {
“addressPrefixes”: [“10.1.0.0/16”]
},
“subnets”: [
{
“name”: “AzureBastionSubnet”,
“properties”: {
“addressPrefix”: “[parameters(‘bastionSubnetAddressPrefix’)]”
}
},
{
“name”: “management”,
“properties”: {
“addressPrefix”: “10.1.1.0/24”
}
}
]
}
},
{
“type”: “Microsoft.Network/publicIPAddresses”,
“apiVersion”: “2023-05-01”,
“name”: “[concat(parameters(‘bastionName’), ‘-pip’)]”,
“location”: “[resourceGroup().location]”,
“sku”: { “name”: “Standard” },
“properties”: {
“publicIPAllocationMethod”: “Static”
}
},
{
“type”: “Microsoft.Network/bastionHosts”,
“apiVersion”: “2023-05-01”,
“name”: “[parameters(‘bastionName’)]”,
“location”: “[resourceGroup().location]”,
“properties”: {
“ipConfigurations”: [
{
“name”: “bastionIpConfig”,
“properties”: {
“subnet”: {
“id”: “[resourceId(‘Microsoft.Network/virtualNetworks/subnets’, ‘hub-vnet’, ‘AzureBastionSubnet’)]”
},
“publicIPAddress”: {
“id”: “[resourceId(‘Microsoft.Network/publicIPAddresses’, concat(parameters(‘bastionName’), ‘-pip’))]”
}
}
}
],
“enableTunneling”: true,
“enableIpConnect”: true,
“enableShareableLink”: true
},
“dependsOn”: [
“[resourceId(‘Microsoft.Network/virtualNetworks’, ‘hub-vnet’)]”,
“[resourceId(‘Microsoft.Network/publicIPAddresses’, concat(parameters(‘bastionName’), ‘-pip’))]”
]
}
]
}
- PowerShell Automation for Bastion Deployment
powershell
function New-CrossTenantBastion {
param(
[string]$HubSubscriptionId,
[string]$BastionName = “cross-tenant-bastion”,
[string]$HubVNetName = “hub-vnet”,
[string]$HubResourceGroup = “hub-networking”,
[string]$BastionSubnetPrefix = “10.1.0.0/27”
)
# Set context to hub subscription
Set-AzContext -SubscriptionId $HubSubscriptionId
# Create or get hub VNet
$vnet = Get-AzVirtualNetwork -Name $HubVNetName -ResourceGroupName $HubResourceGroup -ErrorAction SilentlyContinue
if (!$vnet) {
$vnet = New-AzVirtualNetwork -Name $HubVNetName -ResourceGroupName $HubResourceGroup `
-Location “eastus” -AddressPrefix “10.1.0.0/16”
}
# Create Bastion subnet
$bastionSubnet = Add-AzVirtualNetworkSubnetConfig -Name “AzureBastionSubnet” `
-VirtualNetwork $vnet -AddressPrefix $BastionSubnetPrefix
$vnet | Set-AzVirtualNetwork
# Create public IP
$publicIp = New-AzPublicIpAddress -Name “$BastionName-pip” -ResourceGroupName $HubResourceGroup `
-Location “eastus” -Sku “Standard” -AllocationMethod “Static” -Zone 1,2,3
# Deploy Azure Bastion
$bastion = New-AzBastion -ResourceGroupName $HubResourceGroup -Name $BastionName `
-PublicIpAddress $publicIp -VirtualNetwork $vnet -Sku “Standard” `
-EnableTunneling $true -EnableIpConnect $true -EnableShareableLink $true
Write-Output “Azure Bastion deployed successfully”
return @{
BastionId = $bastion.Id
PublicIp = $publicIp.IpAddress
ResourceGroup = $HubResourceGroup
}
}
- Network Architecture and Security
- Bastion Subnet Requirements
json
{
“bastionSubnetSpecs”: {
“name”: “AzureBastionSubnet”,
“minimumSize”: “/27”,
“recommendedSize”: “/26”,
“purpose”: “Dedicated for Azure Bastion only”,
“restrictions”: [
“No Network Security Groups (NSG) required”,
“No Route Tables (UDR) required”,
“No other resources can be deployed in this subnet”
]
},
“exampleConfigurations”: {
“small”: { “subnetSize”: “/27”, “maxInstances”: 2 },
“medium”: { “subnetSize”: “/26”, “maxInstances”: 8 },
“large”: { “subnetSize”: “/25”, “maxInstances”: 16 }
}
}
- Network Security Configuration
json
{
“resources”: [
{
“type”: “Microsoft.Network/networkSecurityGroups”,
“apiVersion”: “2023-05-01”,
“name”: “nsg-customer-vm-access”,
“location”: “eastus”,
“properties”: {
“securityRules”: [
{
“name”: “Allow-RDP-From-Bastion”,
“properties”: {
“protocol”: “TCP”,
“sourcePortRange”: “*”,
“destinationPortRange”: “3389”,
“sourceAddressPrefix”: “10.1.0.0/27”, # Bastion subnet
“destinationAddressPrefix”: “VirtualNetwork”,
“access”: “Allow”,
“priority”: 100,
“direction”: “Inbound”
}
},
{
“name”: “Allow-SSH-From-Bastion”,
“properties”: {
“protocol”: “TCP”,
“sourcePortRange”: “*”,
“destinationPortRange”: “22”,
“sourceAddressPrefix”: “10.1.0.0/27”, # Bastion subnet
“destinationAddressPrefix”: “VirtualNetwork”,
“access”: “Allow”,
“priority”: 110,
“direction”: “Inbound”
}
},
{
“name”: “Deny-All-Other-RDP-SSH”,
“properties”: {
“protocol”: “TCP”,
“sourcePortRange”: “*”,
“destinationPortRange”: “3389,22”,
“sourceAddressPrefix”: “*”,
“destinationAddressPrefix”: “*”,
“access”: “Deny”,
“priority”: 200,
“direction”: “Inbound”
}
}
]
}
}
]
}
- Specific Cross-Tenant Management Scenarios
Scenario 1: Direct VM Connectivity via Lighthouse
Access customer VMs directly through centralized Bastion
powershell
function Connect-CustomerVMViaBastion {
param(
[string]$BastionResourceGroup,
[string]$BastionName,
[string]$CustomerVMResourceId,
[string]$Protocol = “RDP”, # RDP or SSH
[int]$Port = 3389
)
# Get Bastion context
$bastion = Get-AzBastion -ResourceGroupName $BastionResourceGroup -Name $BastionName
# Generate connection script based on protocol
if ($Protocol -eq “RDP”) {
$connectionScript = @”
# RDP Connection via Azure Bastion
`$bastion = Get-AzBastion -ResourceGroupName ‘$BastionResourceGroup’ -Name ‘$BastionName’
`$vm = Get-AzResource -ResourceId ‘$CustomerVMResourceId’
Connect-AzBastionRDP -ResourceGroupName ‘$BastionResourceGroup’ -Name ‘$BastionName’ -TargetResourceId ‘$CustomerVMResourceId’ -Port $Port
“@
} else {
$connectionScript = @”
# SSH Connection via Azure Bastion
`$bastion = Get-AzBastion -ResourceGroupName ‘$BastionResourceGroup’ -Name ‘$BastionName’
`$vm = Get-AzResource -ResourceId ‘$CustomerVMResourceId’
Connect-AzBastionSSH -ResourceGroupName ‘$BastionResourceGroup’ -Name ‘$BastionName’ -TargetResourceId ‘$CustomerVMResourceId’ -Port $Port
“@
}
Write-Output “Connection script generated for $Protocol to $CustomerVMResourceId”
return $connectionScript
}
Scenario 2: Shareable Links for Temporary Access
Generate time-limited access links for customer collaboration
json
{
“resources”: [
{
“type”: “Microsoft.Network/bastionHosts”,
“apiVersion”: “2023-05-01”,
“name”: “bastion-shareable-links”,
“properties”: {
“ipConfigurations”: [ /* … */ ],
“enableShareableLink”: true
}
}
]
}
powershell
function New-BastionShareableLink {
param(
[string]$BastionResourceGroup,
[string]$BastionName,
[string]$TargetResourceId,
[string]$Protocol = “RDP”,
[timespan]$Duration = (New-TimeSpan -Hours 4)
)
# Generate shareable link
$shareableLink = New-AzBastionShareableLink -ResourceGroupName $BastionResourceGroup `
-BastionHostName $BastionName -TargetResourceId $TargetResourceId `
-Protocol $Protocol -Duration $Duration
# Log link creation for audit
Write-ActivityLog -Message “Shareable link created for $TargetResourceId” `
-Category “BastionAccess” -ResourceId $TargetResourceId
return @{
Link = $shareableLink.BastionShareableLink.Url
Expires = (Get-Date).Add($Duration)
Target = $TargetResourceId
}
}
Scenario 3: IP Connect for Native Client Access
Use native RDP/SSH clients through Bastion
powershell
function Enable-BastionIPConnect {
param(
[string]$BastionResourceGroup,
[string]$BastionName,
[string]$ClientIPAddress
)
# Enable IP Connect feature
$bastion = Get-AzBastion -ResourceGroupName $BastionResourceGroup -Name $BastionName
$bastion.EnableIpConnect = $true
$bastion | Set-AzBastion
# Generate IP Connect token
$token = New-AzBastionIpConnectToken -ResourceGroupName $BastionResourceGroup `
-BastionHostName $BastionName -TargetResourceId $TargetResourceId
Write-Output “IP Connect enabled. Token: $($token.IpConnectToken)”
return $token
}
- Integration with Other Azure Services
- Azure Bastion + Azure Firewall
json
{
“resources”: [
{
“type”: “Microsoft.Network/azureFirewalls”,
“apiVersion”: “2023-05-01”,
“name”: “fw-bastion-traffic”,
“properties”: {
“sku”: { “name”: “AZFW_Hub”, “tier”: “Standard” },
“threatIntelMode”: “Alert”,
“applicationRuleCollections”: [
{
“name”: “Allow-Bastion-WebAccess”,
“properties”: {
“priority”: 100,
“action”: { “type”: “Allow” },
“rules”: [
{
“name”: “Allow-Bastion-Portal”,
“protocols”: [{ “protocolType”: “Https”, “port”: 443 }],
“sourceAddresses”: [“10.1.0.0/27”], # Bastion subnet
“targetFqdns”: [
“*.blob.core.windows.net”,
“*.azurewebsites.net”,
“*.servicebus.windows.net”
]
}
]
}
}
]
}
}
]
}
- Azure Monitor Integration for Bastion Logging
json
{
“resources”: [
{
“type”: “Microsoft.Network/bastionHosts”,
“apiVersion”: “2023-05-01”,
“name”: “bastion-with-logs”,
“properties”: {
“ipConfigurations”: [ /* … */ ],
“enableTunneling”: true
}
},
{
“type”: “Microsoft.Insights/diagnosticSettings”,
“apiVersion”: “2021-05-01-preview”,
“name”: “bastion-diagnostics”,
“properties”: {
“workspaceId”: “[resourceId(‘Microsoft.OperationalInsights/workspaces’, ‘central-logs’)]”,
“logs”: [
{
“category”: “BastionAuditLogs”,
“enabled”: true,
“retentionPolicy”: {
“days”: 90,
“enabled”: true
}
}
]
},
“dependsOn”: [
“[resourceId(‘Microsoft.Network/bastionHosts’, ‘bastion-with-logs’)]”
]
}
]
}
- Security and Access Control
- Azure RBAC for Bastion Access
json
{
“roleAssignments”: [
{
“roleDefinitionId”: “1a9b8a64-43c6-4fb7-b74a-8ce04c92b13d”, # Bastion Reader
“principalId”: “support-team-group-id”,
“scope”: “/subscriptions/hub-sub/resourceGroups/hub-networking/providers/Microsoft.Network/bastionHosts/cross-tenant-bastion”
},
{
“roleDefinitionId”: “a795c144-9c7d-4b6b-9a53-20d2054d7b6c”, # Bastion Contributor
“principalId”: “bastion-admin-group-id”,
“scope”: “/subscriptions/hub-sub/resourceGroups/hub-networking”
}
]
}
- Conditional Access Policies
json
{
“conditionalAccessPolicy”: {
“displayName”: “CA-Bastion-Access-Require-MFA”,
“users”: {
“include”: [“Bastion-Users-Group”],
“exclude”: [“Break-Glass-Accounts”]
},
“applications”: {
“include”: [“Microsoft Azure Management”]
},
“conditions”: {
“locations”: {
“include”: [“All”]
},
“clientApps”: {
“include”: [“Browser”]
}
},
“grant”: {
“operator”: “AND”,
“controls”: [
{ “control”: “RequireMultiFactorAuthentication” },
{ “control”: “RequireCompliantDevice” }
]
}
}
}
- Just-In-Time VM Access with Bastion
powershell
function Enable-JITAccessWithBastion {
param(
[string]$VMResourceId,
[timespan]$AccessDuration = (New-TimeSpan -Hours 2),
[string]$Approver
)
# Request JIT access
$jitRequest = @{
VirtualMachines = @(
@{
Id = $VMResourceId
Ports = @(
@{
Number = 3389
Protocol = “TCP”
AllowedSourceAddressPrefix = “10.1.0.0/27” # Bastion subnet
MaxRequestAccessDuration = “PT2H”
}
)
}
)
}
# Submit JIT request
$jitPolicy = New-AzJitNetworkAccessPolicy -ResourceGroupName (Get-AzResource -ResourceId $VMResourceId).ResourceGroupName `
-Location (Get-AzResource -ResourceId $VMResourceId).Location -Name “Bastion-JIT” `
-VirtualMachine $jitRequest.VirtualMachines
Write-Output “JIT access enabled for VM: $VMResourceId”
Write-ActivityLog -Message “JIT access granted via Bastion for $AccessDuration” `
-Category “Security” -ResourceId $VMResourceId
return $jitPolicy
}
- Monitoring and Troubleshooting
- Bastion Connection Logging
kql
// Monitor Bastion connections across tenants
AzureDiagnostics
| where ResourceType == “BASTION_HOSTS”
| where Category == “BastionAuditLogs”
| extend SessionId = tostring(properties.SessionId)
| extend TargetResource = tostring(properties.TargetResource)
| extend User = tostring(properties.User)
| project TimeGenerated, SessionId, TargetResource, User, OperationName, ResultType
| summarize ConnectionCount = count() by bin(TimeGenerated, 1h), TargetResource
- Bastion Performance Monitoring
kql
// Monitor Bastion performance metrics
AzureMetrics
| where ResourceType == “BASTION_HOSTS”
| where MetricName in (“SessionCount”, “CPUUtilization”, “MemoryUtilization”)
| extend BastionName = tostring(split(ResourceId, ‘/’)[8])
| summarize
AvgSessions = avg(Average),
MaxSessions = max(Maximum),
P95Sessions = percentile(Average, 95)
by BastionName, MetricName, bin(TimeGenerated, 15m)
- Connection Health Checking
powershell
function Test-BastionConnectivity {
param(
[string]$BastionResourceGroup,
[string]$BastionName,
[string]$TestVMResourceId
)
$bastion = Get-AzBastion -ResourceGroupName $BastionResourceGroup -Name $BastionName
$testVM = Get-AzResource -ResourceId $TestVMResourceId
$connectivityTest = @{
BastionStatus = $bastion.ProvisioningState
BastionSku = $bastion.Sku.Name
TestVMStatus = $testVM.Properties.ProvisioningState
TestVMLocation = $testVM.Location
NetworkConnectivity = Test-NetConnection -ComputerName $testVM.Properties.privateIPAddress -Port 3389 -InformationLevel Quiet
}
# Log connectivity status
if ($connectivityTest.NetworkConnectivity) {
Write-Output “Bastion connectivity test PASSED”
} else {
Write-Warning “Bastion connectivity test FAILED”
}
return $connectivityTest
}
- Cost Optimization and Management
- Bastion SKU Selection Guide
json
{
“bastionSkuComparison”: {
“Basic”: {
“maxInstances”: 2,
“maxSessions”: 25,
“features”: [“RDP/SSH over browser”],
“monthlyCost”: “$0.19/hour + data processing”,
“recommendedFor”: “Small teams, infrequent use”
},
“Standard”: {
“maxInstances”: 10,
“maxSessions”: 50,
“features”: [“All Basic features”, “IP Connect”, “Shareable Links”, “Native Client Support”],
“monthlyCost”: “$0.32/hour + data processing”,
“recommendedFor”: “Cross-tenant management, enterprise use”
}
}
}
- Automated Bastion Scaling
powershell
function Optimize-BastionCost {
param(
[string]$BastionResourceGroup,
[string]$BastionName
)
$bastion = Get-AzBastion -ResourceGroupName $BastionResourceGroup -Name $BastionName
$sessions = Get-AzMetric -ResourceId $bastion.Id -MetricName “SessionCount” -TimeGrain 01:00:00
$avgSessions = ($sessions.Data | Measure-Object -Property Average -Average).Average
# Scale recommendations based on usage
if ($avgSessions -lt 5 -and $bastion.Sku.Name -eq “Standard”) {
Write-Output “Consider downgrading to Basic SKU – low session usage detected”
} elseif ($avgSessions -gt 40 -and $bastion.Sku.Name -eq “Standard”) {
Write-Output “High session usage detected – monitor for performance issues”
}
return @{
CurrentSku = $bastion.Sku.Name
AverageSessions = [math]::Round($avgSessions, 2)
Recommendation = if ($avgSessions -lt 5) { “Downgrade to Basic” } else { “Maintain Standard” }
}
}
Implementation Checklist
- Design hub VNet with dedicated AzureBastionSubnet (/27 or larger)
- Select appropriate Bastion SKU (Basic vs Standard)
- Configure public IP for Bastion host
- Set up Azure Lighthouse delegations for customer VM access
- Configure NSGs on customer VMs to allow Bastion subnet
- Implement RBAC for Bastion access control
- Enable diagnostic logging for audit purposes
- Configure Conditional Access policies if needed
- Test connectivity to customer VMs
- Document access procedures for support teams
Summary
Using Azure Bastion for cross-tenant management provides:
✅ Secure RDP/SSH access without public endpoints
✅ No open inbound ports on customer VMs
✅ Browser-based connectivity from anywhere
✅ Azure AD integration for authentication
✅ Audit logging of all sessions
✅ Shareable links for temporary access
✅ Native client support via IP Connect
The key success factors are proper network design, security configuration, cost optimization through appropriate SKU selection, and comprehensive monitoring of Bastion sessions across all customer environments.
what are the design components of Azure Lighthouse?
Excellent question! Azure Lighthouse has a well-defined architecture with specific design components that work together to enable cross-tenant management. Here’s a comprehensive breakdown of the key design components:
- Core Architectural Components
- Tenant Relationship Structure
- Fundamental Design Components
Component 1: Managed Services Registration Definition (MSRD)
The core artifact that defines the service offering and access rules
json
{
“type”: “Microsoft.ManagedServices/registrationDefinitions”,
“apiVersion”: “2019-09-01”,
“name”: “[guid(parameters(‘mspOfferName’))]”,
“properties”: {
“registrationDefinitionName”: “[parameters(‘mspOfferName’)]”,
“description”: “Managed services offer for Azure infrastructure management”,
“managedByTenantId”: “[parameters(‘managedByTenantId’)]”,
“authorizations”: [
{
“principalId”: “[parameters(‘supportEngineersGroupId’)]”,
“roleDefinitionId”: “b24988ac-6180-42a0-ab88-20f7382dd24c”, // Contributor
“principalIdDisplayName”: “Support Engineers Team”
},
{
“principalId”: “[parameters(‘monitoringGroupId’)]”,
“roleDefinitionId”: “acdd72a7-3385-48ef-bd42-f606fba81ae7”, // Reader
“principalIdDisplayName”: “Monitoring Team”
}
]
}
}
Component 2: Authorizations
Define WHO can access WHAT with WHICH permissions
json
“authorizations”: [
{
“principalId”: “a1b2c3d4-e5f6-7890-abcd-ef1234567890”,
“principalIdDisplayName”: “VM Operations Team”,
“roleDefinitionId”: “9980e02c-c2be-4d73-94e8-173b1dc7cf3c”, // Virtual Machine Contributor
“delegatedRoleDefinitionIds”: [
“b24988ac-6180-42a0-ab88-20f7382dd24c” // Contributor
]
}
]
Component 3: Registration Assignments
The actual assignment of the service offering to customer resources
json
{
“type”: “Microsoft.ManagedServices/registrationAssignments”,
“apiVersion”: “2019-09-01”,
“name”: “[guid(parameters(‘mspOfferName’), parameters(‘customerSubscriptionId’))]”,
“properties”: {
“registrationDefinitionId”: “[resourceId(‘Microsoft.ManagedServices/registrationDefinitions’, parameters(‘registrationDefinitionId’))]”
}
}
- Identity and Access Management Components
- Principal Types
json
{
“principalOptions”: {
“user”: {
“type”: “User”,
“useCase”: “Individual administrators”,
“limitation”: “User lifecycle management complexity”
},
“group”: {
“type”: “Group”,
“useCase”: “Recommended for teams”,
“benefit”: “Simplified user management”
},
“servicePrincipal”: {
“type”: “Service Principal”,
“useCase”: “Automation, runbooks, applications”,
“benefit”: “Non-interactive access”
},
“managedIdentity”: {
“type”: “Managed Identity”,
“useCase”: “Azure services automation”,
“benefit”: “No credential management”
}
}
}
- RBAC Integration
json
{
“rbacIntegration”: {
“builtInRoles”: [
“Owner”,
“Contributor”,
“Reader”,
“User Access Administrator”,
“Virtual Machine Contributor”,
“Storage Account Contributor”
],
“customRoles”: {
“purpose”: “Least privilege access”,
“example”: “VM-Start-Stop-Only”,
“benefit”: “Reduced risk exposure”
},
“limitations”: [
“Cannot grant classical administrator roles”,
“Cannot manage Azure AD itself”,
“Limited data plane operations”
]
}
}
- Scope Management Components
- Scope Levels
json
{
“scopeLevels”: {
“managementGroup”: {
“useCase”: “Enterprise-wide management”,
“benefit”: “Broad coverage across subscriptions”,
“limitation”: “Requires customer MG permissions”
},
“subscription”: {
“useCase”: “Most common scenario”,
“benefit”: “Full subscription access”,
“recommendation”: “Default starting point”
},
“resourceGroup”: {
“useCase”: “Limited, specific resources”,
“benefit”: “Least privilege principle”,
“example”: “Single application workload”
}
}
}
- Scope Hierarchy Design
- Service Provider Management Components
- My Customers View
Centralized view of all customer resources
json
{
“myCustomers”: {
“features”: [
“Unified view across all customers”,
“Directory and subscription switcher”,
“Bulk operations across tenants”,
“Access review capabilities”
],
“accessMethods”: [
“Azure Portal: My Customers blade”,
“PowerShell: Get-AzLighthouse* cmdlets”,
“CLI: az managedservices commands”,
“REST API: ManagedServices provider”
]
}
}
- Managed Services Marketplace Integration
json
{
“marketplaceIntegration”: {
“privateOffers”: {
“purpose”: “Specific customer offerings”,
“process”: “Publish via Partner Center”,
“benefit”: “Formalized service agreement”
},
“publicOffers”: {
“purpose”: “Standardized service catalog”,
“process”: “Public marketplace listing”,
“benefit”: “Customer self-service onboarding”
},
“pricingModels”: [
“Bring Your Own License (BYOL)”,
“Usage-based pricing”,
“Flat-rate monthly pricing”
]
}
}
- Security and Compliance Components
- Audit and Monitoring
json
{
“auditComponents”: {
“activityLogs”: {
“source”: “Customer tenant”,
“data”: “All actions by managing tenant users”,
“retention”: “90 days by default”
},
“azureAdAuditLogs”: {
“source”: “Managing tenant”,
“data”: “User sign-ins and access patterns”,
“integration”: “Azure Sentinel, Log Analytics”
},
“customMonitoring”: {
“approaches”: [
“Centralized Log Analytics workspace”,
“Azure Policy compliance tracking”,
“Custom alert rules for suspicious activity”
]
}
}
}
- Access Review Components
json
{
“accessReview”: {
“periodicReviews”: {
“frequency”: “Quarterly recommended”,
“scope”: “All lighthouse authorizations”,
“process”: “Azure AD Access Reviews”
},
“automatedRemediation”: {
“inactiveUsers”: “Auto-remove after 90 days inactivity”,
“roleChanges”: “Update based on job function changes”,
“customerChanges”: “Adjust based on contract changes”
}
}
}
- Automation and Integration Components
- ARM Template Components
json
{
“armTemplateStructure”: {
“parameters”: {
“mspOfferName”: “Unique service identifier”,
“managedByTenantId”: “Service provider tenant ID”,
“authorizations”: “Array of access definitions”
},
“variables”: {
“registrationDefinitionId”: “Generated GUID”,
“roleDefinitionIds”: “RBAC role references”
},
“resources”: [
“registrationDefinition”,
“optional: customer resources monitoring”
],
“outputs”: {
“mspOfferDescription”: “Service description”,
“registrationDefinitionId”: “For assignment reference”
}
}
}
- PowerShell Integration
powershell
# Lighthouse Management Module
class LighthouseDesignComponents {
[string]$ManagingTenantId
[array]$CustomerSubscriptions
[hashtable]$ServiceOfferings
[array]$AuthorizationTemplates
# Method to create new service offering
[void] CreateServiceOffering(
[string]$OfferName,
[array]$Authorizations,
[string]$Description
) {
# Implementation for registration definition
}
# Method to onboard customer
[void] OnboardCustomer(
[string]$CustomerSubscriptionId,
[string]$OfferName,
[string]$Scope
) {
# Implementation for registration assignment
}
}
- Advanced Design Components
- Nested Lighthouse Scenarios
json
{
“nestedLighthouse”: {
“scenario”: “Tiered service delivery”,
“architecture”: “MSP -> Sub-MSP -> End Customer”,
“components”: [
“Primary MSP delegates to secondary MSP”,
“Secondary MSP manages customer resources”,
“Audit chain maintained across tiers”
],
“considerations”: [
“Complex access tracing”,
“Cumulative permission evaluation”,
“Multi-level compliance requirements”
]
}
}
- Cross-Tenant Monitoring Architecture
json
{
“monitoringArchitecture”: {
“centralLogging”: {
“workspace”: “Log Analytics in managing tenant”,
“dataSources”: [
“Activity logs from all customers”,
“Resource metrics and diagnostics”,
“Security Center findings”
],
“integration”: “Azure Lighthouse APIs”
},
“alerting”: {
“unifiedAlerts”: “Cross-tenant alert rules”,
“actionGroups”: “Centralized notification system”,
“automatedResponse”: “Cross-tenant runbooks”
}
}
}
- Governance and Policy Components
- Azure Policy Integration
json
{
“policyComponents”: {
“definitionLocation”: “Managing tenant”,
“assignmentScope”: “Customer subscriptions”,
“complianceTracking”: “Centralized compliance dashboard”,
“remediation”: “Cross-tenant remediation tasks”
}
}
- Cost Management Components
json
{
“costManagement”: {
“visibility”: “Cost analysis across all customers”,
“chargeback”: “Resource tagging for cost allocation”,
“budgeting”: “Cross-tenant budget alerts”,
“optimization”: “Centralized recommendations”
}
}
- Lifecycle Management Components
- Onboarding Workflow
json
{
“onboardingProcess”: {
“phase1”: {
“name”: “Preparation”,
“activities”: [
“Customer agreement and scope definition”,
“RBAC strategy and role design”,
“ARM template development”
]
},
“phase2”: {
“name”: “Deployment”,
“activities”: [
“Registration definition creation”,
“Customer deployment validation”,
“Access testing and verification”
]
},
“phase3”: {
“name”: “Operation”,
“activities”: [
“Monitoring and alerting setup”,
“Documentation and runbooks”,
“Customer training and handoff”
]
}
}
}
- Offboarding Components
json
{
“offboardingProcess”: {
“accessRevocation”: {
“immediate”: “Remove registration assignments”,
“validation”: “Verify access termination”,
“confirmation”: “Customer sign-off”
},
“dataHandling”: {
“logsRetention”: “Maintain audit trails as required”,
“customerData”: “Ensure complete data handover”,
“compliance”: “Meet contractual and regulatory requirements”
}
}
}
Summary of Key Design Components
Component Category | Key Elements | Purpose |
Core Architecture | Registration Definitions, Authorizations, Assignments | Foundation of service offering and access |
Identity & Access | Users, Groups, Service Principals, Managed Identities | Secure, manageable access control |
Scope Management | Management Groups, Subscriptions, Resource Groups | Granular resource targeting |
Service Provider Tools | My Customers view, Marketplace integration | Operational efficiency and scaling |
Security & Compliance | Audit logs, Access reviews, Monitoring | Risk management and compliance |
Automation | ARM templates, PowerShell, REST APIs | Scalable deployment and management |
Governance | Azure Policy, Cost Management, Tagging | Consistent operations and control |
Lifecycle | Onboarding, Operations, Offboarding | End-to-end service management |
The strength of Azure Lighthouse lies in how these components work together to create a secure, scalable, and manageable cross-tenant management solution that maintains clear boundaries while enabling efficient service delivery.