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
77 changes: 53 additions & 24 deletions docs/ACCESSING_PRIVATE_RESOURCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,39 @@ To access these private resources, the deployment includes:

## How to Access Private Resources

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

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

Comment on lines +15 to 19
# Or in Azure Portal:
You sign in to the jumpbox with your **Microsoft Entra ID** credentials — there is **no local
username/password to manage**.

```text
# In the Azure Portal:
# 1. Navigate to your resource group
# 2. Find the VM resource created for the jump box
# 3. Click "Connect" → "Bastion"
# 4. Enter the username and password you set via VM_ADMIN_USERNAME / VM_ADMIN_PASSWORD
# 2. Open the jump VM (name starts with "testvm")
# 3. Click "Connect" -> "Bastion"
# 4. In the Bastion connection blade:
# Authentication type: "Microsoft Entra ID"
# Protocol: RDP
# (No username / password fields will be required.)
# 5. Click "Connect" - a browser tab opens with the RDP session,
# signed in as your Entra ID user.
```

> **Note:** To grant additional users access, assign one of the following RBAC roles to them
> on the jump VM (or the resource group):
> - **Virtual Machine Administrator Login** - sign in with local administrator privileges
> - **Virtual Machine User Login** - sign in as a standard user
>

> A local admin account is still
> created on the VM because Windows requires one at provisioning time, but its password is
> auto-generated, never displayed, and **not** used to connect through Bastion.

### 2. From Jump VM, Access Private Services

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

### Jump VM credentials unknown

If you did not set the credentials before deployment, use the top-layer defaults or reset them:

- Username: `VM_ADMIN_USERNAME` environment variable, or `vmUserName` in [infra/main.bicepparam](../infra/main.bicepparam)
- Default username when unset: `testvmuser`
- Password: `VM_ADMIN_PASSWORD` environment variable, or `vmAdminPassword` in [infra/main.bicepparam](../infra/main.bicepparam)

To reset:
### Cannot sign in to the Jump VM through Bastion

Sign-in uses **Microsoft Entra ID** — there is no username/password to manage. If the
Bastion connection fails or rejects your credentials:

1. Confirm you are signed in to the Azure portal as the **same Entra ID user** that ran
`azd up` (or another principal that has been granted the **Virtual Machine
Administrator Login** or **Virtual Machine User Login** role on the VM).
2. On the Bastion connection blade, ensure **Authentication type** is set to
**Microsoft Entra ID** (not "Password").
3. Verify the **AADLoginForWindows** extension is in a `Succeeded` state on the VM
(Portal → VM → Extensions + applications).
4. To grant additional users access, assign one of these roles on the jump VM (or its
resource group):
- **Virtual Machine Administrator Login** — sign in as a local administrator
- **Virtual Machine User Login** — sign in as a standard user

```pwsh
az role assignment create \
--assignee <user-or-group-object-id> \
--role "Virtual Machine Administrator Login" \
--scope <vm-resource-id>
```

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

## Related Documentation

