> For the complete documentation index, see [llms.txt](https://docs.keeper.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.keeper.io/keeperpam/privileged-access-manager/getting-started/gateways/gateway-on-kubernetes.md).

# Gateway on Kubernetes

<figure><img src="/files/RvY6jL14F1mLedL7i2ki" alt=""><figcaption></figcaption></figure>

### Overview

The Keeper Gateway can be deployed on any Kubernetes cluster using the official Helm chart maintained by Keeper Security. The chart runs the Gateway as a Kubernetes `Deployment` and supports the full set of Gateway capabilities - remote access (RDP, SSH, VNC), Remote Browser Isolation, secret rotation, and discovery - along with optional persistent storage for session recordings, Horizontal Pod Autoscaling, and disposable demo targets for evaluation.

The Gateway establishes **outbound-only** connections to Keeper infrastructure. No Ingress, LoadBalancer, or inbound firewall rules are required.

The chart is published to both the Keeper Helm repository and Docker Hub as an OCI artifact:

* **Helm repository:** `https://keeper-security.github.io/helm-charts`
* **OCI registry:** `oci://registry-1.docker.io/keeper/keeper-gateway`
* **ArtifactHub:** [keeper-security/keeper-gateway](https://artifacthub.io/packages/helm/keeper-security/keeper-gateway)

{% hint style="info" %}
The chart source is available on [GitHub](https://github.com/Keeper-Security/helm-charts/tree/main/charts/keeper-gateway).
{% endhint %}

### Prerequisites

* A Kubernetes cluster, version **1.25 or later**
* [Helm 3](https://helm.sh/docs/intro/install/)
* A Keeper Enterprise account with the [Privileged Access Manager](https://docs.keeper.io/keeperpam/privileged-access-manager) add-on
* A Gateway configuration (Base64) from the Keeper Vault - see Create a Gateway below

### Create a Gateway

A new Gateway deployment can be created by clicking **Create New** > **Gateway** from the Web Vault or Desktop App. When provisioning, choose the **Docker** method and copy the **Base64 Configuration** -this is the value the chart needs.

You can also create a Gateway and its configuration from the Keeper Commander CLI:

```
pam gateway new -n "<Gateway Name>" -a <Application Name or UID> -c b64
```

Application names and UIDs can be found with `secrets-manager app list`. Save the Base64 configuration token; you will provide it to the chart in the next step.

For full details on provisioning, see [Creating a Keeper Gateway](https://docs.keeper.io/keeperpam/privileged-access-manager/getting-started/gateways/one-time-access-token).

{% hint style="info" %}
When provisioning, you can select **Create with example records** to generate sample PAM records that match the chart's optional Demo / Playground Services.
{% endhint %}

### Installation

Install the chart from either the Helm repository or the OCI registry. Set `gateway.acceptEula=Y` and provide the Base64 configuration from the previous step.

{% tabs %}
{% tab title="Helm Repository" %}

```bash
helm repo add keeper https://keeper-security.github.io/helm-charts
helm repo update

helm install keeper-gateway keeper/keeper-gateway \
  --namespace keeper-gateway --create-namespace \
  --set gateway.acceptEula=Y \
  --set gateway.config='<base64-config>'
```

{% endtab %}

{% tab title="OCI Registry (Docker Hub)" %}

```bash
helm install keeper-gateway oci://registry-1.docker.io/keeper/keeper-gateway \
  --namespace keeper-gateway --create-namespace \
  --set gateway.acceptEula=Y \
  --set gateway.config='<base64-config>'
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Passing `--set gateway.config` places the configuration in your shell history and in `helm get values` output. For production, store the configuration in a Kubernetes Secret instead - see Providing the Gateway Configuration.
{% endhint %}

### Providing the Gateway Configuration

The Gateway configuration can be supplied three ways. Accepting the EULA (`gateway.acceptEula=Y`) is required in all cases.

{% tabs %}
{% tab title="Inline (quick start)" %}
Pass the Base64 configuration directly. Best for evaluation and non-production use.

```bash
--set gateway.acceptEula=Y \
--set gateway.config='<base64-config>'
```

{% endtab %}

{% tab title="Existing Secret (recommended)" %}
Store the configuration in a Kubernetes Secret you manage separately. This keeps the configuration out of shell history and Helm release values.

```bash
kubectl create namespace keeper-gateway
kubectl create secret generic gw-config \
  --from-literal=gateway-config='<base64-config>' -n keeper-gateway

helm install keeper-gateway keeper/keeper-gateway \
  --namespace keeper-gateway \
  --set gateway.acceptEula=Y \
  --set gateway.existingSecret=gw-config
```

The key within the secret defaults to `gateway-config`; override it with `gateway.existingSecretKey`.
{% endtab %}

{% tab title="AWS Secrets Manager" %}
Have the Gateway read its configuration from AWS Secrets Manager at startup. Grant the pod access with an IAM role bound through [IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html).

```bash
helm install keeper-gateway keeper/keeper-gateway \
  --namespace keeper-gateway --create-namespace \
  --set gateway.acceptEula=Y \
  --set gateway.awsKmsSecretName='keeper/gateway-config' \
  --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"='arn:aws:iam::<account>:role/<role>'
```

For details on storing the configuration in AWS Secrets Manager and the required IAM policy, see [Gateway Configuration with AWS KMS](https://docs.keeper.io/keeperpam/privileged-access-manager/getting-started/gateways/advanced-configuration/gateway-configuration-with-aws-kms).
{% endtab %}
{% endtabs %}

### Verify

Confirm the pod is running and connected to Keeper:

```bash
kubectl get pods -n keeper-gateway
kubectl logs -n keeper-gateway -l app.kubernetes.io/name=keeper-gateway
```

The Gateway also reports its status as **Online** in the Keeper Vault under the Gateway.

### Logging

Set the log level and format with the `logging` values. Levels apply to both the Gateway service and `guacd` unless overridden individually.

```bash
--set logging.level=debug \
--set logging.format=json
```

* **Levels:** `error`, `warning`, `info`, `debug` (`guacd` also supports `trace`)
* **Formats:** `text`, `json`, `logfmt`, `cef`, `leef`, `rfc5424`, `rfc3164`, `gelf`

Set levels independently with `logging.gatewayLevel` and `logging.guacdLevel`. To forward logs to a syslog server, set `syslog.enabled=true` and the `syslog.host` / `syslog.port` / `syslog.proto` values.

{% hint style="info" %}
Structured log formats (`json`, `logfmt`, `cef`, etc.) require a recent Gateway image (1.8.0+). If your chart pins an earlier `appVersion`, override the image: `--set image.tag=1.8.0`.
{% endhint %}

For event monitoring and SIEM forwarding, see [Alerts and SIEM Integration](https://docs.keeper.io/keeperpam/privileged-access-manager/getting-started/gateways/alerts-and-siem-integration).

### Health Checks

The chart configures Kubernetes startup, liveness, and readiness probes that run the Gateway's built-in `keeper-gateway health-check` command inside the container. The health-check HTTP server binds to `127.0.0.1` (localhost only) on port `8099`.

Health checks are enabled by default. To expose the `/health` endpoint to an external monitoring tool, set an auth token with `healthCheck.authToken` (or `healthCheck.existingAuthTokenSecret`) and adjust the `service` accordingly.

See [Health Checks](/keeperpam/privileged-access-manager/getting-started/gateways/health-checks.md) for the endpoint response format and CLI options.

### Updating

Pull the latest chart and upgrade the release:

```bash
helm repo update
helm upgrade keeper-gateway keeper/keeper-gateway \
  --namespace keeper-gateway \
  --reuse-values
```

With the default `Recreate` strategy, the existing pod is terminated before the new one starts, so active sessions are disconnected during the upgrade. For zero-downtime upgrades, run multiple replicas with the `RollingUpdate` strategy, see Scaling and High Availability.

{% hint style="info" %}
If you provided the configuration with `gateway.config` on the command line, pass it again (or switch to `gateway.existingSecret`) so it is not lost on upgrade.
{% endhint %}

### Scaling and High Availability

Running more than one replica requires the Gateway to be configured for multi-instance operation in Keeper **first**. From Keeper Commander, find the Gateway UID with `pam gateway list`, then set the maximum number of instances:

{% hint style="info" %}
Multi-instance scaling is currently managed through Keeper Commander only. Support for managing it in the Web Vault and Desktop App is coming soon.
{% endhint %}

```
pam gateway set-max-instances -g <GATEWAY_UID> -m <MAX_INSTANCES>
```

Once multi-instance is enabled, scale the deployment with a fixed replica count or the Horizontal Pod Autoscaler, and switch to the `RollingUpdate` strategy:

{% tabs %}
{% tab title="Fixed replicas" %}

```bash
--set replicaCount=3 \
--set strategy.type=RollingUpdate
```

{% endtab %}

{% tab title="Autoscaling (HPA)" %}

```bash
--set strategy.type=RollingUpdate \
--set autoscaling.enabled=true \
--set autoscaling.minReplicas=2 \
--set autoscaling.maxReplicas=5
```

{% endtab %}
{% endtabs %}

For scaled deployments, set `sessionAffinity=ClientIP` to keep a client's traffic on the same pod, and consider enabling a Pod Disruption Budget (`podDisruptionBudget.enabled=true`). All replicas use the same Gateway configuration.

See [Scaling and High Availability](/keeperpam/privileged-access-manager/getting-started/gateways/scaling-and-high-availability.md) for how the Gateway pool distributes and fails over sessions.

### Session Recordings Storage

Session recordings are encrypted (AES-256-GCM) and streamed to Keeper in real time as the session happens, so recordings are not lost if the pod restarts. The Gateway uses a temporary local directory as a streaming buffer. On nodes with limited disk or for many concurrent sessions, attach a persistent volume for this buffer:

```bash
--set recordings.enabled=true \
--set recordings.size=50Gi
```

The `/dev/shm` shared-memory volume required for Remote Browser Isolation (Chromium) sessions is enabled by default (`sharedMemory.enabled=true`, `sharedMemory.sizeLimit=2Gi`). Increase the size limit for heavy RBI or RDP usage.

### KeeperAI Threat Detection (optional)

Use a large language model to monitor privileged sessions and flag suspicious commands in real time. The API key is stored in a Kubernetes Secret.

```bash
--set ai.enabled=true \
--set ai.provider=openai \
--set ai.model=gpt-4o-mini \
--set ai.apiKey='<your-api-key>'
```

Supported providers include OpenAI, Anthropic, Azure OpenAI, Google AI, Vertex AI, AWS Bedrock, and any OpenAI-compatible endpoint (via `openai-generic`). For cloud-native authentication (AWS Bedrock with IRSA, Vertex AI with Workload Identity), use `serviceAccount.annotations` with `ai.existingSecret` or `extraEnv` instead of `ai.apiKey`. See [KeeperAI](/keeperpam/privileged-access-manager/keeperai.md) for details.

### Corporate Proxy / Custom CA Certificates

If your network uses SSL inspection (for example Zscaler), the Gateway needs your organization's CA certificate to establish outbound connections:

```bash
--set-file caCertificates.inline=./company-ca.pem
```

Or reference an existing ConfigMap with `caCertificates.existingConfigMap`. The Gateway installs these certificates into its trust store at startup.

### Security Context

The Gateway requires elevated privileges for two reasons:

1. **Startup** - the entrypoint runs as root to install CA certificates and Python packages, then drops to the `keeper-gw` user before starting services.
2. **RBI sessions** - CEF/Chromium requires Linux namespace isolation (`unshare`, `mount`, `clone`), which needs `CAP_SYS_ADMIN` and an unconfined seccomp profile.

The chart defaults to capabilities `SYS_ADMIN`, `SYS_CHROOT`, `SETUID`, `SETGID`; `seccompProfile: Unconfined`; and `appArmorProfile: unconfined`.

{% hint style="warning" %}
Do not set `runAsNonRoot: true` or `runAsUser`. If your cluster enforces Pod Security Standards, the Gateway namespace may require an exemption.
{% endhint %}

For hardened deployments, the chart README documents installing a custom AppArmor profile (Debian/Ubuntu nodes) and a custom seccomp profile that allow only the syscalls CEF needs.

### Demo / Playground Services (optional)

Deploy sample SSH, RDP, VNC, and MySQL containers alongside the Gateway as disposable targets for evaluation - try remote access, rotation, and discovery without standing up your own infrastructure. Provision the Gateway with **Create with example records**, then enable the demo services:

```bash
--set demo.enabled=true
```

Individual services can be toggled (for example `--set demo.rdp.enabled=false`).

| Service            | Port | Default |
| ------------------ | ---- | ------- |
| `demo.mysql`       | 3306 | Enabled |
| `demo.sshPassword` | 2222 | Enabled |
| `demo.sshKey`      | 2222 | Enabled |
| `demo.vnc`         | 5901 | Enabled |
| `demo.rdp`         | 3389 | Enabled |

{% hint style="info" %}
All demo passwords are placeholders for local testing only. Replace them with the values from your Keeper Vault wizard output. The demo services are **not** intended for production.
{% endhint %}

### Network Configuration

The Keeper Gateway establishes outbound-only connections and does not require any inbound firewall rules. The following outbound connections must be allowed:

<table><thead><tr><th width="257.48046875">Destination Endpoint</th><th width="249.30078125">Ports Needed</th><th>More Info</th></tr></thead><tbody><tr><td><p><strong>Keeper Cloud</strong><br><code>keepersecurity.[x]</code></p><p>Endpoints:</p><p>US: <code>.com</code></p><p>EU: <code>.eu</code></p><p>AU: <code>.com.au</code></p><p>JP: <code>.jp</code></p><p>CA: <code>.ca</code></p><p>US GOV: <code>.us</code></p></td><td>TLS Port 443</td><td>Communicates with Keeper Cloud to access target infrastructure via native protocols (e.g., SSH, RDP)</td></tr><tr><td><p><strong>Keeper Router</strong><br><code>connect.keepersecurity.[x]</code></p><p>Endpoints:</p><p>US: <code>.com</code></p><p>EU: <code>.eu</code></p><p>AU: <code>.com.au</code></p><p>JP: <code>.jp</code></p><p>CA: <code>.ca</code></p><p>US GOV: <code>.us</code></p></td><td>TLS Port 443</td><td>Communicates with Keeper Router to establish secure, real-time WebSocket connections</td></tr><tr><td><p><strong>Keeper Stun/Turn Service</strong></p><p><code>krelay.keepersecurity.[x]</code></p><p>Endpoints:</p><p>US: <code>.com</code></p><p>EU: <code>.eu</code></p><p>AU: <code>.com.au</code></p><p>JP: <code>.jp</code></p><p>CA: <code>.ca</code></p><p>US GOV: <code>.us</code></p></td><td>TCP and UDP opened on Port 3478<br><br>Outbound access to TCP and UDP ports 49152 through 65535<br></td><td>Facilitates secure and encrypted WebRTC connections between end-user's vault and target systems via the Gateway</td></tr></tbody></table>

### Uninstall

```bash
helm uninstall keeper-gateway -n keeper-gateway
kubectl delete namespace keeper-gateway
```

If recordings storage was enabled, the persistent volume is not removed automatically:

```bash
kubectl delete pvc -n keeper-gateway -l app.kubernetes.io/name=keeper-gateway
```

### Configuration Reference

The most common values are below. For the complete list, see the chart's [`values.yaml`](https://github.com/Keeper-Security/helm-charts/blob/main/charts/keeper-gateway/values.yaml) or the [ArtifactHub listing](https://artifacthub.io/packages/helm/keeper-security/keeper-gateway).

#### Gateway configuration

<table><thead><tr><th>Parameter</th><th width="261.9765625">Description</th><th>Default</th></tr></thead><tbody><tr><td><code>gateway.acceptEula</code></td><td>Accept the EULA (required, must be <code>Y</code>)</td><td><code>""</code></td></tr><tr><td><code>gateway.config</code></td><td>Base64-encoded Gateway configuration from Keeper</td><td><code>""</code></td></tr><tr><td><code>gateway.existingSecret</code></td><td>Use a pre-created Kubernetes Secret instead of <code>gateway.config</code></td><td><code>""</code></td></tr><tr><td><code>gateway.existingSecretKey</code></td><td>Key within the existing secret</td><td><code>"gateway-config"</code></td></tr><tr><td><code>gateway.awsKmsSecretName</code></td><td>Load the configuration from AWS Secrets Manager</td><td><code>""</code></td></tr></tbody></table>

#### Image

<table><thead><tr><th>Parameter</th><th width="300.69921875">Description</th><th>Default</th></tr></thead><tbody><tr><td><code>image.repository</code></td><td>Gateway image repository</td><td><code>keeper/gateway</code></td></tr><tr><td><code>image.tag</code></td><td>Image tag (defaults to the chart <code>appVersion</code>)</td><td><code>""</code></td></tr><tr><td><code>image.pullPolicy</code></td><td>Image pull policy</td><td><code>IfNotPresent</code></td></tr></tbody></table>

#### Scaling & availability

<table><thead><tr><th width="272.4296875">Parameter</th><th width="321.640625">Description</th><th>Default</th></tr></thead><tbody><tr><td><code>replicaCount</code></td><td>Number of Gateway pods</td><td><code>1</code></td></tr><tr><td><code>strategy.type</code></td><td><code>Recreate</code> (single instance) or <code>RollingUpdate</code> (multi-instance)</td><td><code>Recreate</code></td></tr><tr><td><code>autoscaling.enabled</code></td><td>Enable the Horizontal Pod Autoscaler</td><td><code>false</code></td></tr><tr><td><code>autoscaling.minReplicas</code> / <code>maxReplicas</code></td><td>HPA bounds</td><td><code>1</code> / <code>5</code></td></tr><tr><td><code>sessionAffinity</code></td><td>Set to <code>ClientIP</code> for scaled deployments</td><td><code>""</code></td></tr><tr><td><code>podDisruptionBudget.enabled</code></td><td>Keep a minimum number of pods running during disruptions</td><td><code>false</code></td></tr></tbody></table>

#### Storage, logging, health & AI

| Parameter                                  | Description                                       | Default          |
| ------------------------------------------ | ------------------------------------------------- | ---------------- |
| `recordings.enabled` / `recordings.size`   | Persistent buffer for session recordings          | `false` / `10Gi` |
| `sharedMemory.sizeLimit`                   | `/dev/shm` size (RBI/Chromium)                    | `2Gi`            |
| `logging.level` / `logging.format`         | Log level and format                              | `info` / `text`  |
| `healthCheck.enabled` / `healthCheck.port` | Health-check server (localhost)                   | `true` / `8099`  |
| `ai.enabled` / `ai.provider` / `ai.model`  | KeeperAI threat detection                         | `false`          |
| `resources.limits`                         | CPU / memory limits (raise for many RBI sessions) | `4` / `4Gi`      |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keeper.io/keeperpam/privileged-access-manager/getting-started/gateways/gateway-on-kubernetes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
