> For the complete documentation index, see [llms.txt](https://docs.p0.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.p0.dev/integrations/resource-integrations/microsoft-azure/configure-bastion-host-integration/custom-jump-host.md).

# Custom jump host

When you select the **Custom jump host** connection type, P0 connects through a virtual machine that acts as a jump host, instead of a managed Azure Bastion host. You provide the jump host VM's Azure resource ID. P0 validates the resource ID and resolves the public IP address on the VM's primary NIC at install time, then uses that IP to reach the jump host for SSH sessions.

{% hint style="info" %}
This page is one of two connection types for [bastion host configuration](/integrations/resource-integrations/microsoft-azure/configure-bastion-host-integration.md). For an overview and the shared subscription steps, start on the [Configure bastion host integration](/integrations/resource-integrations/microsoft-azure/configure-bastion-host-integration.md) page.
{% endhint %}

## Prerequisites

You must have a virtual machine that P0 can use as a jump host. The VM must meet the following requirements.

| Requirement                        | Details                                                                                                                                                                                                                                                                                                                                      |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Public IP address                  | The VM must have a public IP address on its **primary** network interface (NIC). P0 resolves this IP at install time and uses it to reach the jump host.                                                                                                                                                                                     |
| Azure AD login for Linux extension | The VM must have the **Azure AD login for Linux** extension (`AADSSHLoginForLinux`) installed. P0 authenticates SSH sessions through Azure IAM, so the jump host must support this plugin.                                                                                                                                                   |
| SSH server                         | The VM must have an SSH server (`sshd`) installed and running so it can serve as a jump host for SSH sessions. For recommended `sshd` settings and sizing limits, see [Jump host sizing and tuning](/integrations/resource-integrations/microsoft-azure/configure-bastion-host-integration/custom-jump-host/jump-host-sizing-and-tuning.md). |
| Resource ID                        | You must have the VM's Azure resource ID, in the format `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupId}/providers/Microsoft.Compute/virtualMachines/{vmName}`.                                                                                                                                                             |

A custom jump host doesn't use a P0-created role. Instead, your connecting users hold Azure roles that you specify: a **standard user role** that grants the [jump host permissions](#permissions) needed to reach VMs through the jump host over Azure IAM, and an **admin user role** that grants sudo access on the target VM. Both roles are required.

## Permissions

P0 doesn't create a role for the custom jump host connection type. Instead, you grant roles to the users who connect to VMs through the jump host, so they can reach those VMs over Azure IAM.

For each field, you can point P0 at a built-in role, an existing custom role, or a new custom role that you create. If you create your own role, see [Create a custom role](/integrations/resource-integrations/microsoft-azure/configure-bastion-host-integration/create-a-custom-role.md) for the Azure CLI and Terraform steps.

### Standard user role

Point the **Standard user role id** field at a built-in role, an existing custom role, or a new custom role that you create. P0 recommends the built-in **Virtual Machine User Login** role (`fb879df8-f326-4884-b1cf-06f3ad86be52`).

At minimum, the role must include these permissions:

```json
{
  "actions": [
    "Microsoft.Network/publicIPAddresses/read",
    "Microsoft.Network/virtualNetworks/read",
    "Microsoft.Network/loadBalancers/read",
    "Microsoft.Network/networkInterfaces/read",
    "Microsoft.Compute/virtualMachines/*/read"
  ],
  "notActions": [],
  "dataActions": [
    "Microsoft.Compute/virtualMachines/login/action"
  ],
  "notDataActions": []
}
```

The `Microsoft.Compute/virtualMachines/login/action` data action lets the user sign in to the VM through the Azure AD login for Linux extension. The read actions let the connecting user resolve the jump host and target VM network configuration.

### Admin user role

Configure an **Admin user role id** for sudo access on the target VM. This field is required, even if you don't currently allow sudo — P0 grants the role at the target VM only when a request opts into sudo access, but you must configure it at install time. Point it at a built-in role, an existing custom role, or a new custom role. P0 recommends the built-in **Virtual Machine Administrator Login** role (`1c0163c0-47e6-4577-8991-ea5c82e286e4`).

A custom admin role must include the same permissions as the standard user role, plus the `Microsoft.Compute/virtualMachines/loginAsAdmin/action` data action:

```json
{
  "actions": [
    "Microsoft.Network/publicIPAddresses/read",
    "Microsoft.Network/virtualNetworks/read",
    "Microsoft.Network/loadBalancers/read",
    "Microsoft.Network/networkInterfaces/read",
    "Microsoft.Compute/virtualMachines/*/read"
  ],
  "notActions": [],
  "dataActions": [
    "Microsoft.Compute/virtualMachines/login/action",
    "Microsoft.Compute/virtualMachines/loginAsAdmin/action"
  ],
  "notDataActions": []
}
```

The `Microsoft.Compute/virtualMachines/loginAsAdmin/action` data action lets the user sign in to the VM as an administrator with sudo privileges.

### Create a custom role

If you don't use a built-in role, create a custom role from the permissions described earlier in this topic using the Azure CLI or Terraform. See [Create a custom role](/integrations/resource-integrations/microsoft-azure/configure-bastion-host-integration/create-a-custom-role.md) for step-by-step instructions with both tools.

## Setup steps

Complete the [shared subscription steps](/integrations/resource-integrations/microsoft-azure/configure-bastion-host-integration.md#get-started) first, then select **Custom jump host** as the connection type and continue with the following steps.

1. Enter the **Virtual machine resource ID** of the jump host VM. P0 validates the resource ID format and confirms the VM has a public IP address on its primary NIC.

   The virtual machine resource ID follows this format:

   `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupId}/providers/Microsoft.Compute/virtualMachines/{vmName}`
2. Enter the **Standard user role id** of the role your connecting users hold to reach VMs through the jump host over Azure IAM. This can be a built-in role, an existing custom role, or a new custom role. See [Standard user role](#standard-user-role) for the minimum permissions it must include.

   P0 does not create this role, so no role setup commands run for this connection type.
3. Enter the **Admin user role id** of the role that grants sudo access on the target VM. This field is required, even if you don't currently allow sudo — P0 assigns the role at the target VM only when a request opts into sudo access, but you must configure it at install time. See [Admin user role](#admin-user-role) for the recommended role.

The Bastion host configuration is now complete.

## Manage with the P0 Terraform provider

Instead of entering the jump host details in the dashboard, you can register the custom jump host connection with P0 as code using the [`p0_azure_bastion_host`](https://registry.terraform.io/providers/p0-security/p0/latest/docs/resources/azure_bastion_host) resource in the [P0 Terraform provider](https://registry.terraform.io/providers/p0-security/p0/latest). To connect through a custom jump host, configure the resource's `jump_host` block. This is the recommended path for teams that manage their P0 configuration declaratively.

{% hint style="info" %}
The `jump_host` mode of the `p0_azure_bastion_host` resource requires P0 Terraform provider [v0.47.0](https://github.com/p0-security/terraform-provider-p0/releases/tag/v0.47.0) or later.
{% endhint %}

In `jump_host` mode, the resource registers your existing jump host VM with P0 — no staged resource or Azure Bastion host is needed. The VM must have a public IP address on its primary network interface, which P0 resolves and stores at install time. You still create the [roles your connecting users hold](#permissions) in Azure and pass their role definition IDs to the resource: the `jump_host` block requires both `standard_access_role_id` (standard, non-sudo access) and `admin_access_role_id` (sudo access).

Each role ID can point to a built-in role, or a [custom role](/integrations/resource-integrations/microsoft-azure/configure-bastion-host-integration/create-a-custom-role.md) scoped to a subscription or a management group. The following example uses Azure's built-in **Virtual Machine User Login** and **Virtual Machine Administrator Login** roles. These roles are defined at the tenant root, so their role definition IDs are stable across every subscription and management group and don't include a subscription or management group prefix.

1. **Install the Terraform CLI** if you haven't already. See the [Terraform installation guide](https://developer.hashicorp.com/terraform/install).
2. **Generate a P0 API token.** The P0 provider authenticates with an API token that you create in the P0 dashboard — see [Generating an API key](/p0-management/generating-an-api-key.md). Export it so the provider can read it:

```bash
export P0_API_TOKEN=<your-p0-api-token>
```

3. **Register the custom jump host.** Declare the P0 provider, the base Azure resources, and the `p0_azure_bastion_host` resource with a `jump_host` block:

```terraform
terraform {
  required_providers {
    p0 = {
      source  = "p0-security/p0"
      version = ">= 0.47.0"
    }
  }
}

provider "p0" {
  org = "your-p0-organization"
}

resource "p0_azure" "example" {
  directory_id = "<tenant-id>"
}

resource "p0_azure_app" "example" {
  depends_on = [p0_azure.example]
  client_id  = "<app-registration-client-id>"
}

resource "p0_azure_iam_write" "example" {
  depends_on      = [p0_azure_app.example]
  subscription_id = "<subscription-id>"
}

# Registers the custom jump host: P0 reaches your Azure VMs through this jump
# host VM, resolving the VM's public IP at install time. standard_access_role_id
# and admin_access_role_id are the roles P0 assigns to a connecting user for
# standard (non-sudo) and sudo access, respectively. This example uses Azure's
# built-in roles; you can also point each at a custom role scoped to a
# subscription or a management group.
resource "p0_azure_bastion_host" "example" {
  depends_on = [p0_azure_iam_write.example]

  subscription_id = "<subscription-id>"
  jump_host = {
    virtual_machine_id = "/subscriptions/<id>/resourceGroups/<rg>/providers/Microsoft.Compute/virtualMachines/<name>"
    # Built-in Virtual Machine User Login role (standard, non-sudo access)
    standard_access_role_id = "/providers/Microsoft.Authorization/roleDefinitions/fb879df8-f326-4884-b1cf-06f3ad86be52"
    # Built-in Virtual Machine Administrator Login role (sudo access)
    admin_access_role_id = "/providers/Microsoft.Authorization/roleDefinitions/1c0163c0-47e6-4577-8991-ea5c82e286e4"
  }
}
```

4. **Apply the configuration:**

```bash
terraform init
terraform apply
```

To let P0 terminate active jump host sessions when access is revoked, also install the [jump host management](/integrations/resource-integrations/microsoft-azure/jump-host-management.md) component, which the provider exposes as the `p0_azure_jump_host` resource.

For the full argument reference, see the [`p0_azure_bastion_host` resource documentation](https://registry.terraform.io/providers/p0-security/p0/latest/docs/resources/azure_bastion_host).

## Troubleshooting

| Error                                                                            | Cause                                                | Resolution                                                                                                        |
| -------------------------------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| "Enter a valid virtual machine resource ID"                                      | The custom jump host resource ID is malformed        | Enter the full VM resource ID, in the format `/subscriptions/.../providers/Microsoft.Compute/virtualMachines/...` |
| "The jump host virtual machine must have a public IP address on its primary NIC" | The jump host VM has no public IP on its primary NIC | Assign a public IP to the VM's primary network interface, then retry                                              |

## Next step

Proceed to [Install SSH access control](/integrations/resource-integrations/microsoft-azure/install-ssh-access.md) to connect P0 to your Azure VMs.
