> 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/jump-host-management/jump-host-connector-image.md).

# The jump host connector image

The connector image is the container the [jump host connector application](/integrations/resource-integrations/microsoft-azure/jump-host-management/jump-host-connector-application.md) runs. It packages a single Azure function that terminates a live SSH session on one of your jump host VMs when P0 revokes access. This page explains what the image contains, how P0 calls it, and where P0 publishes it.

{% hint style="info" %}
Jump host management is in **beta**.
{% endhint %}

## What the image is

The image is a Node.js Azure Function App container that P0 builds and publishes:

| Property    | Value                                                                            |
| ----------- | -------------------------------------------------------------------------------- |
| Image       | `p0security/p0-security-perimeter-azure-vm`                                      |
| Registry    | [Docker Hub](https://hub.docker.com/r/p0security/p0-security-perimeter-azure-vm) |
| Default tag | `latest`                                                                         |
| Runtime     | Node.js, Azure Functions v4 (worker indexing)                                    |

You do not build the image. P0 builds and publishes it to Docker Hub, and your connector Function App pulls and runs it. View the published image at [hub.docker.com/r/p0security/p0-security-perimeter-azure-vm](https://hub.docker.com/r/p0security/p0-security-perimeter-azure-vm).

## What the function does

The image exposes one HTTP-triggered function that terminates an SSH session:

**Endpoint:** `POST /api/kill-session`

**Request body:**

| Field          | Type   | Required | Description                                                                |
| -------------- | ------ | -------- | -------------------------------------------------------------------------- |
| `email`        | string | Yes      | The requestor whose session is terminated.                                 |
| `ip`           | string | Yes      | The source IP of the SSH session.                                          |
| `port`         | number | No       | The source port of the SSH session.                                        |
| `vmResourceId` | string | Yes      | The full Azure resource ID of the jump host VM to run the kill command on. |

When P0 revokes a requestor's access, it calls this endpoint. The function then:

1. **Validates the request.** It enforces a strict email format, a valid IP address, and a port in the range 1–65535. These checks also guard against shell injection, because the target jump host receives these values in a shell command.
2. **Runs a script on the target VM** through [Azure Run Command](https://learn.microsoft.com/en-us/azure/virtual-machines/run-command-overview) (`RunShellScript`). The script resolves the local account for `email`, finds the SSH connections from `ip` (and `port`, defaulting to 22) to that account, and terminates the matching processes.
3. **Reports the outcome.** Terminating a session is idempotent teardown, so "nothing to terminate" is a success, not an error. The function returns `200` whether it terminated a session, found no matching session, found no local account for the email, or found the VM stopped. It returns `500` only when the script itself fails.

Because termination uses Azure Run Command, the connector needs no inbound network path to your jump hosts and no P0-managed agent on them — it uses the standard Azure VM Guest Agent that Azure VMs run by default.

The function authorizes each Run Command with the connector Function App's system-assigned managed identity, which holds the `P0 Session Terminator` role on the target VM. It also emits security-event logs (`LOG_SECURITY_EVENTS`) so you can audit each termination in the Function App's logs.

## How P0 calls the image securely

Two controls protect the function so that only P0 can invoke it:

* **App Service Authentication.** The Function App accepts requests only from the `p0-session-terminator` app registration; any other caller receives a `401` response. The function itself fails closed — it rejects any request that arrives without the platform-validated caller principal. For how this trust is established, see [The jump host connector application](/integrations/resource-integrations/microsoft-azure/jump-host-management/jump-host-connector-application.md).
* **Workload identity federation.** P0 authenticates without a stored secret. P0 exchanges a Google Cloud service account token for an Entra access token — scoped to `api://<client-id>/.default` with audience `api://AzureADTokenExchange` — and sends it as a bearer token. The connector's federated credential trusts only P0's service account, so no other identity can obtain a valid token.

## Requirements for jump host VMs

The connector terminates sessions by running a shell script on your jump host VMs, so each managed VM must meet the following requirements. Build these into your jump host image or base configuration.

| Requirement                                      | Why                                                                                                                                                                                       |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Azure VM Guest Agent installed and running       | Azure Run Command dispatches the termination script through the guest agent. Standard Azure Linux images ship with it enabled.                                                            |
| A Linux OS with `ss` (from `iproute2`) available | The script uses `ss` to find the SSH connections to terminate.                                                                                                                            |
| SSH users provisioned as local accounts          | The script matches sessions by resolving the requestor's `email` to a local user with `getent passwd`. A session for an email that has no local account is treated as already terminated. |
| SSH listening on the expected port               | The script matches connections against the request's `port`, defaulting to `22`. Set the connector's `DEFAULT_SSH_PORT` app setting if your jump hosts use a different backend port.      |

{% hint style="info" %}
Azure Run Command runs the termination script as `root`, so no extra `sudo` configuration is required on the jump host.
{% endhint %}

## The image's environment contract

The connector Function App sets the following app settings to match what the image expects.

| Setting                               | Value                      | Purpose                                                                                                                                             |
| ------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FUNCTIONS_WORKER_RUNTIME`            | `node`                     | Selects the Node.js worker.                                                                                                                         |
| `CALLER_APP_ID`                       | App registration client ID | The app registration the function trusts as its caller.                                                                                             |
| `LOG_SECURITY_EVENTS`                 | `true`                     | Emits security-event logs for each termination.                                                                                                     |
| `WEBSITES_ENABLE_APP_SERVICE_STORAGE` | `false`                    | Lets the image's baked-in function code and `AzureWebJobsScriptRoot` load instead of an empty Azure Files share.                                    |
| `AzureWebJobsFeatureFlags`            | `EnableWorkerIndexing`     | Required for the v4 Node.js model so the host discovers the function's HTTP trigger.                                                                |
| `DEFAULT_SSH_PORT`                    | `22` (optional)            | The backend SSH port the termination script matches against when a request omits `port`. Set this if your jump hosts listen on a non-standard port. |

{% hint style="warning" %}
Do not change `WEBSITES_ENABLE_APP_SERVICE_STORAGE` or `AzureWebJobsFeatureFlags`. With either set incorrectly, the host loads no functions and the connector exposes no `kill-session` endpoint.
{% endhint %}

## Where the image is published

P0 publishes the image to Docker Hub at [hub.docker.com/r/p0security/p0-security-perimeter-azure-vm](https://hub.docker.com/r/p0security/p0-security-perimeter-azure-vm). The connector Function App runs it directly from there, pulling the `latest` tag by default.

If your environment restricts pulls from Docker Hub, mirror the image to a registry you control, such as Azure Container Registry, and point the connector Function App at your copy. Grant the Function App's managed identity permission to pull from that registry — for example, the `AcrPull` role on an Azure Container Registry.

## Related pages

* [Jump host management](/integrations/resource-integrations/microsoft-azure/jump-host-management.md)
* [The jump host connector application](/integrations/resource-integrations/microsoft-azure/jump-host-management/jump-host-connector-application.md)
