Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<#
.SYNOPSIS
Deploys the lab resources scoped to a subscription or resource group.
.DESCRIPTION
Provides a controlled deployment flow for lab environments, optionally limited to a resource group and specific Entra user IDs.
.PARAMETER DeploymentType
Defines the deployment scope; allowed values are subscription or resourcegroup.
.PARAMETER SubscriptionId
Specifies the Azure subscription that contains the lab resources.
.PARAMETER ResourceGroupName
In case of resourcegroup deployment, specifies the target resource group name.
.PARAMETER PreferredLocation
Specifies the preferred Azure regions (ordered by preference) for resource deployment. An empty array indicates no preference.
.PARAMETER AllowedEntraUserIds
Optional list of Entra user object IDs permitted to access the lab resources.
#>
param(
[Parameter(Mandatory=$true)]
[ValidateSet('subscription','resourcegroup', 'resourcegroup-with-subscriptionowner')]
[string]$DeploymentType,

[Parameter(Mandatory=$true)]
[string]$SubscriptionId,

[string]$ResourceGroupName = "",

[string[]]$PreferredLocation = @(),

[string[]]$AllowedEntraUserIds = @()
)

# Validate parameters
if($DeploymentType -eq 'resourcegroup' -and [string]::IsNullOrEmpty($ResourceGroupName)) {
throw "ResourceGroupName must be provided when DeploymentType is 'resourcegroup'."
}

# set the effective location (used as the metadata location for the subscription-scoped deployment)
if($PreferredLocation.Count -gt 0) {
$effectiveLocation = $PreferredLocation[0]
} else {
$effectiveLocation = "swedencentral" # Default location if no preference is provided
}

# With deploymentType = resourcegroup the platform has already created one resource
# group per participant in the shared subscription and granted the participant Owner
# on it. Surface that resource group name on the participant's dashboard.
if(-not [string]::IsNullOrEmpty($ResourceGroupName)) {
@{"HackboxCredential" = @{ name = "Resource Group Name"; value = $ResourceGroupName; note = "Your dedicated resource group (you have Owner)" }}
}

# Register the resource providers required by the Sovereign Cloud lab on the shared
# subscription (the platform has already set the Azure context to $SubscriptionId).
Write-Host "Registering required resource providers..."
& (Join-Path $PSScriptRoot 'resource-providers.ps1')

# Assign the lab-specific subscription-scoped RBAC (Security Reader + Resource Policy
# Contributor) to the participant.
# main.bicep targets the subscription scope, so it is deployed with New-AzSubscriptionDeployment.
$deploymentName = "lab-" + (Get-MhhStableHash -Value $AllowedEntraUserIds -Length 24)

Write-Host "Assigning subscription-scoped lab RBAC to participant $($AllowedEntraUserIds[0])..."
New-AzSubscriptionDeployment `
-Name $deploymentName `
-Location $effectiveLocation `
-TemplateFile (Join-Path $PSScriptRoot 'main.bicep') `
-TemplateParameterObject @{
userObjectId = $AllowedEntraUserIds[0]
resourceGroupName = $ResourceGroupName
} | Out-Null
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/MicroHack/refs/heads/main/lab-defaults-schema.json",
"groups": [],
"deploymentType": "resourcegroup",
"labsPerSubscription": 60,
"preferredLocation": "swedencentral, italynorth, spaincentral",
"estimatedDailyCostsUsd": 5.0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Sovereign Cloud MicroHack - per-participant lab RBAC
//
// deploymentType = resourcegroup: the platform pre-creates one resource group
// per participant in the shared subscription and grants the participant Owner on
// that resource group plus Reader on the subscription. This template adds the
// same subscription-scoped permissions that resources/subscription-preparations/3-rbac.ps1
// previously assigned to the LabUsers group:
// - Security Reader (view Defender for Cloud secure score / recommendations)
// - Resource Policy Contributor (author and assign Azure Policy at subscription scope)
//
// The role assignments are subscription-scoped, so this deployment must target the
// subscription (see deploy-lab.ps1, which invokes it with New-AzSubscriptionDeployment).

targetScope = 'subscription'

@description('Entra object ID of the lab participant to grant the lab-specific subscription-scoped RBAC roles to.')
param userObjectId string

@description('Name of the participant resource group (created by the platform) to grant resource-group-scoped RBAC roles in.')
param resourceGroupName string

// Built-in role definition IDs (stable across all Azure subscriptions)
var securityReaderRoleId = '39bc4728-0917-49c7-9d2c-d95423bc2eb4'
var resourcePolicyContributorRoleId = '36243c78-bf99-498c-9df9-86d9f8d28608'

resource securityReaderAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(subscription().id, userObjectId, securityReaderRoleId)
properties: {
principalId: userObjectId
principalType: 'User'
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', securityReaderRoleId)
}
}

resource resourcePolicyContributorAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(subscription().id, userObjectId, resourcePolicyContributorRoleId)
properties: {
principalId: userObjectId
principalType: 'User'
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', resourcePolicyContributorRoleId)
}
}