Expand Down
2 changes: 1 addition & 1 deletion docs/deploy_app_from_foundry.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Since all resources are deployed with private endpoints, you must access Microso
2. Navigate to your resource group
3. Select the **Jump VM** (Windows Virtual Machine)
4. Click **Connect** → **Bastion**
5. Enter the VM credentials you configured in the top layer (`VM_ADMIN_USERNAME` / `VM_ADMIN_PASSWORD`, or [infra/main.bicepparam](../infra/main.bicepparam))
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.
6. Once connected, open a browser and navigate to [Microsoft Foundry](https://ai.azure.com)

### 2. Configure Your Playground
Expand Down
11 changes: 3 additions & 8 deletions docs/deploymentguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,15 +205,10 @@ Edit `infra/main.bicepparam` or set environment variables:
| `existingVnetResourceId` | Existing VNet resource ID (when `useExistingVNet=true`) | `` |
| `existingLogAnalyticsWorkspaceResourceId` | Existing Log Analytics workspace to receive PostgreSQL diagnostics. May live in another subscription within the same tenant. | `` |
| `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`. | `` |
| `vmUserName` | Jump box VM admin username | `VM_ADMIN_USERNAME` env var or `testvmuser` |
| `vmAdminPassword` | Jump box VM admin password | `VM_ADMIN_PASSWORD` env var |

For network-isolated deployments, set the VM credentials before running `azd up`:

```powershell
azd env set VM_ADMIN_USERNAME "youradminuser"
azd env set VM_ADMIN_PASSWORD "<your-strong-password>"
```
> **Jump box sign-in:** The jump box VM uses **Microsoft Entra ID authentication** through
> Azure Bastion. See
> [Accessing Private Resources](./ACCESSING_PRIVATE_RESOURCES.md) for the sign-in steps.


</details>
Expand Down
11 changes: 5 additions & 6 deletions docs/post_deployment_steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,12 @@ For network-isolated deployments, use Azure Bastion to access resources:

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

4. Enter the VM admin credentials and click **Connect**
- Admin username: `vmUserName` in [infra/main.bicepparam](../infra/main.bicepparam) or the `VM_ADMIN_USERNAME` environment variable
- Admin password: `vmAdminPassword` in [infra/main.bicepparam](../infra/main.bicepparam) or the `VM_ADMIN_PASSWORD` environment variable
- If `vmUserName` is not set in the top layer, the effective default is `testvmuser`
- If you do not have them, reset the password in **Azure Portal** → **Virtual machine** → **Reset password**.
4. On the Bastion connection blade set **Authentication type** to **Microsoft Entra ID** and click **Connect**
- Sign-in uses your **Microsoft Entra ID** credentials — there is no local username/password to enter.
- 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.
- 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.

![Image showing bastion login](../img/provisioning/checkNetworkIsolation8.png)
![Image showing bastion login](../img/provisioning/checkEntraIDAuthentication8.png)

5. Once connected, open **Edge browser** and navigate to:
- [ai.azure.com](https://ai.azure.com) — Microsoft Foundry
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed img/provisioning/checkNetworkIsolation8.png
Binary file not shown.
59 changes: 59 additions & 0 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,65 @@ var effectiveAiFoundryProjectName = byoAiProjectEnabled ? byoAiFoundryProjectNam
var effectiveAiFoundryResourceGroup = byoAiProjectEnabled ? byoAiProjectResourceGroupName : resourceGroup().name
var effectiveAiFoundrySubscriptionId = byoAiProjectEnabled ? byoAiProjectSubscriptionId : subscription().subscriptionId

// ========================================
// Microsoft Entra ID sign-in for the jumpbox VM via Azure Bastion
// ========================================
// The AI Landing Zone submodule (deployed in preprovision) creates the jumpbox VM with a
// local admin account that we never use. To enable sign-in via Microsoft Entra ID through
// Azure Bastion, this wrapper applies two changes to that already-deployed VM:
// 1) Installs the AADLoginForWindows extension on the existing VM.
// 2) Grants the deploying principal (and any custom principalId override) the built-in
// "Virtual Machine Administrator Login" role scoped to the VM.
// Azure Bastion is deployed by the submodule with the Standard SKU, which supports Entra
// ID authentication for Azure portal RDP/SSH connections.
// Ref: https://learn.microsoft.com/azure/bastion/bastion-entra-id-authentication

// Mirror the submodule's VM name computation (see submodules/ai-landing-zone/main.bicep:
// _vmBaseName = !empty(vmName) ? vmName : 'testvm${resourceToken}', then substring(..., 0, 15)).
var jumpVmEntraIdEnabled = networkIsolation && deployVM && !empty(principalId)
var jumpVmEffectiveName = !empty(vmName) ? vmName : 'testvm${resourceToken}'
var jumpVmName = substring(jumpVmEffectiveName, 0, 15)

// Built-in role: Virtual Machine Administrator Login.
var virtualMachineAdministratorLoginRoleDefinitionId = subscriptionResourceId(
'Microsoft.Authorization/roleDefinitions',
'1c0163c0-47e6-4577-8991-ea5c82e286e4'
)

resource jumpVm 'Microsoft.Compute/virtualMachines@2024-07-01' existing = if (jumpVmEntraIdEnabled) {
name: jumpVmName
}

resource jumpVmAadLoginExtension 'Microsoft.Compute/virtualMachines/extensions@2024-07-01' = if (jumpVmEntraIdEnabled) {
#disable-next-line BCP318
parent: jumpVm
name: 'AADLoginForWindows'
location: location
properties: {
publisher: 'Microsoft.Azure.ActiveDirectory'
type: 'AADLoginForWindows'
typeHandlerVersion: '2.0'
autoUpgradeMinorVersion: true
// Recent extension versions require an explicit mdmId. Empty string means
// "do not enroll the VM into MDM/Intune"; without this the extension
// provisioning fails with: "'mdmId' setting was not found".
settings: {
mdmId: ''
}
}
}

resource jumpVmAdminLoginRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (jumpVmEntraIdEnabled) {
#disable-next-line BCP318
scope: jumpVm
name: guid(resourceGroup().id, jumpVmName, principalId, '1c0163c0-47e6-4577-8991-ea5c82e286e4')
properties: {
roleDefinitionId: virtualMachineAdministratorLoginRoleDefinitionId
principalId: principalId
principalType: principalType
}
}

output virtualNetworkResourceId string = effectiveVnetResourceId
output keyVaultResourceId string = effectiveKeyVaultResourceId
output storageAccountResourceId string = effectiveStorageAccountResourceId
Expand Down
9 changes: 7 additions & 2 deletions infra/main.bicepparam
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,13 @@ param containerAppsList = [
}
]

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

// ========================================
Expand Down
Loading