Skip to content

Commit cac797a

Browse files
fix: update documentation and configuration for Microsoft Entra ID authentication on Jump VM via Azure Bastion
1 parent 3aca9a7 commit cac797a

8 files changed

Lines changed: 128 additions & 41 deletions

docs/ACCESSING_PRIVATE_RESOURCES.md

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,39 @@ To access these private resources, the deployment includes:
1010

1111
## How to Access Private Resources
1212

13-
### 1. Connect to Jump VM via Bastion
13+
### 1. Connect to Jump VM via Bastion (Microsoft Entra ID sign-in)
1414

15-
```bashazd up
16-
# Get the Jump VM name from deployment outputs
17-
azd env get-values | grep jumpVm
15+
The jumpbox VM is provisioned with the **AAD Login for Windows** extension and the deploying
16+
principal is automatically granted the **Virtual Machine Administrator Login** role on the VM.
17+
Azure Bastion is deployed using the **Standard** SKU (which supports Microsoft Entra ID
18+
authentication for Azure portal RDP/SSH sessions).
1819

19-
# Or in Azure Portal:
20+
You sign in to the jumpbox with your **Microsoft Entra ID** credentials — there is **no local
21+
username/password to manage**.
22+
23+
```text
24+
# In the Azure Portal:
2025
# 1. Navigate to your resource group
21-
# 2. Find the VM resource created for the jump box
22-
# 3. Click "Connect" → "Bastion"
23-
# 4. Enter the username and password you set via VM_ADMIN_USERNAME / VM_ADMIN_PASSWORD
26+
# 2. Open the jump VM (name starts with "testvm")
27+
# 3. Click "Connect" -> "Bastion"
28+
# 4. In the Bastion connection blade:
29+
# Authentication type: "Microsoft Entra ID"
30+
# Protocol: RDP
31+
# (No username / password fields will be required.)
32+
# 5. Click "Connect" - a browser tab opens with the RDP session,
33+
# signed in as your Entra ID user.
2434
```
2535

36+
> **Note:** To grant additional users access, assign one of the following RBAC roles to them
37+
> on the jump VM (or the resource group):
38+
> - **Virtual Machine Administrator Login** - sign in with local administrator privileges
39+
> - **Virtual Machine User Login** - sign in as a standard user
40+
>
41+
42+
> A local admin account is still
43+
> created on the VM because Windows requires one at provisioning time, but its password is
44+
> auto-generated, never displayed, and **not** used to connect through Bastion.
45+
2646
### 2. From Jump VM, Access Private Services
2747

2848
Once connected to the Jump VM, you can:
@@ -167,23 +187,32 @@ You can configure services without private endpoints by modifying individual ser
167187
3. Ensure NSGs allow traffic from Jump VM subnet to private endpoints subnet
168188
4. Test DNS resolution: `nslookup <service-name>.vault.azure.net`
169189

170-
### Jump VM credentials unknown
171-
172-
If you did not set the credentials before deployment, use the top-layer defaults or reset them:
173-
174-
- Username: `VM_ADMIN_USERNAME` environment variable, or `vmUserName` in [infra/main.bicepparam](../infra/main.bicepparam)
175-
- Default username when unset: `testvmuser`
176-
- Password: `VM_ADMIN_PASSWORD` environment variable, or `vmAdminPassword` in [infra/main.bicepparam](../infra/main.bicepparam)
177-
178-
To reset:
190+
### Cannot sign in to the Jump VM through Bastion
191+
192+
Sign-in uses **Microsoft Entra ID** — there is no username/password to manage. If the
193+
Bastion connection fails or rejects your credentials:
194+
195+
1. Confirm you are signed in to the Azure portal as the **same Entra ID user** that ran
196+
`azd up` (or another principal that has been granted the **Virtual Machine
197+
Administrator Login** or **Virtual Machine User Login** role on the VM).
198+
2. On the Bastion connection blade, ensure **Authentication type** is set to
199+
**Microsoft Entra ID** (not "Password").
200+
3. Verify the **AADLoginForWindows** extension is in a `Succeeded` state on the VM
201+
(Portal → VM → Extensions + applications).
202+
4. To grant additional users access, assign one of these roles on the jump VM (or its
203+
resource group):
204+
- **Virtual Machine Administrator Login** — sign in as a local administrator
205+
- **Virtual Machine User Login** — sign in as a standard user
206+
207+
```pwsh
208+
az role assignment create \
209+
--assignee <user-or-group-object-id> \
210+
--role "Virtual Machine Administrator Login" \
211+
--scope <vm-resource-id>
212+
```
179213

180-
```bash
181-
az vm user update \
182-
--resource-group <rg> \
183-
--name <vm-name> \
184-
--username azureuser \
185-
--password <new-password>
186-
```
214+
See [Azure Bastion — Microsoft Entra ID authentication](https://learn.microsoft.com/azure/bastion/bastion-entra-id-authentication)
215+
for full details.
187216

188217
## Related Documentation
189218

docs/deploy_app_from_foundry.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Since all resources are deployed with private endpoints, you must access Microso
2424
2. Navigate to your resource group
2525
3. Select the **Jump VM** (Windows Virtual Machine)
2626
4. Click **Connect****Bastion**
27-
5. Enter the VM credentials you configured in the top layer (`VM_ADMIN_USERNAME` / `VM_ADMIN_PASSWORD`, or [infra/main.bicepparam](../infra/main.bicepparam))
27+
5. On the Bastion connection blade set **Authentication type** to **Microsoft Entra ID** and click **Connect**you will be signed in with your Entra ID credentials (no username/password required). See [Accessing Private Resources](./ACCESSING_PRIVATE_RESOURCES.md) for details.
2828
6. Once connected, open a browser and navigate to [Microsoft Foundry](https://ai.azure.com)
2929

3030
### 2. Configure Your Playground

docs/deploymentguide.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -205,15 +205,10 @@ Edit `infra/main.bicepparam` or set environment variables:
205205
| `existingVnetResourceId` | Existing VNet resource ID (when `useExistingVNet=true`) | `` |
206206
| `existingLogAnalyticsWorkspaceResourceId` | Existing Log Analytics workspace to receive PostgreSQL diagnostics. May live in another subscription within the same tenant. | `` |
207207
| `existingAiProjectResourceId` | Existing Microsoft Foundry **project** resource ID to reuse instead of creating a new Foundry account + project. When set, `deployAiFoundry` and `deployAfProject` are auto-disabled. Read from `AZURE_EXISTING_AI_PROJECT_RESOURCE_ID`. | `` |
208-
| `vmUserName` | Jump box VM admin username | `VM_ADMIN_USERNAME` env var or `testvmuser` |
209-
| `vmAdminPassword` | Jump box VM admin password | `VM_ADMIN_PASSWORD` env var |
210208

211-
For network-isolated deployments, set the VM credentials before running `azd up`:
212-
213-
```powershell
214-
azd env set VM_ADMIN_USERNAME "youradminuser"
215-
azd env set VM_ADMIN_PASSWORD "<your-strong-password>"
216-
```
209+
> **Jump box sign-in:** The jump box VM uses **Microsoft Entra ID authentication** through
210+
> Azure Bastion. See
211+
> [Accessing Private Resources](./ACCESSING_PRIVATE_RESOURCES.md) for the sign-in steps.
217212
218213

219214
</details>

docs/post_deployment_steps.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,12 @@ For network-isolated deployments, use Azure Bastion to access resources:
211211

212212
![Image showing bastion blade](../img/provisioning/checkNetworkIsolation7.png)
213213

214-
4. Enter the VM admin credentials and click **Connect**
215-
- Admin username: `vmUserName` in [infra/main.bicepparam](../infra/main.bicepparam) or the `VM_ADMIN_USERNAME` environment variable
216-
- Admin password: `vmAdminPassword` in [infra/main.bicepparam](../infra/main.bicepparam) or the `VM_ADMIN_PASSWORD` environment variable
217-
- If `vmUserName` is not set in the top layer, the effective default is `testvmuser`
218-
- If you do not have them, reset the password in **Azure Portal****Virtual machine****Reset password**.
214+
4. On the Bastion connection blade set **Authentication type** to **Microsoft Entra ID** and click **Connect**
215+
- Sign-in uses your **Microsoft Entra ID** credentials — there is no local username/password to enter.
216+
- The deploying principal is automatically granted the **Virtual Machine Administrator Login** role on the jump VM. To grant additional users access, assign **Virtual Machine Administrator Login** or **Virtual Machine User Login** on the VM.
217+
- See [Accessing Private Resources](./ACCESSING_PRIVATE_RESOURCES.md) and [Azure Bastion — Entra ID authentication](https://learn.microsoft.com/azure/bastion/bastion-entra-id-authentication) for details.
219218

220-
![Image showing bastion login](../img/provisioning/checkNetworkIsolation8.png)
219+
![Image showing bastion login](../img/provisioning/checkEntraIDAuthentication8.png)
221220

222221
5. Once connected, open **Edge browser** and navigate to:
223222
- [ai.azure.com](https://ai.azure.com) — Microsoft Foundry
70.9 KB
Loading
-55.9 KB
Binary file not shown.

infra/main.bicep

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,65 @@ var effectiveAiFoundryProjectName = byoAiProjectEnabled ? byoAiFoundryProjectNam
545545
var effectiveAiFoundryResourceGroup = byoAiProjectEnabled ? byoAiProjectResourceGroupName : resourceGroup().name
546546
var effectiveAiFoundrySubscriptionId = byoAiProjectEnabled ? byoAiProjectSubscriptionId : subscription().subscriptionId
547547

548+
// ========================================
549+
// Microsoft Entra ID sign-in for the jumpbox VM via Azure Bastion
550+
// ========================================
551+
// The AI Landing Zone submodule (deployed in preprovision) creates the jumpbox VM with a
552+
// local admin account that we never use. To enable sign-in via Microsoft Entra ID through
553+
// Azure Bastion, this wrapper applies two changes to that already-deployed VM:
554+
// 1) Installs the AADLoginForWindows extension on the existing VM.
555+
// 2) Grants the deploying principal (and any custom principalId override) the built-in
556+
// "Virtual Machine Administrator Login" role scoped to the VM.
557+
// Azure Bastion is deployed by the submodule with the Standard SKU, which supports Entra
558+
// ID authentication for Azure portal RDP/SSH connections.
559+
// Ref: https://learn.microsoft.com/azure/bastion/bastion-entra-id-authentication
560+
561+
// Mirror the submodule's VM name computation (see submodules/ai-landing-zone/main.bicep:
562+
// _vmBaseName = !empty(vmName) ? vmName : 'testvm${resourceToken}', then substring(..., 0, 15)).
563+
var jumpVmEntraIdEnabled = networkIsolation && deployVM && !empty(principalId)
564+
var jumpVmEffectiveName = !empty(vmName) ? vmName : 'testvm${resourceToken}'
565+
var jumpVmName = substring(jumpVmEffectiveName, 0, 15)
566+
567+
// Built-in role: Virtual Machine Administrator Login.
568+
var virtualMachineAdministratorLoginRoleDefinitionId = subscriptionResourceId(
569+
'Microsoft.Authorization/roleDefinitions',
570+
'1c0163c0-47e6-4577-8991-ea5c82e286e4'
571+
)
572+
573+
resource jumpVm 'Microsoft.Compute/virtualMachines@2024-07-01' existing = if (jumpVmEntraIdEnabled) {
574+
name: jumpVmName
575+
}
576+
577+
resource jumpVmAadLoginExtension 'Microsoft.Compute/virtualMachines/extensions@2024-07-01' = if (jumpVmEntraIdEnabled) {
578+
#disable-next-line BCP318
579+
parent: jumpVm
580+
name: 'AADLoginForWindows'
581+
location: location
582+
properties: {
583+
publisher: 'Microsoft.Azure.ActiveDirectory'
584+
type: 'AADLoginForWindows'
585+
typeHandlerVersion: '2.0'
586+
autoUpgradeMinorVersion: true
587+
// Recent extension versions require an explicit mdmId. Empty string means
588+
// "do not enroll the VM into MDM/Intune"; without this the extension
589+
// provisioning fails with: "'mdmId' setting was not found".
590+
settings: {
591+
mdmId: ''
592+
}
593+
}
594+
}
595+
596+
resource jumpVmAdminLoginRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (jumpVmEntraIdEnabled) {
597+
#disable-next-line BCP318
598+
scope: jumpVm
599+
name: guid(resourceGroup().id, jumpVmName, principalId, '1c0163c0-47e6-4577-8991-ea5c82e286e4')
600+
properties: {
601+
roleDefinitionId: virtualMachineAdministratorLoginRoleDefinitionId
602+
principalId: principalId
603+
principalType: principalType
604+
}
605+
}
606+
548607
output virtualNetworkResourceId string = effectiveVnetResourceId
549608
output keyVaultResourceId string = effectiveKeyVaultResourceId
550609
output storageAccountResourceId string = effectiveStorageAccountResourceId

infra/main.bicepparam

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,13 @@ param containerAppsList = [
228228
}
229229
]
230230

231-
param vmUserName = readEnvironmentVariable('VM_ADMIN_USERNAME', 'testvmuser')
232-
param vmAdminPassword = readEnvironmentVariable('VM_ADMIN_PASSWORD', 'JumpboxAdminP@ssw0rd1234!')
231+
// Jumpbox sign-in is performed via Microsoft Entra ID through Azure Bastion (Basic SKU).
232+
// Windows still requires a local admin account at provisioning time, but it is NOT used
233+
// for sign-in. The username is fixed to a default and the password is generated
234+
// deterministically per azd environment so nothing weak/known is committed to source.
235+
// Ref: https://learn.microsoft.com/azure/bastion/bastion-entra-id-authentication
236+
param vmUserName = 'testvmuser'
237+
param vmAdminPassword = 'Jb!${uniqueString(readEnvironmentVariable('AZURE_ENV_NAME', 'default'), readEnvironmentVariable('AZURE_SUBSCRIPTION_ID', 'sub'))}${guid(readEnvironmentVariable('AZURE_ENV_NAME', 'default'), 'vm-admin-password')}'
233238
param vmSize = 'Standard_D2s_v4'
234239

235240
// ========================================

0 commit comments

Comments
 (0)