// Resource-group-scoped roles for the participant's dedicated resource group
// (Owner is already granted by the platform).
module resourceGroupRbac 'rg-rbac.bicep' = {
name: 'lab-rg-rbac'
scope: resourceGroup(resourceGroupName)
params: {
userObjectId: userObjectId
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<#
.SYNOPSIS
Register required Azure resource providers for the Sovereign Cloud MicroHack.

.DESCRIPTION
This script registers all required Azure resource providers needed for the
Sovereign Cloud MicroHack across all available subscriptions.

Required providers include:
- Azure Arc and hybrid connectivity
- Azure Local (Stack HCI)
- Confidential computing
- Key Vault and encryption
- Monitoring and policy

.EXAMPLE
.\1-resource-providers.ps1
Registers all required resource providers

.NOTES
Author: MicroHack Team
Date: January 2026

.LINK
https://learn.microsoft.com/azure/azure-resource-manager/management/resource-providers-and-types
#>

[CmdletBinding()]
param(
)

# Ensure required modules are available
$requiredModules = @('Az.Accounts', 'Az.Resources')
foreach ($module in $requiredModules) {
if (-not (Get-Module -ListAvailable -Name $module)) {
Write-Error "$module module is not installed. Please run: Install-Module -Name $module"
exit 1
}
}

# Import required modules
Import-Module Az.Accounts, Az.Resources -ErrorAction Stop

Write-Host "`n=== Resource Provider Registration Utility ===" -ForegroundColor Cyan
Write-Host "This script will register all required resource providers for the Sovereign Cloud MicroHack."
Write-Host ""

# Check if user is logged in
try {
$context = Get-AzContext
if (-not $context) {
Write-Host "No Azure context found. Please login..." -ForegroundColor Yellow
$context = Get-AzContext
} else {
Write-Host "Using Azure account: $($context.Account.Id)" -ForegroundColor Green
}
} catch {
Write-Error "Failed to get Azure context. Please run Connect-AzAccount first."
exit 1
}

# Get all subscriptions
$subscriptions = Get-AzSubscription

if ($subscriptions.Count -eq 0) {
Write-Error "No subscriptions found. Please ensure you have access to at least one subscription."
exit 1
}

Write-Host "Found $($subscriptions.Count) subscription(s)" -ForegroundColor Green

# List of resource providers to register for Sovereign Cloud MicroHack
$providers = @(
# Azure Arc and Hybrid
"Microsoft.HybridCompute",
"Microsoft.GuestConfiguration",
"Microsoft.HybridConnectivity",
"Microsoft.AzureArcData",

# Azure Local (Stack HCI)
"Microsoft.AzureStackHCI",
"Microsoft.ResourceConnector",
"Microsoft.HybridContainerService",

# Compute and Confidential Computing
"Microsoft.Compute",
"Microsoft.ConfidentialLedger",

# Security and Compliance
"Microsoft.Security",
"Microsoft.PolicyInsights",
"Microsoft.Advisor",

# Monitoring and Operations
"Microsoft.OperationsManagement",
"Microsoft.OperationalInsights",
"Microsoft.Insights",
"Microsoft.Monitor",

# Key Vault and Encryption
"Microsoft.KeyVault",
"Microsoft.ManagedIdentity",

# Networking
"Microsoft.Network",

# Storage
"Microsoft.Storage",

# Attestation (for Confidential Computing)
"Microsoft.Attestation",

# Kubernetes (for AKS Arc)
"Microsoft.Kubernetes",
"Microsoft.KubernetesConfiguration",
"Microsoft.ContainerService",

# Extended Location (for Azure Local)
"Microsoft.ExtendedLocation"
)

Write-Host "`nResource providers to register:" -ForegroundColor Yellow
foreach ($provider in $providers) {
Write-Host " - $provider" -ForegroundColor Gray
}

# Register resource providers for current subscription

foreach ($provider in $providers) {
$existingProvider = Get-AzResourceProvider -ProviderNamespace $provider -ErrorAction SilentlyContinue

if ($existingProvider.RegistrationState -eq 'Registered') {
Write-Host " [REGISTERED] $provider" -ForegroundColor Green
} else {
Write-Host " [REGISTERING] $provider..." -ForegroundColor Yellow
try {
Register-AzResourceProvider -ProviderNamespace $provider | Out-Null
Write-Host " Registration initiated" -ForegroundColor Gray
} catch {
Write-Host " Failed to register: $($_.Exception.Message)" -ForegroundColor Red
}
}
}


Write-Host "`n" + ("=" * 80) -ForegroundColor Cyan
Write-Host "SUMMARY" -ForegroundColor Cyan
Write-Host ("=" * 80) -ForegroundColor Cyan
Write-Host "Resource provider registration initiated for subscription: $($SubscriptionId)" -ForegroundColor Green
Write-Host "`nNote: Some providers may take a few minutes to fully register." -ForegroundColor Yellow
Write-Host "You can check registration status with: Get-AzResourceProvider -ProviderNamespace <namespace>" -ForegroundColor Gray
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Sovereign Cloud MicroHack - per-participant resource-group-scoped RBAC
//
// Deployed as a module (scope = the participant's resource group) from main.bicep.
// Adds the resource-group-scoped roles (per participant).
// Owner on the resource group is already granted by the platform (deploymentType =
// resourcegroup), so only the two additional roles are assigned here:
// - Key Vault Administrator
// - Storage Account Contributor

targetScope = 'resourceGroup'

@description('Entra object ID of the lab participant to grant the resource-group-scoped RBAC roles to.')
param userObjectId string

// Built-in role definition IDs (stable across all Azure subscriptions)
var keyVaultAdministratorRoleId = '00482a5a-887f-4fb3-b363-3b7fe8e74483'
var storageAccountContributorRoleId = '17d1049b-9a84-46fb-8f53-869881c3d3ab'

resource keyVaultAdministratorAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(resourceGroup().id, userObjectId, keyVaultAdministratorRoleId)
properties: {
principalId: userObjectId
principalType: 'User'
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', keyVaultAdministratorRoleId)
}
}

resource storageAccountContributorAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(resourceGroup().id, userObjectId, storageAccountContributorRoleId)
properties: {
principalId: userObjectId
principalType: 'User'
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', storageAccountContributorRoleId)
}
}
Empty file.
Loading