Skip to content
Merged
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
2 changes: 1 addition & 1 deletion 03-Azure/01-03-Infrastructure/01_Sovereign_Cloud/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ The main cost driver for this Hackathon is virtual machines:
- Plan subscription quotas for at least 12 general-purpose vCPUs and 4 confidential vCPUs per participant, plus upgrade headroom. Keep two participants per subscription unless larger aggregate increases have been approved. Challenge 5 application cleanup does not release node quota because Challenge 7 still uses the cluster.

For a 50-participant event, this planning range is USD 1,750-2,250 per day, plus LocalBox for each participating subscription if Challenge 6 is enabled.
There will also be smaller costs for services such as Key Vault, storage, and monitoring. Budget separately for the approved Defender for Servers plan used in Challenge 6.
There will also be smaller costs for services such as Key Vault, storage, and monitoring. Hosted Console setup automatically enables **Defender for Servers P2 and Endpoint protection on every event subscription**. Budget separately for P2 charges on covered servers during preparation and delivery; the infrastructure estimates above do not include them. Manual/BYOS organizers enable their approved plan separately. Removing lab resource groups does not reset subscription-level Defender settings.
An Azure Pricing Calculator estimate is available [here](https://azure.com/e/1a7aec76a3e049cba57cda6742025373).
This estimate can be adjusted for fewer/more students, running the VMs shorter/longer and adding additional services if desired.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
function Initialize-MhhHostedDefender {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$SubscriptionId
)

$request = {
param([string]$Path, [string]$Method, [hashtable]$Body)
Update-MhhToken | Out-Null
$context = Get-AzContext -ErrorAction Stop
if ($context.Subscription.Id -ne $SubscriptionId) {
throw "The Azure context must target hosted subscription $SubscriptionId before configuring Defender."
}
$arguments = @{ Path = $Path; Method = $Method; ErrorAction = 'Stop' }
if ($null -ne $Body) {
$arguments.Payload = $Body | ConvertTo-Json -Depth 30 -Compress
}
$response = Invoke-AzRestMethod @arguments
$expectedStatus = if ($Method -eq 'PUT') { @(200, 201) } else { @(200) }
if ($response.StatusCode -notin $expectedStatus) {
throw "Defender $Method $Path failed (HTTP $($response.StatusCode)): $($response.Content)"
}
$response.Content | ConvertFrom-Json -AsHashtable -ErrorAction Stop
}

$basePath = "/subscriptions/$SubscriptionId/providers/Microsoft.Security"
$pricingPath = "$basePath/pricings/VirtualMachines?api-version=2024-01-01"
$endpointPath = "$basePath/settings/WDATP?api-version=2021-06-01"
Write-Host "Enabling paid Defender for Servers P2 and Endpoint protection in hosted subscription $SubscriptionId..."
$pricing = & $request $pricingPath 'GET'
if (-not $pricing.properties -or -not $pricing.properties.pricingTier) {
throw 'Defender pricing response is missing properties.pricingTier.'
}
if ($pricing.properties.pricingTier -ne 'Standard' -or $pricing.properties.subPlan -ne 'P2') {
$properties = @{ pricingTier = 'Standard'; subPlan = 'P2' }
if ($pricing.properties.ContainsKey('enforce')) {
$properties.enforce = $pricing.properties.enforce
}
if ($pricing.properties.ContainsKey('extensions')) {
# Preserve configured extensions, excluding read-only operation status.
$properties.extensions = @(
foreach ($extension in $pricing.properties.extensions) {
$item = @{ name = $extension.name; isEnabled = $extension.isEnabled }
if ($extension.ContainsKey('additionalExtensionProperties')) {
$item.additionalExtensionProperties = $extension.additionalExtensionProperties
}
$item
}
)
}
& $request $pricingPath 'PUT' @{ properties = $properties } | Out-Null
}

& $request $endpointPath 'PUT' @{
kind = 'DataExportSettings'
properties = @{ enabled = $true }
} | Out-Null

for ($attempt = 1; $attempt -le 12; $attempt++) {
$pricing = & $request $pricingPath 'GET'
$endpoint = & $request $endpointPath 'GET'
if ($pricing.properties.pricingTier -eq 'Standard' -and
$pricing.properties.subPlan -eq 'P2' -and
$endpoint.properties.enabled -is [bool] -and $endpoint.properties.enabled) {
Write-Host 'Verified Defender for Servers P2 and Endpoint protection. VM onboarding must still be validated.' -ForegroundColor Green
return
}
if ($attempt -lt 12) {
Write-Host "Waiting for Defender settings propagation ($attempt/12)..."
Start-Sleep -Seconds 10
}
}
throw "Defender verification failed in subscription $SubscriptionId after 12 attempts: tier=$($pricing.properties.pricingTier), plan=$($pricing.properties.subPlan), Endpoint protection=$($endpoint.properties.enabled). Stop provisioning and inspect Defender environment settings."
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ required Azure resource providers. It ensures one preferred region has the VM
SKUs and compute quota required by the subscription's participant count.
It also submits one shared LocalBox environment per subscription for Challenge 6.
For Microsoft-hosted environments only: assigns and verifies the MCAPS control-tag
initiative before deploying resources. Do not use this hook for BYOS setup.
initiative and enables paid Defender for Servers P2 with Endpoint protection before
deploying resources. Do not use this hook for BYOS setup.
#>
param(
[Parameter(Mandatory=$true)]
Expand All @@ -23,6 +24,7 @@ param(
. (Join-Path $PSScriptRoot 'quota-helpers.ps1')
. (Join-Path $PSScriptRoot 'localbox-credentials.ps1')
. (Join-Path $PSScriptRoot 'hosted-tag-policy.ps1')
. (Join-Path $PSScriptRoot 'hosted-defender.ps1')

Get-LocalBoxConsoleGroupCredential

Expand Down Expand Up @@ -155,6 +157,7 @@ Set-MhhConfidentialComputeSelection -SubscriptionId $SubscriptionId -Candidate $
Write-Host "Selected $($selectedCandidate.VmSize) in $($selectedCandidate.Location); compute SKUs and quotas are ready for $participantCount participants." -ForegroundColor Green

Initialize-MhhHostedTagPolicy -SubscriptionId $SubscriptionId -Location $selectedCandidate.Location
Initialize-MhhHostedDefender -SubscriptionId $SubscriptionId

$localBoxResourceGroupName = 'rg-localbox-shared'
$localBoxLocations = @(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,31 @@ This runbook covers the FY27 EMEA Cloud & AI Hackathons program described in the

When automatic provisioning is not scheduled, use the Console's **Create Users**, content-pack license defaults and **Deploy Lab Environment** lifecycle in order. Investigate failures before continuing; do not compensate by running subscription-wide manual utilities.

## Defender for Servers configuration and costs

The [shared hook](../../labautomation/shared-deploy-lab.ps1) calls
[hosted Defender setup](../../labautomation/hosted-defender.ps1) once per subscription,
after hosted tag-policy verification and before LocalBox deployment. It sets
`Microsoft.Security/pricings/VirtualMachines` to `Standard` / `P2` and
`Microsoft.Security/settings/WDATP` to `enabled=true` (the **Endpoint protection**
toggle). Existing pricing extension and enforcement settings are preserved; other
Defender plans and settings are not changed. Reruns never toggle protection off.

The Console deployment identity needs permission to read/write these subscription
settings; the hosted subscription Owner identity supplies it. Participants retain
their existing roles, including Security Reader; no participant subscription Owner
or User Access Administrator role is added. Setup verifies both settings by GET,
retrying propagation up to 12 times, 10 seconds apart. Authorization/API failures
or verification timeout stop shared setup rather than report readiness. A failure
does not roll back P2 or disable protection; inspect the settings before retrying.

**P2 is a paid subscription-wide plan**, not a per-lab-RG setting. Include its
charges for covered servers during preparation and delivery in the approved event
budget, separately from the existing infrastructure estimates. Use only dedicated
hosted lab subscriptions. Deleting lab resource groups does not reset the plan or
Endpoint integration; the subscription owner must review these settings when
releasing a subscription. This hook is not part of manual/BYOS preparation.

## Complete LocalBox preparation

The shared hook submits `localbox-*` in `rg-localbox-shared`, then waits up to six hours for ARM completion, refreshing its Console authentication while polling. It does not publish LocalBox administrator credentials. A Client VM appearing after roughly 15-20 minutes confirms only that deployment has started. Full nested Azure Local provisioning can take 4-6 hours and must still be checked separately.
Expand All @@ -23,7 +48,7 @@ The shared hook submits `localbox-*` in `rg-localbox-shared`, then waits up to s
3. Copy **Lab Group ObjectId** from the Console's **Credentials** tab for the preparation prompt or `-AksAdminGroupObjectId`. Confirm that intended Azure lab identities/coaches are members; see the group dependency below.
4. Follow [LocalBox preparation](../localbox/readme.md), once per shared subscription, in elevated PowerShell 7. It creates AKS and then installs/verifies the shared MetalLB extension and reserved ARP pool. Azure authentication uses the Client VM's managed identity; preparation constructs the nested Windows credential locally from the installed configuration without printing it. An explicit `-NodeCredential` overrides that value after a nested-account rotation.
5. Run [Pester health checks](../tests/readme.md) for LocalBox and every selected participant lab. A control-plane-only pass does not establish full readiness.
6. Complete the [participant VM readiness exercise](../localbox/manual-preparation.md#step-6-test-the-environment), including guest management, Defender and Update Manager. Subscription-wide paid-plan changes require the authorized owner and approved budget.
6. Console shared setup enables and verifies **Defender for Servers Plan 2** and **Endpoint protection** on every event subscription. Complete the [Defender readiness checklist](../localbox/manual-preparation.md#defender-for-servers-readiness-organizer) and [participant VM readiness exercise](../localbox/manual-preparation.md#step-6-test-the-environment), including guest management, actual Defender onboarding and Update Manager. Verified subscription settings do not prove that a VM has completed onboarding.
7. Verify an intended participant can use Entra-authenticated `az connectedk8s proxy` and a private application port-forward from their Codespace. Participants inspect MetalLB, not install it, and never need LocalBox-Client access. This validates the lab access path, not routing to the MetalLB service VIP.

Shared setup registers `Microsoft.KubernetesRuntime`, waits for registration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,38 @@ Hosted lab automation grants participants access to shared LocalBox resources, *

#### Defender for Servers readiness (organizer)

Complete these checks on **every event subscription** before attendees arrive.
Hosted Console setup enables and reads back **Defender for Servers P2** and
**Endpoint protection**, and grants participants Security Reader access. For
manual/BYOS setup, an authorized subscription administrator enables the approved
plan and integration using the steps below. In both paths, verify actual onboarding
of a test participant VM; subscription configuration alone is not exercise readiness.

1. Confirm the Defender for Servers plan approved for the event, including its subscription scope and charges
2. As an authorized subscription administrator, open **Microsoft Defender for Cloud -> Environment settings** and select the lab subscription
3. Under **Defender plans**, enable **Servers** with the approved plan if it is not already enabled, and save the changes
4. Verify that the [Defender for Endpoint integration](https://learn.microsoft.com/azure/defender-for-cloud/enable-defender-for-endpoint) is enabled and that required onboarding settings and extensions can apply to the participant VMs
4. Open **Settings & monitoring** for Servers and verify **Endpoint protection** is **On**. If enabling it, select **Continue**, then **Save** on the Defender plans page. This [Defender for Endpoint integration](https://learn.microsoft.com/azure/defender-for-cloud/enable-defender-for-endpoint) is separate from the Servers plan status; verify it even when the plan is already enabled.
5. Verify that participants have **Security Reader** access to review coverage and recommendations. Students verify protection on their own VM; subscription-level plan changes remain an organizer responsibility

For a read-only CLI check, use the intended event subscription explicitly:

```bash
SUBSCRIPTION_ID='<event-subscription-id>'
az rest --method get \
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/providers/Microsoft.Security/pricings/VirtualMachines?api-version=2024-01-01" \
--query 'properties.{tier:pricingTier,plan:subPlan}'
az rest --method get \
--url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/providers/Microsoft.Security/settings/WDATP?api-version=2021-06-01" \
--query 'properties.enabled'
```

For hosted Console labs, expect `Standard` / `P2` and `true` for `WDATP`.
For manual labs, compare the returned plan with the approved plan. A missing setting
or a failed query is not proof that integration is enabled. These are
subscription-configuration checks only: verify `MDE.Windows` extension success
and actual device onboarding on the test VM below. Allow for onboarding delays;
do not repeatedly toggle integration to force deployment.

### Step 6: Test the Environment

Before participants begin, follow the [Challenge 6 walkthrough](../../walkthrough/challenge-06/solution-06.md) using a normal participant identity:
Expand Down
Loading
Loading