> 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)
